[gimp-gap/gap-2-8] added LAYER GROUP Support in the MovePath dialog.
- From: Wolfgang Hofer <wolfgangh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp-gap/gap-2-8] added LAYER GROUP Support in the MovePath dialog.
- Date: Sun, 2 Feb 2014 08:39:33 +0000 (UTC)
commit 43c26576a914d168e81139fc8dffa0b7e34cf669
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date: Sun Feb 2 09:37:41 2014 +0100
added LAYER GROUP Support in the MovePath dialog.
ChangeLog | 30 +++
gap/gap_image.c | 491 +++++++++++++++++++++++++++++++++++++++++++++++++
gap/gap_image.h | 24 +++
gap/gap_mov_dialog.c | 255 +++++++++++++++++++-------
gap/gap_mov_dialog.h | 13 +-
gap/gap_mov_exec.c | 228 ++++++++++++++++-------
gap/gap_mov_exec.h | 2 +
gap/gap_mov_render.c | 21 ++-
gap/gap_mov_xml_par.c | 238 ++++++++++++++----------
gap/gap_xml_util.c | 27 +++-
gap/gap_xml_util.h | 4 +-
11 files changed, 1086 insertions(+), 247 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e0c9253..e8c7b77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2014-02-02 Wolfgang Hofer <hof gimp org>
+
+- added LAYER GROUP Support in the "MovePath" dialog.
+ Tis dialog now provides a "Target Group" and Delimiter entry
+ To specifiy a Groupname where the rendered layer(s) shall be
+ inserted in all processed frame images.
+ The groupname may also refere a subgroup when
+ it is separeted by the specified delimiter character
+ Example:
+ Delimiter: /
+ Target Group: "animals/flying/birds"
+
+ Note that an empty groupname refers to the image.
+ (e.g. the rendered layer(s) are inserted at image level)
+
+ The Stepmode loop for layer specific stepmodes
+ (loop, loop reverse, once, once reverse, ping pong)
+ now iterates over the layers that are member of the same group as the selected
+ Source Image/Layer. Selecting a toplevel Layer (or toplevel Grouplayer) iterates
+ over all toplevel layers including all toplevel Grouplayers of the Source image.
+
+ * gap/gap_image.c [.h]
+ * gap/gap_mov_dialog.c [.h]
+ * gap/gap_mov_exec.c [.h]
+ * gap/gap_mov_main.c
+ * gap/gap_mov_render.c [.h]
+ * gap/gap_mov_xml_par.c
+ * gap/gap_xml_util.c [.h]
+
+
2014-01-12 Wolfgang Hofer <hof gimp org>
- support for RAW files as "readonly" frame sequences for processing
as high bit depth video source in MovePath operations or Storyboard Clips.
diff --git a/gap/gap_image.c b/gap/gap_image.c
index 5d03fce..5a1a764 100644
--- a/gap/gap_image.c
+++ b/gap/gap_image.c
@@ -33,6 +33,7 @@
#include <string.h>
+#include <glib.h>
#include <gap_image.h>
#include <gap_base.h>
#include <gap_layer_copy.h>
@@ -566,3 +567,493 @@ gap_image_create_unicolor_image(gint32 *layer_id, gint32 width , gint32 height
}
return(l_image_id);
} /* end gap_image_create_unicolor_image */
+
+
+/* -----------------------------------------------
+ * gap_image_get_tree_position_list
+ * -----------------------------------------------
+ * return a list that represents the stack positions
+ * of the specified item_id (typically a layer)
+ * which contains positions within the image
+ * and within all its parent group layers.
+ *
+ * The 1st element in the stack position list refers to the stackposition
+ * at toplevel of the image.
+ * Note:
+ * The caller shall g_free the returned list
+ * after use by calling: gap_image_gfree_tree_position_list
+ */
+GapImageStackPositionsList *
+gap_image_get_tree_position_list(gint32 item_id)
+{
+ gint32 l_image_id;
+ gint32 l_curr_item_id;
+ GapImageStackPositionsList *posRootPtr;
+
+
+ posRootPtr = NULL;
+ l_image_id = gimp_item_get_image (item_id);
+
+ if(gap_debug)
+ {
+ printf("gap_image_get_tree_position_list Start image_id: %d\n"
+ , (int)l_image_id
+ );
+ }
+
+ if (l_image_id < 0)
+ {
+ return (NULL);
+ }
+
+ l_curr_item_id = item_id;
+
+ while(l_curr_item_id > 0)
+ {
+ GapImageStackPositionsList *posPtr;
+
+ posPtr = g_new(GapImageStackPositionsList, 1);
+ posPtr->stack_position = gimp_image_get_item_position (l_image_id,
+ l_curr_item_id);
+ if(gap_debug)
+ {
+ printf("item_id:%d stack_position: %d name:%s\n"
+ , (int)l_curr_item_id
+ , (int)posPtr->stack_position
+ , gimp_item_get_name(l_curr_item_id)
+ );
+ }
+
+ posPtr->next = posRootPtr;
+ posRootPtr = posPtr;
+
+ l_curr_item_id = gimp_item_get_parent (l_curr_item_id);
+
+ }
+
+ return (posRootPtr);
+
+} /* end gap_image_get_tree_position_list */
+
+
+
+/* -----------------------------------------------
+ * gap_image_gfree_tree_position_list
+ * -----------------------------------------------
+ */
+void
+gap_image_gfree_tree_position_list(GapImageStackPositionsList *rootPosPtr)
+{
+ GapImageStackPositionsList *posPtr;
+ GapImageStackPositionsList *nextPosPtr;
+
+ posPtr = rootPosPtr;
+ while (posPtr != NULL)
+ {
+ nextPosPtr = posPtr->next;
+ g_free(posPtr);
+
+ posPtr = nextPosPtr;
+ }
+} /* end gap_image_gfree_tree_position_list */
+
+
+/* -----------------------------------------------
+ * gap_image_get_layer_id_by_tree_position_list
+ * -----------------------------------------------
+ * return the item_id of the layer that matches
+ * the specified stack position list.
+ * (where each list element describes the position
+ * in the next tree level
+ * The 1st element in the stack position list refers to the stackposition
+ * at toplevel of the image)
+ *
+ */
+gint32
+gap_image_get_layer_id_by_tree_position_list(gint32 image_id, GapImageStackPositionsList *rootPosPtr)
+{
+ GapImageStackPositionsList *posPtr;
+ gint l_nlayers;
+ gint l_treelevel;
+ gint32 *l_src_layers;
+ gint32 l_layer_id;
+ gint32 l_wanted_layer_id;
+
+ l_layer_id = -1;
+ l_wanted_layer_id = -1;
+ l_treelevel = 0;
+ posPtr = rootPosPtr;
+ if (posPtr == NULL)
+ {
+ return (l_layer_id);
+ }
+ l_src_layers = gimp_image_get_layers (image_id, &l_nlayers);
+ if (l_src_layers == NULL)
+ {
+ return (-1);
+ }
+
+ while(posPtr != NULL)
+ {
+ if ((posPtr->stack_position >= 0) && (posPtr->stack_position < l_nlayers))
+ {
+ l_layer_id = l_src_layers[posPtr->stack_position];
+ if(gap_debug)
+ {
+ printf("get_layer_id_by_tree_pos layer_id: treelevel:%d %d name:%s N:%d stackPos:%d\n"
+ , (int)l_treelevel
+ , (int)l_layer_id
+ , gimp_item_get_name(l_layer_id)
+ , l_nlayers
+ , posPtr->stack_position
+ );
+ }
+ }
+ g_free(l_src_layers);
+ if (l_layer_id < 0)
+ {
+ if(gap_debug)
+ {
+ printf("get_layer_id_by_tree_pos l_treelevel:%d stack_position:%d NOT found!\n"
+ , (int)l_treelevel
+ , (int)posPtr->stack_position
+ );
+ }
+ break;
+ }
+ posPtr = posPtr->next;
+ if(posPtr != NULL)
+ {
+ if (gimp_item_is_group(l_layer_id))
+ {
+ l_src_layers = gimp_item_get_children (l_layer_id, &l_nlayers);
+ if (l_src_layers == NULL)
+ {
+ if(gap_debug)
+ {
+ printf("get_layer_id_by_tree_pos l_treelevel:%d NO CHILD LAYERS FOUND ! for item_id:%d\n"
+ , (int)l_treelevel
+ , (int)l_layer_id
+ );
+ }
+ return (-1); /* failed to get group members */
+ }
+ }
+ else
+ {
+ if(gap_debug)
+ {
+ printf("get_layer_id_by_tree_pos l_treelevel:%d item_id:%d IS NOT A GROUP !\n"
+ , (int)l_treelevel
+ , (int)l_layer_id
+ );
+ }
+ return (-1); /* group was expected, but not found, cant evaluate rest of the list */
+ }
+ }
+ else
+ {
+ l_wanted_layer_id = l_layer_id;
+ }
+ l_treelevel++;
+ } /* end while */
+
+ return (l_wanted_layer_id);
+
+
+} /* end gap_image_get_layer_id_by_tree_position_list */
+
+
+/* -----------------------------------------------
+ * gap_image_greate_group_layer_path
+ * -----------------------------------------------
+ * create group layer specified by nameArray starting with
+ * the element at start_idx end at 1st NULL pointer element.
+ * in case the rest in this nameArray contains more than one name
+ * a hierarchy of group layers is created, where each name
+ * has the previous name as parent.
+ */
+gint32
+gap_image_greate_group_layer_path(gint32 image_id
+ , gint32 parent_id /* or 0 for top imagelevel */
+ , gint32 stackposition /* where 0 is on top position */
+ , gchar **nameArray
+ , gint start_idx
+ )
+{
+ gint32 parent_layer_id;
+ gint32 group_layer_id;
+ gint32 position;
+ gchar *namePtr;
+ gint l_ii;
+
+ position = stackposition;
+ parent_layer_id = 0;
+ if (nameArray != NULL)
+ {
+ for(l_ii = 0; nameArray[l_ii] != NULL; l_ii++)
+ {
+ if(l_ii >= start_idx)
+ {
+ namePtr = nameArray[l_ii];
+ group_layer_id = gimp_layer_group_new(image_id);
+ gimp_item_set_name(group_layer_id, namePtr);
+ gimp_image_insert_layer(image_id, group_layer_id, parent_layer_id, position);
+ if(gap_debug)
+ {
+ printf("gap_image_greate_group_layer_path: name[%d]:%s group_layer_id:%d\n"
+ , (int)l_ii
+ , namePtr
+ , (int)group_layer_id
+ );
+ }
+
+ parent_layer_id = group_layer_id;
+ }
+ position = 0;
+ }
+ }
+
+ return (group_layer_id);
+
+} /* end gap_image_greate_group_layer_path */
+
+
+
+
+
+/* -----------------------------------------------
+ * gap_image_find_or_create_group_layer
+ * -----------------------------------------------
+ * find the group layer where the name
+ * (and concateneated names of all its parent group layers when present)
+ * is equal to the specified group_name_path.
+ * and return its item_id
+ * Group_layer names levels are concatenated with the specified separator character.
+ *
+ * an empty group_name_path_string (NULL or \0) will return 0
+ * which refers to the toplevel (indicating that no group is relevant)
+ *
+ * in case the wanted group was not found
+ * the result depends on the flag enableCreate.
+ * when enableCreate == TRUE
+ * the group layer (and all missing parent groups) are created
+ * and its item_id is returned.
+ * when enableCreate == FALSE
+ * -1 is returned (indicating that the wanted group was not found)
+ *
+ * Example (separator character '/' is assumed)
+ *
+ * layertree example
+ * --------------------
+ * toplayer id:4
+ * gr-sky id:3
+ * subgr-1.1 id:7
+ * layer-sun id:13
+ * gr-2 id:2
+ * subgr-animals id:6
+ * layer-cat id:12
+ * layer-dog id:11
+ * subgr-house id:5
+ * layer-roof id:10
+ * layer-window id:9
+ * layer-wall id:8
+ * background id:1
+ *
+ * o) a call with group_name_path_string = "gr-2/subgr-animals"
+ * will return 6, because the group layer with name "subgr-animals"
+ * can be found.
+ * o) a call with group_name_path_string = "gr-2/subgr-animals/flying/birds"
+ * will either return -1
+ * or create both missing groups "flying" and "birds"
+ * and will return the item_id of the "birds" group.
+ * gr-2 id:2
+ * subgr-animals id:6
+ * flying id:14 # newly created group layer
+ * birds id:15 # newly created group layer
+ * layer-cat id:12
+ * layer-dog id:11
+ * o) a call with group_name_path_string = "toplayer"
+ * will return -1, because this layer already exists
+ * but is not a group layer.
+ *
+ */
+gint32
+gap_image_find_or_create_group_layer(gint32 image_id
+ , gchar *group_name_path_string
+ , gchar *delimiter
+ , gint stackposition
+ , gboolean enableCreate
+)
+{
+ gchar **nameArray;
+ gchar *namePtr;
+ gint l_nlayers;
+ gint l_treelevel;
+ gint l_ii;
+ gint l_idx;
+ gint l_position;
+ gint32 *l_src_layers;
+ gint32 l_layer_id;
+
+ gint32 l_parent_layer_id;
+ gint32 l_group_layer_id;
+
+ if (group_name_path_string == NULL)
+ {
+ return (0);
+ }
+ if (*group_name_path_string == '\0')
+ {
+ return (0);
+ }
+
+ l_parent_layer_id = 0; /* start at top imagelevel */
+ l_group_layer_id = -1;
+ l_position = stackposition;
+
+ if(delimiter != NULL)
+ {
+ nameArray = g_strsplit(group_name_path_string
+ , delimiter
+ , -1 /* max_tokens less than 1 splits the string completely. */
+ );
+ }
+ else
+ {
+ nameArray = g_malloc(sizeof(gchar*) * 2);
+ nameArray[0] = g_strdup(group_name_path_string);
+ nameArray[1] = NULL;
+ }
+
+ if (nameArray == NULL)
+ {
+ return (0);
+ }
+ l_src_layers = gimp_image_get_layers (image_id, &l_nlayers);
+ if (l_src_layers == NULL)
+ {
+ if (enableCreate)
+ {
+ l_group_layer_id = gap_image_greate_group_layer_path(image_id
+ , l_parent_layer_id /* 0 is on top imagelevel */
+ , l_position /* 0 on top stackposition */
+ , nameArray
+ , 0
+ );
+ }
+ g_strfreev(nameArray);
+ return (l_group_layer_id);
+ }
+
+ for(l_ii = 0; nameArray[l_ii] != NULL; l_ii++)
+ {
+ gboolean l_found;
+ l_found = FALSE;
+
+ namePtr = nameArray[l_ii];
+
+ if(gap_debug)
+ {
+ printf("gap_image_find_or_create_group_layer: name[%d]:%s\n"
+ , (int)l_ii
+ , namePtr
+ );
+ }
+
+
+ for(l_idx = 0; l_idx < l_nlayers; l_idx++)
+ {
+ gchar *l_name;
+
+ l_name = gimp_item_get_name(l_src_layers[l_idx]);
+ if(gap_debug)
+ {
+ printf("cmp: name[%d]:%s with item[%d]:%d name:%s\n"
+ , (int)l_ii
+ , namePtr
+ , (int)l_idx
+ , (int)l_src_layers[l_idx]
+ , l_name
+ );
+ }
+ if (strcmp(l_name, namePtr) == 0)
+ {
+ if (gimp_item_is_group(l_src_layers[l_idx]))
+ {
+ l_parent_layer_id = l_src_layers[l_idx];
+ l_position = 0;
+ l_found = TRUE;
+ }
+ else
+ {
+ if(gap_debug)
+ {
+ printf("ERROR: gap_image_find_or_create_group_layer the path\n %s\n"
+ " refers to an already exsiting item that is NOT a GROUP\n"
+ , group_name_path_string
+ );
+ }
+ g_free(l_name);
+ g_free(l_src_layers);
+ return (-1);
+ }
+ }
+ g_free(l_name);
+ if (l_found)
+ {
+ break;
+ }
+ }
+ g_free(l_src_layers);
+ l_src_layers = NULL;
+
+
+ if(gap_debug)
+ {
+ printf(" l_found:%d l_parent_layer_id:%d\n"
+ , (int)l_found
+ , (int)l_parent_layer_id
+ );
+ }
+ if (l_found)
+ {
+ if (nameArray[l_ii +1] == NULL)
+ {
+ /* no more names to compare and all did match, we are done */
+ l_group_layer_id = l_parent_layer_id;
+ }
+ else
+ {
+ /* check next treelevel e.g. members of the current group */
+ l_src_layers = gimp_item_get_children (l_parent_layer_id, &l_nlayers);
+ }
+ }
+ else
+ {
+ if (enableCreate)
+ {
+ /* create all missing groups/subgroups */
+ l_group_layer_id = gap_image_greate_group_layer_path(image_id
+ , l_parent_layer_id /* 0 is on top imagelevel */
+ , l_position /* 0 on top stackposition */
+ , nameArray
+ , l_ii
+ );
+ }
+ break;
+ }
+ }
+
+ if(gap_debug)
+ {
+ printf("gap_image_find_or_create_group_layer BEFORE g_strfreev l_group_layer_id:%d\n"
+ ,(int)l_group_layer_id
+ );
+ }
+
+ g_strfreev(nameArray);
+
+ return(l_group_layer_id);
+
+} /* end gap_image_find_or_create_group_layer */
diff --git a/gap/gap_image.h b/gap/gap_image.h
index 59c7b2b..bfc04cc 100644
--- a/gap/gap_image.h
+++ b/gap/gap_image.h
@@ -42,6 +42,12 @@
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
+typedef struct {
+ gint stack_position;
+ void *next;
+} GapImageStackPositionsList;
+
+
void gap_image_delete_immediate (gint32 image_id);
gint32 gap_image_merge_visible_layers(gint32 image_id, GimpMergeType mergemode);
void gap_image_prevent_empty_image(gint32 image_id);
@@ -61,5 +67,23 @@ gint32 gap_image_create_unicolor_image(gint32 *layer_id, gint32 width , gint3
, gdouble r_f, gdouble g_f, gdouble b_f, gdouble a_f);
+GapImageStackPositionsList * gap_image_get_tree_position_list(gint32 item_id);
+void gap_image_gfree_tree_position_list(GapImageStackPositionsList *rootPosPtr);
+gint32 gap_image_get_layer_id_by_tree_position_list(gint32 image_id, GapImageStackPositionsList
*rootPosPtr);
+gint32 gap_image_greate_group_layer_path(gint32 image_id
+ , gint32 parent_id /* or 0 for top imagelevel */
+ , gint32 stackposition /* where 0 is on top position */
+ , gchar **nameArray
+ , gint start_idx
+ );
+
+gint32 gap_image_find_or_create_group_layer(gint32 image_id
+ , gchar *group_name_path_string
+ , gchar *delimiter
+ , gint stackposition
+ , gboolean enableCreate
+ );
+
+
#endif
diff --git a/gap/gap_mov_dialog.c b/gap/gap_mov_dialog.c
index e81f32d..0806426 100644
--- a/gap/gap_mov_dialog.c
+++ b/gap/gap_mov_dialog.c
@@ -140,6 +140,10 @@ extern int gap_debug; /* ==0 ... dont print debug infos */
#define SPINBUTTON_WIDTH 60
#define SCALE_WIDTH 125
+#define ENTRY_DELIMITER_WIDTH 20
+#define ENTRY_GROUP_PATH_WIDTH 200
+
+
/* instant apply is implemented via timer, configured to fire 10 times per second (100 msec)
* this collects instant_apply_requests set by other widget callbacks and events
* and then update only once.
@@ -302,7 +306,7 @@ typedef struct
* TRUE
* (typically called from the storyboard for update xml file settings)
* - invoke from any image is tolerated
- * - rendering of frames is DISABLED
+ * - rendering of frames is DISABLED
* (Animated preview rendering is allowed)
* - frame range limits are 1 upto 999999.
* - the moving object (source image) is fixed by the caller,
@@ -325,18 +329,22 @@ typedef struct
*/
gboolean isRecordOnlyMode;
gboolean isStandaloneGui;
-
+
t_close_movepath_edit_callback_fptr close_fptr;
gpointer callback_data;
-
+
gchar xml_paramfile[GAP_MOVPATH_XML_FILENAME_MAX_LENGTH];
+ // GtkWidget *clip_to_img_check_button;
+ GtkWidget *dstGroupPathEntry;
+ GtkWidget *dstGroupDelimiterEntry;
+
} t_mov_gui_stuff;
/* Declare local functions.
*/
-static long p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
+static void p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
, GapMovData *mov_ptr
, gboolean isRecordOnlyMode
, gboolean isStandaloneGui
@@ -448,6 +456,8 @@ static void mov_stepmode_menu_callback (GtkWidget *, t_mov_gui_stuff *mgp);
static void mov_tweenlayer_sensitivity(t_mov_gui_stuff *mgp);
static void mov_tracelayer_sensitivity(t_mov_gui_stuff *mgp);
static void mov_gint_toggle_callback (GtkWidget *, gpointer);
+static void on_dstGroupPathEntry_changed (GtkEditable *editable, t_mov_gui_stuff *mgp);
+static void on_dstGroupDelimiterEntry_changed (GtkEditable *editable, t_mov_gui_stuff *mgp);
static void mov_force_visibility_toggle_callback ( GtkWidget *widget, gpointer data );
static void mov_bluebox_callback (GtkWidget *, gpointer);
static void mov_tracelayer_callback (GtkWidget *, gpointer);
@@ -539,20 +549,20 @@ gap_mov_dlg_move_dialog (GapMovData *mov_ptr)
mgp = g_new( t_mov_gui_stuff, 1 );
mgp->shell = NULL;
mgp->pointfile_name = NULL;
-
+
isRecordOnlyMode = FALSE;
isStandaloneGui = TRUE;
p_gap_mov_dlg_move_dialog(mgp, mov_ptr, isRecordOnlyMode, isStandaloneGui, NULL, NULL, 1);
p_free_mgp_resources(mgp);
g_free(mgp);
-
+
if(mov_int.run == TRUE)
{
return 0; /* OK */
}
return -1; /* Cancel or error occured */
-
+
}
@@ -568,7 +578,7 @@ gap_mov_dlg_move_dialog (GapMovData *mov_ptr)
*
* This procedure is typically called be the Storyboard transition attributes dialog
*/
-GtkWidget *
+GtkWidget *
gap_mov_dlg_edit_movepath_dialog (gint32 frame_image_id, gint32 drawable_id
, const char *xml_paramfile
, GapAnimInfo *ainfo_ptr
@@ -607,7 +617,7 @@ gap_mov_dlg_edit_movepath_dialog (gint32 frame_image_id, gint32 drawable_id
pvals = pvals_edit;
-
+
pvals->dst_image_id = frame_image_id;
pvals->bbp_pv = gap_bluebox_bbp_new(-1);
@@ -617,7 +627,7 @@ gap_mov_dlg_edit_movepath_dialog (gint32 frame_image_id, gint32 drawable_id
{
g_snprintf(mgp->xml_paramfile, sizeof(mgp->xml_paramfile), "%s", xml_paramfile);
mgp->pointfile_name = g_strdup_printf("%s", xml_paramfile);
-
+
/* attempt to init settings in case the xml_paramfile
* already contains valid settings
*/
@@ -641,7 +651,7 @@ gap_mov_dlg_edit_movepath_dialog (gint32 frame_image_id, gint32 drawable_id
pvals->bbp = NULL;
pvals->bbp_pv = NULL;
pvals->clip_to_img = 0;
-
+
pvals->step_speed_factor = 1.0;
pvals->tracelayer_enable = FALSE;
pvals->trace_opacity_initial = 100.0;
@@ -688,7 +698,7 @@ gap_mov_dlg_edit_movepath_dialog (gint32 frame_image_id, gint32 drawable_id
* ------------------------------------------
*
*/
-static long
+static void
p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
, GapMovData *mov_ptr
, gboolean isRecordOnlyMode
@@ -750,6 +760,8 @@ p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
mgp->dst_layerstack_adj = NULL;
mgp->src_force_visible_check_button = NULL;
mgp->clip_to_img_check_button = NULL;
+ mgp->dstGroupPathEntry = NULL;
+ mgp->dstGroupDelimiterEntry = NULL;
mgp->tracelayer_enable_check_button = NULL;
mgp->src_apply_bluebox_check_button = NULL;
mgp->bluebox_keycolor_color_button = NULL;
@@ -762,7 +774,7 @@ p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
pvals = mov_ptr->val_ptr;
-
+
if(mgp->pointfile_name == NULL)
{
if(mov_ptr->dst_ainfo_ptr->basename != NULL)
@@ -797,11 +809,11 @@ p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
l_last = mov_ptr->dst_ainfo_ptr->last_frame_nr;
l_curr = mov_ptr->dst_ainfo_ptr->curr_frame_nr;
l_max = l_last;
-
+
pvals->src_image_id = -1;
pvals->src_layer_id = -1;
pvals->src_stepmode = GAP_STEP_LOOP;
-
+
}
/* init parameter values */
@@ -837,7 +849,7 @@ p_gap_mov_dlg_move_dialog(t_mov_gui_stuff *mgp
pvals->bbp = NULL;
pvals->bbp_pv = NULL;
pvals->clip_to_img = 0;
-
+
pvals->step_speed_factor = 1.0;
pvals->tracelayer_enable = FALSE;
pvals->trace_opacity_initial = 100.0;
@@ -900,12 +912,12 @@ p_free_mgp_resources(t_mov_gui_stuff *mgp)
{
return;
}
-
+
if(gap_debug)
{
printf("p_free_mgp_resources START\n");
}
-
+
/* destroy the tmp image(s) */
if(pvals->tmp_image_id >= 0)
{
@@ -1158,7 +1170,7 @@ mov_dialog ( GimpDrawable *drawable, t_mov_gui_stuff *mgp,
gtk_main ();
gdk_flush ();
}
-
+
if(gap_debug) printf("GAP-DEBUG: END mov_dialog\n");
return mov_int.run;
@@ -1237,7 +1249,7 @@ mov_close_callback (GtkWidget *widget,
gtk_widget_destroy (l_shell);
p_free_mgp_resources(mgp);
}
-
+
if(mgp->isStandaloneGui)
{
if(gap_debug)
@@ -1255,7 +1267,7 @@ mov_close_callback (GtkWidget *widget,
}
gtk_main_quit ();
}
-
+
} /* end mov_close_callback */
@@ -1335,7 +1347,7 @@ mov_upvw_callback (GtkWidget *widget,
);
}
l_filename = NULL;
-
+
if(mgp->ainfo_ptr->ainfo_type == GAP_AINFO_FRAMES)
{
if(gap_debug)
@@ -1359,8 +1371,8 @@ mov_upvw_callback (GtkWidget *widget,
);
}
}
-
-
+
+
if(!mgp->instant_apply)
{
/* dont show waiting cursor at instant_apply
@@ -1413,9 +1425,9 @@ mov_upvw_callback (GtkWidget *widget,
*/
l_new_tmp_image_id = gimp_image_duplicate(mgp->ainfo_ptr->image_id);
}
-
-
-
+
+
+
if (l_new_tmp_image_id >= 0)
{
/* use the new loaded temporary image */
@@ -2549,7 +2561,7 @@ p_refresh_widgets_after_load(t_mov_gui_stuff *mgp)
{
gtk_adjustment_set_value(mgp->trace_opacity_desc_adj, pvals->trace_opacity_desc);
}
-
+
if(mgp->tracelayer_enable_check_button != NULL)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->tracelayer_enable_check_button),
@@ -2561,19 +2573,30 @@ p_refresh_widgets_after_load(t_mov_gui_stuff *mgp)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->src_force_visible_check_button),
pvals->src_force_visible);
}
-
+
if (mgp->clip_to_img_check_button != NULL)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->clip_to_img_check_button),
pvals->clip_to_img);
}
-
+
+ if ((mgp->dstGroupPathEntry != NULL) && (pvals->dst_group_name_path_string != NULL))
+ {
+ gtk_entry_set_text (GTK_ENTRY (mgp->dstGroupPathEntry),
+ pvals->dst_group_name_path_string);
+ }
+ if ((mgp->dstGroupDelimiterEntry != NULL) && (pvals->dst_group_name_delimiter != NULL))
+ {
+ gtk_entry_set_text (GTK_ENTRY (mgp->dstGroupDelimiterEntry),
+ pvals->dst_group_name_delimiter);
+ }
+
if (mgp->src_apply_bluebox_check_button != NULL)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->src_apply_bluebox_check_button),
pvals->src_apply_bluebox);
}
-
+
if (mgp->bluebox_keycolor_color_button != NULL)
{
if(pvals->bbp != NULL)
@@ -2820,10 +2843,15 @@ mov_imglayer_menu_callback(GtkWidget *widget, t_mov_gui_stuff *mgp)
static gint
mov_imglayer_constrain(gint32 image_id, gint32 drawable_id, gpointer data)
{
- if(gap_debug) printf("GAP-DEBUG: mov_imglayer_constrain PROCEDURE image_id:%d drawable_id:%d\n"
+ if(gap_debug)
+ {
+ printf("GAP-DEBUG: mov_imglayer_constrain PROCEDURE image_id:%d drawable_id:%d name:%s\n"
,(int)image_id
,(int)drawable_id
+ , gimp_item_get_name(drawable_id)
);
+ }
+
if(drawable_id < 0)
{
@@ -2838,6 +2866,11 @@ mov_imglayer_constrain(gint32 image_id, gint32 drawable_id, gpointer data)
return(FALSE);
}
+ if (!gimp_drawable_is_layer(drawable_id))
+ {
+ return(FALSE);
+ }
+
/* dont accept layers from within the destination image id
* or layers within the internal used tmporary images
@@ -2992,6 +3025,52 @@ mov_gint_toggle_callback(GtkWidget *w, gpointer client_data)
} /* end mov_gint_toggle_callback */
static void
+on_dstGroupPathEntry_changed (GtkEditable *editable,
+ t_mov_gui_stuff *mgp)
+{
+ if(gap_debug) printf("CB: on_dstGroupPathEntry_changed\n");
+
+ if (pvals)
+ {
+ if (pvals->dst_group_name_path_string != NULL)
+ {
+ g_free(pvals->dst_group_name_path_string);
+ pvals->dst_group_name_path_string = NULL;
+ }
+ pvals->dst_group_name_path_string = g_strdup(gtk_entry_get_text(GTK_ENTRY(editable)));
+ }
+
+ if(mgp)
+ {
+ mov_set_instant_apply_request(mgp);
+ }
+} /* end on_dstGroupPathEntry_changed */
+
+static void
+on_dstGroupDelimiterEntry_changed (GtkEditable *editable,
+ t_mov_gui_stuff *mgp)
+{
+ if(gap_debug) printf("CB: on_dstGroupDelimiterEntry_changed\n");
+
+ if (pvals)
+ {
+ if (pvals->dst_group_name_delimiter != NULL)
+ {
+ g_free(pvals->dst_group_name_delimiter);
+ pvals->dst_group_name_delimiter = NULL;
+ }
+ pvals->dst_group_name_delimiter = g_strdup(gtk_entry_get_text(GTK_ENTRY(editable)));
+ }
+
+ if(mgp)
+ {
+ mov_set_instant_apply_request(mgp);
+ }
+} /* end on_dstGroupDelimiterEntry_changed */
+
+
+
+static void
mov_force_visibility_toggle_callback (GtkWidget *widget, gpointer client_data)
{
t_mov_gui_stuff *mgp;
@@ -3105,7 +3184,7 @@ mov_remove_timer(t_mov_gui_stuff *mgp)
{
return;
}
-
+
if(mgp->instant_timertag >= 0)
{
g_source_remove(mgp->instant_timertag);
@@ -3662,7 +3741,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
gtk_widget_show(combo);
mgp->src_layer_combo = combo;
-
+
if(mgp->isRecordOnlyMode)
{
gtk_widget_hide(label);
@@ -3711,17 +3790,17 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
{
gint initialValue;
initialValue = GIMP_NORMAL_MODE;
-
+
if(pvals)
{
initialValue = pvals->src_paintmode;
}
-
+
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
initialValue,
G_CALLBACK (mov_paintmode_menu_callback),
mgp);
-
+
}
gtk_table_attach(GTK_TABLE(table), combo, 3, 4, 0, 1,
@@ -3771,16 +3850,16 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
G_CALLBACK (gimp_double_adjustment_update),
&pvals->step_speed_factor);
mgp->step_speed_factor_adj = GTK_ADJUSTMENT(adj);
-
+
if(mgp->isRecordOnlyMode)
{
GtkWidget *widget;
-
+
widget = g_object_get_data(G_OBJECT (adj), "label");
gtk_widget_hide(widget);
widget = g_object_get_data(G_OBJECT (adj), "spinbutton");
gtk_widget_hide(widget);
-
+
}
@@ -3813,7 +3892,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
G_CALLBACK (mov_stepmode_menu_callback),
mgp);
}
-
+
gtk_table_attach(GTK_TABLE(sub_table), combo, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, 0, 0, 0);
gimp_help_set_help_data(combo,
@@ -3845,7 +3924,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
_("Center"), GAP_HANDLE_CENTER,
NULL);
-
+
{
gint initialValue;
@@ -3863,7 +3942,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
break;
}
}
-
+
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
initialValue,
G_CALLBACK (mov_handmode_menu_callback),
@@ -4399,6 +4478,8 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
GtkWidget *table;
GtkAdjustment *adj;
GtkWidget *check_button;
+ GtkWidget *entry;
+ GtkWidget *label;
gint master_rows;
gint master_cols;
gint tabcol, tabrow, boxcol, boxrow;
@@ -4435,8 +4516,10 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
, GTK_FILL|GTK_EXPAND, GTK_FILL, 4, 0);
gtk_widget_show (table);
+ row = 0;
+
/* the start frame scale_entry */
- adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 0, /* table col, row */
+ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, row, /* table col, row */
_("From Frame:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gdouble)pvals->dst_range_start, /* value */
@@ -4457,8 +4540,10 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
mgp);
mgp->dst_range_start_adj = adj;
+ row++;
+
/* the end frame scale_entry */
- adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */
+ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, row, /* table col, row */
_("To Frame:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gdouble)pvals->dst_range_end, /* value */
@@ -4479,8 +4564,10 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
mgp);
mgp->dst_range_end_adj = adj;
+ row++;
+
/* the Layerstack scale_entry */
- adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 2, /* table col, row */
+ adj = gimp_scale_entry_new( GTK_TABLE (table), 0, row, /* table col, row */
_("Layerstack:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gdouble)pvals->dst_layerstack, /* value */
@@ -4499,8 +4586,63 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
&pvals->dst_layerstack);
mgp->dst_layerstack_adj = adj;
+ row++;
+
+ /* destination group path */
+ label = gtk_label_new(_("Target Group:"));
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+ gtk_widget_show (label);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1
+ , GTK_FILL, GTK_FILL, 4, 0);
+
+ entry = gtk_entry_new();
+ gtk_widget_show (entry);
+ gtk_widget_set_size_request (entry, ENTRY_GROUP_PATH_WIDTH, -1);
+ gtk_table_attach (GTK_TABLE (table), entry, 1, 2, row, row+1,
+ (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
+ (GtkAttachOptions) (0), 0, 0);
+ gimp_help_set_help_data (entry, _("group/subgroup name path where to insert the rendered object. "
+ "note that the specified group (and subgroups) will be created "
+ "automatically in all processed target frames where they are not already
present. "
+ "Leave the target group empty when insert into the image outside groups
is desired")
+ , NULL);
+ if (pvals->dst_group_name_path_string != NULL)
+ {
+ gtk_entry_set_text (GTK_ENTRY (entry), pvals->dst_group_name_path_string);
+ }
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (on_dstGroupPathEntry_changed),
+ mgp);
+ mgp->dstGroupPathEntry = entry;
+
+
+ entry = gtk_entry_new();
+ gtk_widget_show (entry);
+ gtk_widget_set_size_request (entry, ENTRY_DELIMITER_WIDTH, -1);
+ gtk_table_attach (GTK_TABLE (table), entry, 2, 3, row, row+1,
+ (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
+ (GtkAttachOptions) (0), 0, 0);
+ gimp_help_set_help_data (entry, _("delimiter to separate group/subgroup"), NULL);
+ if (pvals->dst_group_name_delimiter != NULL)
+ {
+ gtk_entry_set_text (GTK_ENTRY (entry), pvals->dst_group_name_delimiter);
+ }
+ g_signal_connect (G_OBJECT (entry), "changed",
+ G_CALLBACK (on_dstGroupDelimiterEntry_changed),
+ mgp);
+ mgp->dstGroupDelimiterEntry = entry;
+
+
+
+
+
+
+
+
+
+
/* the table for checkbuttons and info labels */
- table = gtk_table_new (3, 3, FALSE);
+ table = gtk_table_new (4, 3, FALSE);
gtk_widget_show (table);
row = 0;
@@ -5532,7 +5674,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
G_CALLBACK (mov_instant_int_adjustment_update),
&mgp->preview_frame_nr);
mgp->preview_frame_nr_adj = GTK_ADJUSTMENT(adj);
-
+
if(mgp->ainfo_ptr->ainfo_type != GAP_AINFO_FRAMES)
{
GtkWidget *widget;
@@ -5552,7 +5694,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
{
gtk_widget_hide(widget);
}
-
+
}
@@ -6380,21 +6522,8 @@ p_get_prevw_drawable (t_mov_gui_stuff *mgp)
l_curr.accSelFeatherRadius = (gdouble)mgp->accSelFeatherRadius;
- l_curr.src_layer_idx = 0;
- l_curr.src_layers = gimp_image_get_layers (pvals->src_image_id, &l_nlayers);
+ gap_mov_exec_set_iteration_relevant_src_layers(&l_curr, pvals->src_layer_id, pvals->src_image_id);
- if((l_curr.src_layers != NULL) && (l_nlayers > 0))
- {
- l_curr.src_last_layer = l_nlayers -1;
- /* findout index of src_layer_id */
- for(l_curr.src_layer_idx = 0;
- l_curr.src_layer_idx < l_nlayers;
- l_curr.src_layer_idx++)
- {
- if(l_curr.src_layers[l_curr.src_layer_idx] == pvals->src_layer_id)
- break;
- }
- }
if(pvals->src_stepmode >= GAP_STEP_FRAME)
{
gap_mov_render_fetch_src_frame (pvals, -1); /* negative value fetches the selected frame number */
diff --git a/gap/gap_mov_dialog.h b/gap/gap_mov_dialog.h
index 3d311d9..f6f800a 100644
--- a/gap/gap_mov_dialog.h
+++ b/gap/gap_mov_dialog.h
@@ -92,13 +92,14 @@ typedef enum
} GapMovSelMode;
typedef struct {
- long dst_frame_nr; /* current destination frame_nr */
- long src_layer_idx; /* index of current layer (used for multilayer stepmodes) */
- long src_frame_idx; /* current frame number (used for source frame stepmodes) */
+ gint32 dst_frame_nr; /* current destination frame_nr */
+ gint32 src_layer_parent_id; /* 0 for toplevel layer that are not member of a layer group */
+ gint32 src_layer_idx; /* index of current layer within group or image (used for multilayer
stepmodes) */
+ gint32 src_frame_idx; /* current frame number (used for source frame stepmodes) */
gdouble src_layer_idx_dbl;
gdouble src_frame_idx_dbl;
- gint32 *src_layers; /* array of source images layer id's (used for multilayer stepmodes) */
- long src_last_layer; /* index of last layer 0 upto n-1 (used for multilayer stepmodes) */
+ gint32 *src_layers; /* array of layer id's in hte same layer group or image (used for
multilayer stepmodes) */
+ gint32 src_last_layer_idx; /* index of last layer 0 upto n-1 within group or image (used for
multilayer stepmodes) */
gdouble currX, currY;
gint l_handleX;
gint l_handleY;
@@ -264,6 +265,8 @@ typedef struct {
gdouble rotate_threshold;
+ gchar *dst_group_name_path_string;
+ gchar *dst_group_name_delimiter;
} GapMovValues;
diff --git a/gap/gap_mov_exec.c b/gap/gap_mov_exec.c
index 363fef3..9b4e840 100644
--- a/gap/gap_mov_exec.c
+++ b/gap/gap_mov_exec.c
@@ -137,6 +137,89 @@ static gint p_calculate_settings_for_current_FrameTween(
+/* -----------------------------------------------
+ * gap_mov_exec_set_iteration_relevant_src_layers
+ * -----------------------------------------------
+ * get the source layers that are in the same group or image
+ * and therefore are relevant for iteration in the animation.
+ * store them in the specified GapMovCurrent *cur_ptr
+ * AS attributes:
+ * curr_ptr->src_layers
+ * ## is set to array of relevant src_layer_ids (within group or image)
+ * curr_ptr->src_layer_idx
+ * ## is set to index of src layer within src_layer array.
+ * curr_ptr->src_last_layer_idx
+ * ## is set to the last valid index in the src_layers array.
+ *
+ * Note that animation of a toplevel layer iterates over all toplevel layers
+ * (where groups are treated as if they were a single layer)
+ *
+ * But if the src_layer_id is member of a layer group, the animation
+ * itaration is done on the members of the same group.
+ * (when the group contains sub groups, the sub groups act as if they were
+ * a single layer)
+ */
+void
+gap_mov_exec_set_iteration_relevant_src_layers(GapMovCurrent *cur_ptr, gint32 src_layer_id, gint32
src_image_id)
+{
+ gint32 l_src_layer_parent_id; /* 0 for toplevel layer that is not member of a layer group */
+ gint l_nlayers;
+
+ cur_ptr->src_layers = NULL;
+ cur_ptr->src_layer_idx = 0;
+ cur_ptr->src_last_layer_idx = -1; /* indicate invalid src layer */
+
+ if (src_layer_id < 0)
+ {
+ return;
+ }
+
+ l_src_layer_parent_id = gimp_item_get_parent (src_layer_id);
+ if(gap_debug)
+ {
+ printf("gap_mov_exec_set_iteration_relevant_src_layers: src_layer_id:%d, src_layer_parent_id:%d\n"
+ , (int)src_layer_id
+ , (int)l_src_layer_parent_id
+ );
+ }
+ if (l_src_layer_parent_id > 0)
+ {
+ /* the src layer is member of a layergroup, get all members of the group */
+ cur_ptr->src_layers = gimp_item_get_children (l_src_layer_parent_id, &l_nlayers);
+ }
+ else
+ {
+ /* the src layer is a toplevel layer, get all toplevel layers of the image */
+ cur_ptr->src_layers = gimp_image_get_layers (src_image_id, &l_nlayers);
+ }
+
+
+ if((cur_ptr->src_layers != NULL) && (l_nlayers > 0))
+ {
+ cur_ptr->src_last_layer_idx = l_nlayers -1;
+ /* findout index of src_layer_id (within group or image) */
+ for(cur_ptr->src_layer_idx = 0;
+ cur_ptr->src_layer_idx < l_nlayers;
+ cur_ptr->src_layer_idx++)
+ {
+ if(gap_debug)
+ {
+ printf("gap_mov_exec_set_iteration_relevant_src_layers: l_nlayers:%d, src_layer_id:%d,
cur_ptr->src_layer_idx:%d\n"
+ , (int)l_nlayers
+ , (int)cur_ptr->src_layers[cur_ptr->src_layer_idx]
+ , (int)cur_ptr->src_layer_idx
+ );
+ }
+ if(cur_ptr->src_layers[cur_ptr->src_layer_idx] == src_layer_id)
+ {
+ cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_layer_idx;
+ return;
+ }
+ }
+ }
+ cur_ptr->src_layer_idx = 0;
+
+} /* end gap_mov_exec_set_iteration_relevant_src_layers */
@@ -538,7 +621,7 @@ p_mov_advance_src_layer(GapMovCurrent *cur_ptr, GapMovValues *pvals)
gdouble l_round;
/* limit step factor to number of available layers -1 */
- l_step_speed_factor = MIN(pvals->step_speed_factor, (gdouble)cur_ptr->src_last_layer);
+ l_step_speed_factor = MIN(pvals->step_speed_factor, (gdouble)cur_ptr->src_last_layer_idx);
if(pvals->tween_steps > 0)
{
/* when we have tweens, the speed_factor must be divided (the +1 is for the real frame) */
@@ -550,7 +633,7 @@ p_mov_advance_src_layer(GapMovCurrent *cur_ptr, GapMovValues *pvals)
{
printf("p_mov_advance_src_layer: stepmode=%d last_layer=%d idx=%d (%.4f) speed_factor: %.4f\n",
(int)pvals->src_stepmode,
- (int)cur_ptr->src_last_layer,
+ (int)cur_ptr->src_last_layer_idx,
(int)cur_ptr->src_layer_idx,
(float)cur_ptr->src_layer_idx_dbl,
(float)l_step_speed_factor
@@ -562,15 +645,15 @@ p_mov_advance_src_layer(GapMovCurrent *cur_ptr, GapMovValues *pvals)
* therfore reverse loops have to count up
* forward loop is defined as sequence from BG to TOP layer
*/
- if((cur_ptr->src_last_layer > 0 ) && (pvals->src_stepmode != GAP_STEP_NONE))
+ if((cur_ptr->src_last_layer_idx > 0 ) && (pvals->src_stepmode != GAP_STEP_NONE))
{
switch(pvals->src_stepmode)
{
case GAP_STEP_ONCE_REV:
cur_ptr->src_layer_idx_dbl += l_step_speed_factor;
- if(cur_ptr->src_layer_idx_dbl > cur_ptr->src_last_layer)
+ if(cur_ptr->src_layer_idx_dbl > cur_ptr->src_last_layer_idx)
{
- cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_last_layer;
+ cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_last_layer_idx;
}
break;
case GAP_STEP_ONCE:
@@ -593,18 +676,18 @@ p_mov_advance_src_layer(GapMovCurrent *cur_ptr, GapMovValues *pvals)
}
else
{
- if(cur_ptr->src_layer_idx_dbl >= (gdouble)(cur_ptr->src_last_layer +1))
+ if(cur_ptr->src_layer_idx_dbl >= (gdouble)(cur_ptr->src_last_layer_idx +1))
{
- cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_last_layer - 1.0;
+ cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_last_layer_idx - 1.0;
l_ping = -1;
}
}
break;
case GAP_STEP_LOOP_REV:
cur_ptr->src_layer_idx_dbl += l_step_speed_factor;
- if(cur_ptr->src_layer_idx_dbl >= (gdouble)(cur_ptr->src_last_layer +1))
+ if(cur_ptr->src_layer_idx_dbl >= (gdouble)(cur_ptr->src_last_layer_idx +1))
{
- cur_ptr->src_layer_idx_dbl -= (gdouble)(cur_ptr->src_last_layer + 1);
+ cur_ptr->src_layer_idx_dbl -= (gdouble)(cur_ptr->src_last_layer_idx + 1);
}
break;
case GAP_STEP_LOOP:
@@ -612,13 +695,22 @@ p_mov_advance_src_layer(GapMovCurrent *cur_ptr, GapMovValues *pvals)
cur_ptr->src_layer_idx_dbl -= l_step_speed_factor;
if(cur_ptr->src_layer_idx_dbl < -0.5)
{
- cur_ptr->src_layer_idx_dbl += (gdouble)(cur_ptr->src_last_layer + 1);
+ cur_ptr->src_layer_idx_dbl += (gdouble)(cur_ptr->src_last_layer_idx + 1);
}
l_round = 0.5;
break;
}
cur_ptr->src_layer_idx = MAX((long)(cur_ptr->src_layer_idx_dbl + l_round), 0);
+ if(gap_debug)
+ {
+ printf("p_advance_src_layer: src_layer_idx_dbl %f l_step_speed_factor:%f layer_idx_dbl+round:%f
src_layer_idx:%d\n"
+ ,(float)cur_ptr->src_layer_idx_dbl
+ ,(float)l_step_speed_factor
+ ,(float)(cur_ptr->src_layer_idx_dbl + l_round)
+ ,(int)cur_ptr->src_layer_idx
+ );
+ }
}
} /* end p_advance_src_layer */
@@ -1484,12 +1576,12 @@ p_log_current_render_params(GapMovData *mov_ptr, GapMovCurrent *cur_ptr)
val_ptr = mov_ptr->val_ptr;
- printf("\nCurrent Render Params: dst_frame_nr:%ld tweenIndex:%d src_layer_idx:%d (dbl:%f)\n"
+ printf("\nCurrent Render Params: dst_frame_nr:%d tweenIndex:%d src_layer_idx:%d (dbl:%f)\n"
" currX:%f currY:%f\n"
" Width:%f Height:%f\n"
" Opacity:%f Rotate:%f clip_to_img:%d force_visibility:%d\n"
" src_stepmode:%d handleX:%d handleY:%d currSelFeatherRadius:%f rotate_threshold:%f\n",
- cur_ptr->dst_frame_nr, (int)val_ptr->twix, (int)cur_ptr->src_layer_idx,
+ (int)cur_ptr->dst_frame_nr, (int)val_ptr->twix, (int)cur_ptr->src_layer_idx,
(float)cur_ptr->src_layer_idx_dbl,
(float)cur_ptr->currX,
(float)cur_ptr->currY,
@@ -1912,32 +2004,20 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
l_sel_channel_id = gimp_image_get_selection(val_ptr->src_image_id);
gap_mov_render_create_or_replace_tempsel_image(l_sel_channel_id, val_ptr, l_all_empty);
}
-
- cur_ptr->src_layers = gimp_image_get_layers (val_ptr->src_image_id, &l_nlayers);
+
+
+ /* allocate and set array cur_ptr->src_layers with ids of relevant layers and findout index of
src_layer_id */
+ gap_mov_exec_set_iteration_relevant_src_layers(cur_ptr, val_ptr->src_layer_id, val_ptr->src_image_id);
if(cur_ptr->src_layers == NULL)
{
printf("ERROR (in p_mov_execute): Got no layers from SrcImage\n");
return -1;
}
- if(l_nlayers < 1)
+ if(cur_ptr->src_last_layer_idx < 0)
{
printf("ERROR (in p_mov_execute): Source Image has no layers\n");
return -1;
}
- cur_ptr->src_last_layer = l_nlayers -1;
-
- /* findout index of src_layer_id */
- for(cur_ptr->src_layer_idx = 0;
- cur_ptr->src_layer_idx < l_nlayers;
- cur_ptr->src_layer_idx++)
- {
- if(cur_ptr->src_layers[cur_ptr->src_layer_idx] == val_ptr->src_layer_id)
- {
- cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_layer_idx;
- break;
- }
- }
- cur_ptr->src_last_layer = l_nlayers -1; /* index of last layer */
}
else
{
@@ -2455,7 +2535,7 @@ p_mov_execute_singleframe(GapMovData *mov_ptr)
cur_ptr->dst_frame_nr = 1;
cur_ptr->src_layers = NULL;
- cur_ptr->src_last_layer = -1;
+ cur_ptr->src_last_layer_idx = -1;
p_init_curr_ptr_with_1st_controlpoint(cur_ptr, val_ptr, singleFramePtr);
/* set offsets (in cur_ptr) according to handle mode and src_img dimension */
@@ -2813,9 +2893,10 @@ gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint
gint32 l_mlayer_image_id;
GimpImageBaseType l_type;
guint l_width, l_height;
- gint32 l_stackpos;
- gint l_nlayers;
- gint32 *l_src_layers;
+ gint32 l_stackpos; /* toplevel stackpos within src image orignal */
+ GapImageStackPositionsList *l_stack_pos_list;
+
+
gint l_rc;
gdouble l_xresoulution, l_yresoulution;
gint32 l_unit;
@@ -2841,6 +2922,7 @@ gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint
/* -1 assume no tmp_image (use unscaled original source) */
l_tmp_image_id = -1;
l_stackpos = 0;
+ l_stack_pos_list = NULL;
/* Scale (down) needed ? */
if((l_pvals->apv_scalex != 100.0) || (l_pvals->apv_scaley != 100.0))
@@ -2866,48 +2948,48 @@ gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint
l_size_y = MAX(1, (gimp_image_height(l_tmp_image_id) * l_pvals->apv_scaley) / 100);
gimp_image_scale(l_tmp_image_id, l_size_x, l_size_y);
- /* findout the src_layer id in the scaled copy by stackpos index */
- l_pvals->src_layer_id = -1;
- l_src_layers = gimp_image_get_layers (pvals_orig->src_image_id, &l_nlayers);
- if(l_src_layers == NULL)
- {
- printf("ERROR: gap_mov_exec_anim_preview GOT no src_layers (original image_id %d)\n",
- (int)pvals_orig->src_image_id);
- }
- else
- {
- for(l_stackpos = 0;
- l_stackpos < l_nlayers;
- l_stackpos++)
- {
- if(l_src_layers[l_stackpos] == pvals_orig->src_layer_id)
- break;
- }
- g_free(l_src_layers);
+ /* findout the src_layer id in the scaled copy by its stackpositions in image and layergroups */
+ l_pvals->src_layer_id = -1;
+ l_stack_pos_list = gap_image_get_tree_position_list(pvals_orig->src_layer_id);
+ if (l_stack_pos_list == NULL)
+ {
+ printf("ERROR: gap_mov_exec_anim_preview GOT no stack position list (original image_id %d)\n",
+ (int)pvals_orig->src_image_id);
+ gimp_image_delete(l_tmp_image_id);
+ return (-1);
+ }
+ else
+ {
+ l_stackpos = l_stack_pos_list->stack_position;
+ l_pvals->src_layer_id =
+ gap_image_get_layer_id_by_tree_position_list(l_tmp_image_id, l_stack_pos_list);
- l_src_layers = gimp_image_get_layers (l_tmp_image_id, &l_nlayers);
- if(l_src_layers == NULL)
- {
- printf("ERROR: gap_mov_exec_anim_preview GOT no src_layers (scaled copy image_id %d)\n",
- (int)l_tmp_image_id);
- }
- else
- {
- l_pvals->src_layer_id = l_src_layers[l_stackpos];
- g_free(l_src_layers);
- }
+ gap_image_gfree_tree_position_list(l_stack_pos_list);
+ }
+ if (l_pvals->src_layer_id < 0)
+ {
+ printf("ERROR: gap_mov_exec_anim_preview Failed to find corresponding layer orig image_id %d
copy:%d)\n"
+ , (int)pvals_orig->src_image_id
+ , (int)l_tmp_image_id
+ );
+ gimp_image_delete(l_tmp_image_id);
+ return (-1);
+ }
- }
if(gap_debug)
{
- printf("gap_mov_exec_anim_preview: orig src_image_id:%d src_layer:%d, stackpos:%d\n"
+ printf("gap_mov_exec_anim_preview: orig src_image_id:%d src_layer:%d, stackpos:%d name:%s\n"
,(int)pvals_orig->src_image_id
,(int)pvals_orig->src_layer_id
- ,(int)l_stackpos);
- printf(" Scaled src_image_id:%d scaled_src_layer:%d\n"
+ ,(int)l_stackpos
+ , gimp_item_get_name(pvals_orig->src_layer_id)
+ );
+ printf(" Scaled src_image_id:%d scaled_src_layer:%d name:%s\n"
,(int)l_tmp_image_id
- ,(int)l_pvals->src_layer_id );
+ ,(int)l_pvals->src_layer_id
+ , gimp_item_get_name(l_pvals->src_layer_id)
+ );
}
}
} /* end if Scaledown needed */
@@ -3041,6 +3123,7 @@ gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint
/* add a display for the animated preview multilayer image */
gimp_display_new(l_mlayer_image_id);
+
/* delete the scaled copy of the src image (if there is one) */
if(l_tmp_image_id >= 0)
{
@@ -3056,6 +3139,9 @@ gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint
} /* end gap_mov_exec_anim_preview */
+
+
+
/* ============================================================================
* p_conv_keyframe
* ============================================================================
@@ -4010,9 +4096,9 @@ void gap_mov_exec_set_handle_offsets(GapMovValues *val_ptr, GapMovCurrent *cur_p
} /* end gap_mov_exec_set_handle_offsets */
-/* ------------------------------------
- * gap_mov_exec_new_GapMovValues
- * ------------------------------------
+/* ------------------------------------------
+ * gap_mov_exec_get_default_rotate_threshold
+ * ------------------------------------------
*/
gdouble
gap_mov_exec_get_default_rotate_threshold()
@@ -4081,6 +4167,8 @@ GapMovValues *gap_mov_exec_new_GapMovValues()
pvals->tween_steps = 0;
pvals->tween_opacity_initial = 80.0;
pvals->tween_opacity_desc = 80.0;
+
+ pvals->dst_group_name_delimiter = g_strdup("/");
return(pvals);
diff --git a/gap/gap_mov_exec.h b/gap/gap_mov_exec.h
index 2d6eff6..7fe8cd6 100644
--- a/gap/gap_mov_exec.h
+++ b/gap/gap_mov_exec.h
@@ -41,6 +41,7 @@
#include "libgimp/gimp.h"
#include "gap_mov_dialog.h"
+void gap_mov_exec_set_iteration_relevant_src_layers(GapMovCurrent *cur_ptr, gint32 src_layer_id, gint32
src_image_id);
gint32 gap_mov_exec_move_path(GimpRunMode run_mode, gint32 image_id, GapMovValues *pvals, gchar *pointfile,
gint rotation_follow, gdouble startangle);
gint32 gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint preview_frame_nr);
gint32 gap_mov_exec_move_path_singleframe(GimpRunMode run_mode, gint32 image_id
@@ -61,6 +62,7 @@ GapMovValues *gap_mov_exec_new_GapMovValues();
gboolean gap_mov_exec_check_valid_xml_paramfile(const char *filename);
+
/* ---------------------------------------------
* gap_mov_exec_move_path_singleframe_directcall
* ---------------------------------------------
diff --git a/gap/gap_mov_render.c b/gap/gap_mov_render.c
index 203d879..a1f2e6c 100644
--- a/gap/gap_mov_render.c
+++ b/gap/gap_mov_render.c
@@ -151,6 +151,7 @@ p_mov_selection_handling(gint32 orig_layer_id
GIMP_RGBA_IMAGE,
100.0, /* full opaque */
GIMP_NORMAL_MODE);
+
gimp_image_insert_layer(val_ptr->tmpsel_image_id, l_tmp_layer_id, 0, 0);
gimp_layer_set_offsets(l_tmp_layer_id, src_offset_x, src_offset_y);
gimp_selection_none(val_ptr->tmpsel_image_id);
@@ -734,6 +735,7 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
GimpLayerModeEffects l_mode;
gdouble scaleWidthPercent;
gdouble scaleHeightPercent;
+ gint32 l_parent_id;
if(gap_debug)
{
@@ -757,6 +759,8 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
image_id
);
}
+
+ l_parent_id = 0;
if(cur_ptr->isSingleFrame)
{
@@ -797,7 +801,13 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
cur_ptr->processedLayerId = -1;
return -1;
}
- gimp_image_insert_layer(image_id, l_cp_layer_id, 0, val_ptr->dst_layerstack);
+ l_parent_id = gap_image_find_or_create_group_layer(image_id
+ , val_ptr->dst_group_name_path_string
+ , val_ptr->dst_group_name_delimiter
+ , val_ptr->dst_layerstack /* stackposition for the group in case it is created
at toplvel */
+ , TRUE /* enableCreate */
+ );
+ gimp_image_insert_layer(image_id, l_cp_layer_id, l_parent_id, val_ptr->dst_layerstack);
}
@@ -854,7 +864,14 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
return -1;
}
- gimp_image_insert_layer(image_id, l_cp_layer_id, 0,
+ l_parent_id = gap_image_find_or_create_group_layer(image_id
+ , val_ptr->dst_group_name_path_string
+ , val_ptr->dst_group_name_delimiter
+ , val_ptr->dst_layerstack /* stackposition for the group in case it is created at
toplvel */
+ , TRUE /* enableCreate */
+ );
+
+ gimp_image_insert_layer(image_id, l_cp_layer_id, l_parent_id,
val_ptr->dst_layerstack);
if(gap_debug)
{
diff --git a/gap/gap_mov_xml_par.c b/gap/gap_mov_xml_par.c
index bd1dc19..73a819e 100644
--- a/gap/gap_mov_xml_par.c
+++ b/gap/gap_mov_xml_par.c
@@ -91,6 +91,9 @@
#define GAP_MOVPATH_XML_TOKEN_SRC_SELMODE "src_selmode"
#define GAP_MOVPATH_XML_TOKEN_SRC_PAINTMODE "src_paintmode"
#define GAP_MOVPATH_XML_TOKEN_DST_LAYERSTACK "dst_layerstack"
+#define GAP_MOVPATH_XML_TOKEN_DST_GROUP_PATH "dst_group_name_path"
+#define GAP_MOVPATH_XML_TOKEN_DST_GROUP_DELIM "dst_group_name_delimiter"
+
#define GAP_MOVPATH_XML_TOKEN_STEP_SPEED_FACTOR "step_speed_factor"
#define GAP_MOVPATH_XML_TOKEN_SRC_FORCE_VISIBLE "src_force_visible"
#define GAP_MOVPATH_XML_TOKEN_CLIP_TO_IMG "clip_to_img"
@@ -213,7 +216,7 @@ static void p_xml_parse_element_controlpoint(const gchar *element_name,
const gchar **attribute_values,
GapMovXmlUserData *userDataPtr,
gint count);
-
+
@@ -326,7 +329,7 @@ static const GEnumValue valuesGapBlueboxThresMode[] =
-/*
+/*
* XML PARSER procedures
*/
@@ -348,7 +351,7 @@ p_xml_parse_value_GapMovHandle(const gchar *attribute_value, GapMovHandle *valDe
*valDestPtr = value;
}
return (isOk);
-
+
} /* end p_xml_parse_value_GapMovHandle */
@@ -389,7 +392,7 @@ p_xml_parse_value_GapMovSelMode(const gchar *attribute_value, GapMovSelMode *val
*valDestPtr = value;
}
return (isOk);
-
+
} /* end p_xml_parse_value_GapMovSelMode */
@@ -409,7 +412,7 @@ p_xml_parse_value_GimpPaintmode_as_gint(const gchar *attribute_value, gint *valD
*valDestPtr = value;
}
return (isOk);
-
+
} /* end gap_xml_parse_value_GimpPaintmode */
@@ -429,7 +432,7 @@ p_xml_parse_value_GapBlueboxThresMode(const gchar *attribute_value, GapBlueboxTh
*valDestPtr = value;
}
return (isOk);
-
+
} /* end p_xml_parse_value_GapBlueboxThresMode */
@@ -439,7 +442,7 @@ p_xml_parse_value_GapBlueboxThresMode(const gchar *attribute_value, GapBlueboxTh
* p_xml_parse_element_root
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_root(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -472,7 +475,7 @@ p_xml_parse_element_root(const gchar *element_name,
* p_xml_parse_element_frame_description
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_frame_description(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -509,7 +512,7 @@ p_xml_parse_element_frame_description(const gchar *element_name,
{
userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->total_frames);
}
-
+
name_cursor++;
value_cursor++;
}
@@ -520,7 +523,7 @@ p_xml_parse_element_frame_description(const gchar *element_name,
* p_xml_parse_element_tween
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_tween(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -561,7 +564,7 @@ p_xml_parse_element_tween(const gchar *element_name,
* p_xml_parse_element_trace
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_trace(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -602,7 +605,7 @@ p_xml_parse_element_trace(const gchar *element_name,
* p_xml_parse_element_moving_object
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_moving_object(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -647,6 +650,14 @@ p_xml_parse_element_moving_object(const gchar *element_name,
{
userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->dst_layerstack);
}
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_DST_GROUP_PATH) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_utf8_string(*value_cursor,
&userDataPtr->pvals->dst_group_name_path_string);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_DST_GROUP_DELIM) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_utf8_string(*value_cursor,
&userDataPtr->pvals->dst_group_name_delimiter);
+ }
else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_STEP_SPEED_FACTOR) == 0)
{
userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor,
&userDataPtr->pvals->step_speed_factor);
@@ -690,7 +701,7 @@ p_xml_parse_element_moving_object(const gchar *element_name,
* p_xml_parse_element_bluebox_parameters
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_bluebox_parameters(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -699,7 +710,7 @@ p_xml_parse_element_bluebox_parameters(const gchar *element_name,
{
const gchar **name_cursor = attribute_names;
const gchar **value_cursor = attribute_values;
-
+
GapBlueboxGlobalParams *bbp;
if(count > 0)
@@ -710,7 +721,7 @@ p_xml_parse_element_bluebox_parameters(const gchar *element_name,
if(userDataPtr->pvals->bbp == NULL)
{
gint32 layer_id;
-
+
layer_id = -1;
userDataPtr->pvals->bbp = gap_bluebox_bbp_new(layer_id);
gap_bluebox_init_default_vals(userDataPtr->pvals->bbp);
@@ -799,7 +810,7 @@ p_xml_parse_element_bluebox_parameters(const gchar *element_name,
* p_xml_parse_element_controlpoints
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_controlpoints(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -808,12 +819,12 @@ p_xml_parse_element_controlpoints(const gchar *element_name,
{
const gchar **name_cursor = attribute_names;
const gchar **value_cursor = attribute_values;
-
+
if(count > 0)
{
userDataPtr->isParseOk = FALSE;
}
-
+
while ((*name_cursor) && (userDataPtr->isParseOk))
{
if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_CURRENT_POINT) == 0)
@@ -828,7 +839,7 @@ p_xml_parse_element_controlpoints(const gchar *element_name,
{
gint numberOfPoints;
userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &numberOfPoints);
-
+
if(userDataPtr->isParseOk)
{
if((numberOfPoints < GAP_MOV_MAX_POINT) && (numberOfPoints > 0))
@@ -840,7 +851,7 @@ p_xml_parse_element_controlpoints(const gchar *element_name,
userDataPtr->isParseOk = FALSE;
}
}
-
+
}
name_cursor++;
@@ -877,7 +888,7 @@ p_set_load_defaults_for_one_controlpoint(GapMovValues *pvals, gint idx)
pvals->point[idx].sel_feather_radius = 0.0;
pvals->point[idx].keyframe = 0; /* 0: controlpoint is not fixed to keyframe */
pvals->point[idx].keyframe_abs = 0; /* 0: controlpoint is not fixed to keyframe */
-
+
pvals->point[idx].accPosition = 0; /* 0: linear (e.g NO acceleration) is default */
pvals->point[idx].accOpacity = 0; /* 0: linear (e.g NO acceleration) is default */
pvals->point[idx].accSize = 0; /* 0: linear (e.g NO acceleration) is default */
@@ -886,7 +897,7 @@ p_set_load_defaults_for_one_controlpoint(GapMovValues *pvals, gint idx)
pvals->point[idx].accSelFeatherRadius = 0; /* 0: linear (e.g NO acceleration) is default */
}
-
+
} /* end p_set_load_defaults_for_one_controlpoint */
@@ -895,7 +906,7 @@ p_set_load_defaults_for_one_controlpoint(GapMovValues *pvals, gint idx)
* p_xml_parse_element_controlpoint
* --------------------------------------
*/
-static void
+static void
p_xml_parse_element_controlpoint(const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -904,14 +915,14 @@ p_xml_parse_element_controlpoint(const gchar *element_name,
{
const gchar **name_cursor = attribute_names;
const gchar **value_cursor = attribute_values;
-
+
if(count >= GAP_MOV_MAX_POINT)
{
userDataPtr->isParseOk = FALSE;
}
-
+
p_set_load_defaults_for_one_controlpoint(userDataPtr->pvals, count);
-
+
while ((*name_cursor) && (userDataPtr->isParseOk))
{
if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_PX) == 0)
@@ -925,7 +936,7 @@ p_xml_parse_element_controlpoint(const gchar *element_name,
else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYFRAME) == 0)
{
gint keyframe;
-
+
userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &keyframe);
userDataPtr->pvals->point[count].keyframe = keyframe;
userDataPtr->pvals->point[count].keyframe_abs = gap_mov_exec_conv_keyframe_to_abs(keyframe,
userDataPtr->pvals);
@@ -934,7 +945,7 @@ p_xml_parse_element_controlpoint(const gchar *element_name,
else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYFRAME_ABS) == 0)
{
gint keyframe_abs;
-
+
userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &keyframe_abs);
userDataPtr->pvals->point[count].keyframe_abs = keyframe_abs;
userDataPtr->pvals->point[count].keyframe = gap_mov_exec_conv_keyframe_to_rel(keyframe_abs,
userDataPtr->pvals);
@@ -1030,13 +1041,13 @@ p_xml_parse_element_controlpoint(const gchar *element_name,
* this handler is called each time the parser recognizes
* the start event of an xml element.
*/
-static void
+static void
p_start_xml_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
GapMovXmlUserData *userDataPtr,
- GError **error)
+ GError **error)
{
gint jj;
@@ -1060,8 +1071,8 @@ p_start_xml_element (GMarkupParseContext *context,
}
if(!userDataPtr->isScopeValid)
{
- /* stop parsing when outsided of known namespace
- * (and stop on duplicate root element too)
+ /* stop parsing when outsided of known namespace
+ * (and stop on duplicate root element too)
*/
return;
}
@@ -1091,7 +1102,7 @@ p_start_xml_element (GMarkupParseContext *context,
* this handler is called each time the parser recognizes
* the end event of an xml element
*/
-static void
+static void
p_end_xml_element (GMarkupParseContext *context,
const gchar *element_name,
GapMovXmlUserData *userDataPtr,
@@ -1109,7 +1120,7 @@ p_end_xml_element (GMarkupParseContext *context,
if(userDataPtr->isScopeValid)
{
gint jj;
-
+
for(jj=0; jmpTableElement[jj].name != NULL; jj++)
{
if(strcmp(jmpTableElement[jj].name, element_name) == 0)
@@ -1117,9 +1128,9 @@ p_end_xml_element (GMarkupParseContext *context,
jmpTableElement[jj].count++;
}
}
-
+
}
-
+
} /* end p_end_xml_element */
@@ -1140,20 +1151,20 @@ p_end_xml_element (GMarkupParseContext *context,
static gint
p_transform_path_coordinate(gint value, gint32 recordedSize, gint32 actualSize)
{
-
+
if((recordedSize != 0) && (actualSize != recordedSize))
{
gdouble newValue;
gint newIntValue;
-
+
newValue = ((gdouble)value * (gdouble)actualSize) / (gdouble)recordedSize;
newIntValue = rint(newValue);
-
+
return (newIntValue);
}
return(value);
-
+
}
@@ -1167,7 +1178,7 @@ p_copy_transformed_values(GapMovValues *dstValues, GapMovValues *srcValues
, gint32 actualFrameWidth, gint32 actualFrameHeight)
{
gint ii;
-
+
dstValues->version = srcValues->version;
dstValues->rotate_threshold = srcValues->rotate_threshold;
dstValues->recordedFrameWidth = srcValues->recordedFrameWidth;
@@ -1188,6 +1199,25 @@ p_copy_transformed_values(GapMovValues *dstValues, GapMovValues *srcValues
dstValues->src_selmode = srcValues->src_selmode;
dstValues->src_paintmode = srcValues->src_paintmode;
dstValues->dst_layerstack = srcValues->dst_layerstack;
+ if(dstValues->dst_group_name_path_string != NULL)
+ {
+ g_free(dstValues->dst_group_name_path_string);
+ dstValues->dst_group_name_path_string = NULL;
+ }
+ if(srcValues->dst_group_name_path_string != NULL)
+ {
+ dstValues->dst_group_name_path_string = g_strdup(srcValues->dst_group_name_path_string);
+ }
+
+ if(dstValues->dst_group_name_delimiter != NULL)
+ {
+ g_free(dstValues->dst_group_name_delimiter);
+ dstValues->dst_group_name_delimiter = NULL;
+ }
+ if(srcValues->dst_group_name_delimiter != NULL)
+ {
+ dstValues->dst_group_name_delimiter = g_strdup(srcValues->dst_group_name_delimiter);
+ }
dstValues->step_speed_factor = srcValues->step_speed_factor;
dstValues->src_force_visible = srcValues->src_force_visible;
dstValues->clip_to_img = srcValues->clip_to_img;
@@ -1214,8 +1244,8 @@ p_copy_transformed_values(GapMovValues *dstValues, GapMovValues *srcValues
dstValues->bbp = g_new(GapBlueboxGlobalParams, 1);
memcpy(dstValues->bbp, srcValues->bbp, sizeof(GapBlueboxGlobalParams));
}
-
-
+
+
dstValues->point_idx = srcValues->point_idx;
dstValues->point_idx_max = srcValues->point_idx_max;
@@ -1223,7 +1253,7 @@ p_copy_transformed_values(GapMovValues *dstValues, GapMovValues *srcValues
for(ii=0; ii <= srcValues->point_idx_max; ii++)
{
memcpy(&dstValues->point[ii], &srcValues->point[ii], sizeof(GapMovPoint));
-
+
dstValues->point[ii].p_x = p_transform_path_coordinate(srcValues->point[ii].p_x
, srcValues->recordedFrameWidth
, actualFrameWidth
@@ -1232,7 +1262,7 @@ p_copy_transformed_values(GapMovValues *dstValues, GapMovValues *srcValues
, srcValues->recordedFrameHeight
, actualFrameHeight
);
-
+
}
} /* end p_copy_transformed_values */
@@ -1255,28 +1285,28 @@ p_error_handler(GMarkupParseContext *context,
,(int)error->code
,error->message
);
-
+
}
-
+
if(context != NULL)
{
gint line_number;
gint char_number;
-
+
g_markup_parse_context_get_position (context, &line_number, &char_number);
-
+
printf("context: line_number:%d char_number:%d element:%s\n"
,(int)line_number
,(int)char_number
,g_markup_parse_context_get_element(context)
);
}
-
+
if(user_data != NULL)
{
GapMovXmlUserData *userDataPtr;
userDataPtr = user_data;
-
+
printf("userDataPtr: isParseOk:%d isScopeValid:%d errorLineNumber:%d\n"
,(int)userDataPtr->isParseOk
,(int)userDataPtr->isScopeValid
@@ -1294,7 +1324,7 @@ p_error_handler(GMarkupParseContext *context,
* (use actualFrameWidth and actualFrameHeight value 0 in case no transformation
* is desired)
*/
-gboolean
+gboolean
gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
,gint32 actualFrameWidth, gint32 actualFrameHeight)
{
@@ -1316,7 +1346,7 @@ gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
GapMovValues *tmpValues;
GapMovXmlUserData *userDataPtr;
GError *gError;
-
+
isOk = TRUE;
gError = NULL;
tmpValues = gap_mov_exec_new_GapMovValues();
@@ -1325,17 +1355,17 @@ gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
userDataPtr = g_new(GapMovXmlUserData, 1);
userDataPtr->pvals = tmpValues;
- ///p_init_default_values(tmpValues); /// (?) TODO
-
+ ///p_init_default_values(tmpValues); /// (?) TODO
+
userDataPtr->isScopeValid = FALSE;
userDataPtr->isParseOk = TRUE;
userDataPtr->errorLineNumber = 0;
-
+
for(jj=0; jmpTableElement[jj].name != NULL; jj++)
{
jmpTableElement[jj].count = 0;
}
-
+
GMarkupParseContext *context = g_markup_parse_context_new (
&parserFuctions /* GMarkupParser */
, 0 /* GMarkupParseFlags flags */
@@ -1343,21 +1373,21 @@ gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
, NULL /* GDestroyNotify user_data_dnotify */
);
- if (g_file_get_contents (filename, &textBuffer, &lengthTextBuffer, NULL) != TRUE)
+ if (g_file_get_contents (filename, &textBuffer, &lengthTextBuffer, NULL) != TRUE)
{
printf("Couldn't load XML file:%s\n", filename);
return(FALSE);
}
-
+
if (g_markup_parse_context_parse (context, textBuffer, lengthTextBuffer, &gError) != TRUE)
{
printf("Parse failed of file: %s\n", filename);
p_error_handler(context, gError, userDataPtr);
-
+
return(FALSE);
}
-
+
/* check for mandatory elements */
if(userDataPtr->isParseOk)
{
@@ -1375,19 +1405,19 @@ gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
}
}
}
-
+
}
if(userDataPtr->isParseOk)
{
/* copy loaded values and transform coordinates from recorded frame size
- * to actual frame size
+ * to actual frame size
*/
p_copy_transformed_values(productiveValues, tmpValues, actualFrameWidth, actualFrameHeight);
- }
-
+ }
+
isOk = userDataPtr->isParseOk;
-
+
g_free(textBuffer);
g_markup_parse_context_free (context);
@@ -1402,8 +1432,8 @@ gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
g_free(tmpValues);
g_free(userDataPtr);
-
-
+
+
return (isOk);
} /* end gap_mov_xml_par_load */
@@ -1412,7 +1442,7 @@ gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
-/*
+/*
* XML WRITER procedure
*/
@@ -1438,20 +1468,20 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gboolean writeRotateValues;
gboolean writeOpacityValues;
gboolean writeFeatherRadiusValues;
-
+
fprintf(l_fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
-
+
/* root */
fprintf(l_fp, "<%s ", GAP_MOVPATH_XML_TOKEN_ROOT);
gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_VERSION, pvals->version);
fprintf(l_fp, ">\n");
-
+
/* attributes for description of the processed frames */
{
gint32 total_frames;
-
+
total_frames = 1 + abs(pvals->dst_range_end - pvals->dst_range_start);
-
+
fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_FRAME_DESCRIPTION);
gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_WIDTH, gimp_image_width(pvals->dst_image_id));
gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_HEIGHT, gimp_image_height(pvals->dst_image_id));
@@ -1460,8 +1490,8 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_TOTAL_FRAMES, total_frames);
fprintf(l_fp, "/>\n");
}
-
-
+
+
/* attributes for tween processing */
fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_TWEEN);
gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_TWEEN_STEPS, pvals->tween_steps);
@@ -1471,7 +1501,7 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_DESC, pvals->tween_opacity_desc,
1, 3);
}
fprintf(l_fp, "/>\n");
-
+
/* attributes for trace layer generation */
isTraceLayerEnabled = (pvals->tracelayer_enable != 0);
fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_TRACE);
@@ -1482,12 +1512,12 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_DESC, pvals->trace_opacity_desc,
1, 3);
}
fprintf(l_fp, "/>\n");
-
+
/* attributes of the moving_object */
{
char *src_filename;
gint32 src_image_id;
-
+
src_image_id = gimp_drawable_get_image(pvals->src_layer_id);
fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_MOVING_OBJECT);
@@ -1513,11 +1543,13 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gap_xml_write_EnumValue(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_PAINTMODE, pvals->src_paintmode,
&valuesGimpPaintmode[0]);
fprintf(l_fp, "\n ");
gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_DST_LAYERSTACK, pvals->dst_layerstack);
+ gap_xml_write_string_value(l_fp, GAP_MOVPATH_XML_TOKEN_DST_GROUP_PATH,
pvals->dst_group_name_path_string);
+ gap_xml_write_string_value(l_fp, GAP_MOVPATH_XML_TOKEN_DST_GROUP_DELIM,
pvals->dst_group_name_delimiter);
gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_FORCE_VISIBLE,
pvals->src_force_visible);
gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_CLIP_TO_IMG, pvals->clip_to_img);
gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_APPLY_BLUEBOX,
pvals->src_apply_bluebox);
fprintf(l_fp, "\n");
-
+
/* attributes for applying bluebox transparency processing */
if((pvals->src_apply_bluebox) && (pvals->bbp != NULL))
{
@@ -1546,13 +1578,13 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_R, pvals->bbp->vals.keycolor.r, 1,
3);
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_G, pvals->bbp->vals.keycolor.g, 1,
3);
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_B, pvals->bbp->vals.keycolor.b, 1,
3);
-
+
fprintf(l_fp, "\n");
fprintf(l_fp, " >\n");
fprintf(l_fp, " </%s>\n", GAP_MOVPATH_XML_TOKEN_BLUEBOX_PARAMETERS);
-
+
}
-
+
fprintf(l_fp, " >\n");
fprintf(l_fp, " </%s>\n", GAP_MOVPATH_XML_TOKEN_MOVING_OBJECT);
}
@@ -1567,7 +1599,7 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_ROTATE_THRESHOLD, pvals->rotate_threshold, 1, 7);
fprintf(l_fp, " >\n");
- /* check for conditonal write
+ /* check for conditonal write
* (to keep files smaller and more readable we skip writing of some information
* that is equal to the default value in all controlpoints)
*/
@@ -1582,22 +1614,22 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
{
writeResizeValues = TRUE;
}
-
+
if(pvals->point[l_idx].opacity != 100.0)
{
writeOpacityValues = TRUE;
}
-
+
if(pvals->point[l_idx].rotation != 0.0)
{
writeRotateValues = TRUE;
}
-
+
if(pvals->point[l_idx].sel_feather_radius != 0.0)
{
writeFeatherRadiusValues = TRUE;
}
-
+
}
/* write controlpoints loop */
@@ -1607,13 +1639,13 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
gdouble py;
gboolean writeAccelerationCharacteristics;
gboolean keyframeInNewLine;
-
+
keyframeInNewLine = FALSE;
px = pvals->point[l_idx].p_x;
py = pvals->point[l_idx].p_y;
-
+
/* write basic attributes of the controlpoint */
-
+
fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_CONTROLPOINT);
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_PX, px, 5, 0);
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_PY, py, 5, 0);
@@ -1634,7 +1666,7 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
{
gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_SEL_FEATHER_RADIUS,
pvals->point[l_idx].sel_feather_radius, 3, 1);
}
-
+
/* conditional write perspective transformation (only if there is any) */
if(pvals->point[l_idx].ttlx != 1.0
|| pvals->point[l_idx].ttly != 1.0
@@ -1670,7 +1702,7 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
|| (pvals->point[l_idx].accPerspective != 0)
|| (pvals->point[l_idx].accSelFeatherRadius != 0))
{
- if (l_idx == 0)
+ if (l_idx == 0)
{
writeAccelerationCharacteristics = TRUE;
}
@@ -1682,9 +1714,9 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
writeAccelerationCharacteristics = TRUE;
}
}
-
+
}
-
+
if (writeAccelerationCharacteristics == TRUE)
{
keyframeInNewLine = TRUE;
@@ -1707,30 +1739,30 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
,gap_mov_exec_conv_keyframe_to_rel(pvals->point[l_idx].keyframe_abs, pvals)
);
}
-
+
/* check for writing keyframe
* (the implicite keyframes at first and last controlpoints are not written to file)
*/
if((l_idx > 0)
&& (l_idx < pvals->point_idx_max)
&& ((int)pvals->point[l_idx].keyframe_abs > 0))
- {
+ {
if(keyframeInNewLine == TRUE)
{
fprintf(l_fp, "\n ");
}
- gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYFRAME_ABS,
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYFRAME_ABS,
pvals->point[l_idx].keyframe_abs);
-
+
}
fprintf(l_fp, "/>\n"); /* end of GAP_MOVPATH_XML_TOKEN_CONTROLPOINT */
-
- }
-
+
+ }
+
fprintf(l_fp, " </%s>\n", GAP_MOVPATH_XML_TOKEN_CONTROLPOINTS);
fprintf(l_fp, "</%s>", GAP_MOVPATH_XML_TOKEN_ROOT);
-
+
fclose(l_fp);
return 0;
}
diff --git a/gap/gap_xml_util.c b/gap/gap_xml_util.c
index 6f4b83a..83b8a80 100644
--- a/gap/gap_xml_util.c
+++ b/gap/gap_xml_util.c
@@ -188,9 +188,32 @@ const GEnumValue *enumValuesTable)
} /* end gap_xml_parse_EnumValue_as_gint */
+/* --------------------------------------
+ * gap_xml_parse_value_utf8_string
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_value_utf8_string(const gchar *attribute_value, gchar **valDestPtr)
+{
+ if(*valDestPtr != NULL)
+ {
+ g_free(*valDestPtr);
+ *valDestPtr = NULL;
+ }
+ if(attribute_value != NULL)
+ {
+ gboolean utf8_compliant;
-
-
+ utf8_compliant = g_utf8_validate(attribute_value, -1, NULL);
+ if(utf8_compliant)
+ {
+ *valDestPtr = g_strdup(attribute_value);
+ return (TRUE);
+ }
+
+ }
+ return (FALSE);
+}
diff --git a/gap/gap_xml_util.h b/gap/gap_xml_util.h
index 5ffa4a9..f7410ea 100644
--- a/gap/gap_xml_util.h
+++ b/gap/gap_xml_util.h
@@ -41,8 +41,8 @@ gboolean gap_xml_parse_value_gint32(const gchar *attribute_value, gint32 *val
gboolean gap_xml_parse_value_gint(const gchar *attribute_value, gint *valDestPtr);
gboolean gap_xml_parse_value_gboolean(const gchar *attribute_value, gboolean *valDestPtr);
gboolean gap_xml_parse_value_gboolean_as_gint(const gchar *attribute_value, gint *valDestPtr);
-gboolean gap_xml_parse_EnumValue_as_gint(const gchar *attribute_value, gint
-*valDestPtr, const GEnumValue *enumValuesTable);
+gboolean gap_xml_parse_EnumValue_as_gint(const gchar *attribute_value, gint *valDestPtr, const GEnumValue
*enumValuesTable);
+gboolean gap_xml_parse_value_utf8_string(const gchar *attribute_value, gchar **valDestPtr);
void gap_xml_write_gboolean_value(FILE *fp, const char *name, gboolean value);
void gap_xml_write_gint_as_gboolean_value(FILE *fp, const char *name, gint value);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]