[gimp/wip/animation: 66/197] plug-ins: serialization for cel animations.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 66/197] plug-ins: serialization for cel animations.
- Date: Sat, 7 Oct 2017 03:03:57 +0000 (UTC)
commit ac3a7d1910aa9c9c59adac256ec75117537b1a4f
Author: Jehan <jehan girinstud io>
Date: Sun Aug 7 02:16:45 2016 +0200
plug-ins: serialization for cel animations.
.../animation-play/core/animation-celanimation.c | 621 ++++++++++++++++++--
.../animation-play/core/animation-celanimation.h | 4 +
plug-ins/animation-play/core/animation.c | 30 +-
plug-ins/animation-play/core/animationanimatic.c | 12 +-
plug-ins/animation-play/widgets/animation-dialog.c | 28 +-
5 files changed, 621 insertions(+), 74 deletions(-)
---
diff --git a/plug-ins/animation-play/core/animation-celanimation.c
b/plug-ins/animation-play/core/animation-celanimation.c
index 7b3dd58..8457a2a 100644
--- a/plug-ins/animation-play/core/animation-celanimation.c
+++ b/plug-ins/animation-play/core/animation-celanimation.c
@@ -68,31 +68,78 @@ struct _AnimationCelAnimationPrivate
GList *tracks;
};
+typedef enum
+{
+ START_STATE,
+ ANIMATION_STATE,
+ SEQUENCE_STATE,
+ FRAME_STATE,
+ LAYER_STATE,
+ COMMENTS_STATE,
+ COMMENT_STATE,
+ END_STATE
+} AnimationParseState;
+
+typedef struct
+{
+ Animation *animation;
+ AnimationParseState state;
+
+ Track *track;
+ gint frame_position;
+ gint frame_duration;
+} ParseStatus;
+
#define GET_PRIVATE(animation) \
G_TYPE_INSTANCE_GET_PRIVATE (animation, \
ANIMATION_TYPE_CEL_ANIMATION, \
AnimationCelAnimationPrivate)
-static void animation_cel_animation_finalize (GObject *object);
+static void animation_cel_animation_finalize (GObject *object);
/* Virtual methods */
-static gint animation_cel_animation_get_length (Animation *animation);
-
-static void animation_cel_animation_load (Animation *animation);
-static GeglBuffer * animation_cel_animation_get_frame (Animation *animation,
- gint pos);
-static gboolean animation_cel_animation_same (Animation *animation,
- gint previous_pos,
- gint next_pos);
+static gint animation_cel_animation_get_length (Animation *animation);
+
+static void animation_cel_animation_load (Animation *animation);
+static void animation_cel_animation_load_xml (Animation *animation,
+ const gchar *xml);
+static GeglBuffer * animation_cel_animation_get_frame (Animation *animation,
+ gint pos);
+static gchar * animation_cel_animation_serialize (Animation *animation);
+
+static gboolean animation_cel_animation_same (Animation *animation,
+ gint previous_pos,
+ gint next_pos);
+
+/* XML parsing */
+
+static void animation_cel_animation_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+static void animation_cel_animation_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
+
+static void animation_cel_animation_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
/* Utils */
-static void animation_cel_animation_cleanup (AnimationCelAnimation *animation);
-static void animation_cel_animation_cache (AnimationCelAnimation *animation,
- gint position);
-static gboolean animation_cel_animation_cache_cmp (Cache *cache1,
- Cache *cache2);
+static void animation_cel_animation_cleanup (AnimationCelAnimation *animation);
+static void animation_cel_animation_cache (AnimationCelAnimation *animation,
+ gint position);
+static gboolean animation_cel_animation_cache_cmp (Cache *cache1,
+ Cache *cache2);
+static void animation_cel_animation_clean_cache (Cache *cache);
+static void animation_cel_animation_clean_track (Track *track);
G_DEFINE_TYPE (AnimationCelAnimation, animation_cel_animation, ANIMATION_TYPE_ANIMATION)
@@ -108,7 +155,9 @@ animation_cel_animation_class_init (AnimationCelAnimationClass *klass)
anim_class->get_length = animation_cel_animation_get_length;
anim_class->load = animation_cel_animation_load;
+ anim_class->load_xml = animation_cel_animation_load_xml;
anim_class->get_frame = animation_cel_animation_get_frame;
+ anim_class->serialize = animation_cel_animation_serialize;
anim_class->same = animation_cel_animation_same;
g_type_class_add_private (klass, sizeof (AnimationCelAnimationPrivate));
@@ -125,6 +174,9 @@ animation_cel_animation_init (AnimationCelAnimation *animation)
static void
animation_cel_animation_finalize (GObject *object)
{
+ /* Save first, before cleaning anything. */
+ animation_save_to_parasite (ANIMATION (object));
+
animation_cel_animation_cleanup (ANIMATION_CEL_ANIMATION (object));
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -143,7 +195,7 @@ animation_cel_animation_set_comment (AnimationCelAnimation *animation,
position <= animation->priv->duration);
item = g_list_nth (animation->priv->comments, position - 1);
- if (item->data)
+ if (item && item->data)
{
g_free (item->data);
}
@@ -162,6 +214,57 @@ animation_cel_animation_get_comment (AnimationCelAnimation *animation,
return g_list_nth_data (animation->priv->comments, position - 1);
}
+void
+animation_cel_animation_set_duration (AnimationCelAnimation *animation,
+ gint duration)
+{
+ if (duration < animation->priv->duration)
+ {
+ GList *iter;
+
+ /* Free memory. */
+ iter = g_list_nth (animation->priv->cache, duration);
+ if (iter && iter->prev)
+ {
+ iter->prev->next = NULL;
+ iter->prev = NULL;
+ }
+ g_list_free_full (iter, (GDestroyNotify) animation_cel_animation_clean_cache);
+
+ iter = g_list_nth (animation->priv->tracks, duration);
+ if (iter && iter->prev)
+ {
+ iter->prev->next = NULL;
+ iter->prev = NULL;
+ }
+ g_list_free_full (iter, (GDestroyNotify) animation_cel_animation_clean_track);
+
+ iter = g_list_nth (animation->priv->comments, duration);
+ if (iter && iter->prev)
+ {
+ iter->prev->next = NULL;
+ iter->prev = NULL;
+ }
+ g_list_free_full (iter, (GDestroyNotify) g_free);
+
+ for (iter = animation->priv->tracks; iter; iter = iter->next)
+ {
+ Track *track = iter->data;
+ GList *iter2;
+
+ iter2 = g_list_nth (track->frames, duration);
+ if (iter2 && iter2->prev)
+ {
+ iter2->prev->next = NULL;
+ iter2->prev = NULL;
+ }
+ g_list_free (iter2);
+ }
+ }
+
+ animation->priv->duration = duration;
+}
+
/**** Virtual methods ****/
static gint
@@ -224,6 +327,65 @@ animation_cel_animation_load (Animation *animation)
}
}
+static void
+animation_cel_animation_load_xml (Animation *animation,
+ const gchar *xml)
+{
+ const GMarkupParser markup_parser =
+ {
+ animation_cel_animation_start_element,
+ animation_cel_animation_end_element,
+ animation_cel_animation_text,
+ NULL, /* passthrough */
+ NULL /* error */
+ };
+ GMarkupParseContext *context;
+ ParseStatus status = { 0, };
+ GError *error = NULL;
+
+ g_return_if_fail (xml != NULL);
+
+ /* Parse XML to update. */
+ status.state = START_STATE;
+ status.animation = animation;
+
+ context = g_markup_parse_context_new (&markup_parser,
+ 0, &status, NULL);
+ g_markup_parse_context_parse (context, xml, strlen (xml), &error);
+ if (error)
+ {
+ g_warning ("Error parsing XML: %s", error->message);
+ }
+ else
+ {
+ g_markup_parse_context_end_parse (context, &error);
+ if (error)
+ g_warning ("Error parsing XML: %s", error->message);
+ }
+ g_markup_parse_context_free (context);
+
+ /* If XML parsing failed, just reset the animation. */
+ if (error)
+ {
+ animation_cel_animation_load (animation);
+ }
+ else
+ {
+ /* cache. */
+ gint i;
+ gint duration = animation_get_length (animation);
+
+ for (i = 0; i < duration; i++)
+ {
+ g_signal_emit_by_name (animation, "loading",
+ (gdouble) i / ((gdouble) duration - 0.999));
+
+ /* Panel image. */
+ animation_cel_animation_cache (ANIMATION_CEL_ANIMATION (animation), i);
+ }
+ }
+}
+
static GeglBuffer *
animation_cel_animation_get_frame (Animation *animation,
gint pos)
@@ -243,6 +405,94 @@ animation_cel_animation_get_frame (Animation *animation,
return frame;
}
+static gchar *
+animation_cel_animation_serialize (Animation *animation)
+{
+ AnimationCelAnimationPrivate *priv;
+ gchar *xml;
+ gchar *xml2;
+ gchar *tmp;
+ GList *iter;
+ gint i;
+
+ priv = ANIMATION_CEL_ANIMATION (animation)->priv;
+
+ xml = g_strdup_printf ("<animation type=\"cels\" framerate=\"%f\" "
+ " duration=\"%d\" width=\"\" height=\"\">",
+ animation_get_framerate (animation),
+ priv->duration);
+
+ for (iter = priv->tracks; iter; iter = iter->next)
+ {
+ Track *track = iter->data;
+ GList *iter2;
+ gint pos;
+ gint duration;
+
+ xml2 = g_markup_printf_escaped ("<sequence name=\"%s\">",
+ track->title);
+ tmp = xml;
+ xml = g_strconcat (xml, xml2, NULL);
+ g_free (tmp);
+ g_free (xml2);
+
+ pos = 1;
+ duration = 0;
+ for (iter2 = track->frames; iter2; iter2 = iter2->next)
+ {
+ if (GPOINTER_TO_INT (iter2->data))
+ {
+ duration++;
+ if (! iter2->next || iter2->next->data != iter2->data)
+ {
+ xml2 = g_markup_printf_escaped ("<frame position=\"%d\""
+ " duration=\"%d\">"
+ "<layer id=\"%d\"/>"
+ "</frame>",
+ pos - duration, duration,
+ GPOINTER_TO_INT (iter2->data));
+ tmp = xml;
+ xml = g_strconcat (xml, xml2, NULL);
+ g_free (tmp);
+ g_free (xml2);
+ }
+ }
+ pos++;
+ }
+
+ tmp = xml;
+ xml = g_strconcat (xml, "</sequence>", NULL);
+ g_free (tmp);
+ }
+
+ tmp = xml;
+ xml = g_strconcat (xml, "<comments title=\"\">", NULL);
+ g_free (tmp);
+
+ /* New loop for comments. */
+ for (iter = priv->comments, i = 0; iter; iter = iter->next, i++)
+ {
+ if (iter->data)
+ {
+ gchar *comment = iter->data;
+
+ /* Comments are for a given panel, not for a frame position. */
+ xml2 = g_markup_printf_escaped ("<comment frame-position=\"%d\">%s</comment>",
+ i + 1,
+ comment);
+ tmp = xml;
+ xml = g_strconcat (xml, xml2, NULL);
+ g_free (tmp);
+ g_free (xml2);
+ }
+ }
+ tmp = xml;
+ xml = g_strconcat (xml, "</comments></animation>", NULL);
+ g_free (tmp);
+
+ return xml;
+}
+
static gboolean
animation_cel_animation_same (Animation *animation,
gint pos1,
@@ -254,10 +504,10 @@ animation_cel_animation_same (Animation *animation,
cel_animation = ANIMATION_CEL_ANIMATION (animation);
- g_return_val_if_fail (pos1 > 0 &&
- pos1 <= cel_animation->priv->duration &&
- pos2 > 0 &&
- pos2 <= cel_animation->priv->duration,
+ g_return_val_if_fail (pos1 >= 0 &&
+ pos1 < cel_animation->priv->duration &&
+ pos2 >= 0 &&
+ pos2 < cel_animation->priv->duration,
FALSE);
cache1 = g_list_nth_data (cel_animation->priv->cache,
@@ -268,59 +518,305 @@ animation_cel_animation_same (Animation *animation,
return animation_cel_animation_cache_cmp (cache1, cache2);
}
-/**** Utils ****/
-
static void
-animation_cel_animation_cleanup (AnimationCelAnimation *animation)
+animation_cel_animation_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
{
- AnimationCelAnimationPrivate *priv;
- GList *iter;
-
- priv = ANIMATION_CEL_ANIMATION (animation)->priv;
+ const gchar **names = attribute_names;
+ const gchar **values = attribute_values;
+ ParseStatus *status = (ParseStatus *) user_data;
+ AnimationCelAnimation *animation = ANIMATION_CEL_ANIMATION (status->animation);
+ AnimationCelAnimationPrivate *priv = GET_PRIVATE (status->animation);
- if (priv->cache)
+ switch (status->state)
{
- for (iter = priv->cache; iter; iter = iter->next)
+ case START_STATE:
+ if (g_strcmp0 (element_name, "animation") != 0)
{
- if (iter->data)
+ g_set_error (error, 0, 0,
+ _("Tag <animation> expected. "
+ "Got \"%s\" instead."),
+ element_name);
+ return;
+ }
+ while (*names && *values)
+ {
+ if (strcmp (*names, "type") == 0)
{
- Cache *cache = iter->data;
+ if (! **values || strcmp (*values, "cels") != 0)
+ {
+ g_set_error (error, 0, 0,
+ _("Unknown animation type: \"%s\"."),
+ *values);
+ return;
+ }
+ }
+ else if (strcmp (*names, "framerate") == 0 && **values)
+ {
+ gdouble fps = g_strtod (*values, NULL);
+ if (fps >= MAX_FRAMERATE)
+ {
+ /* Let's avoid huge frame rates. */
+ fps = MAX_FRAMERATE;
+ }
+ else if (fps <= 0)
+ {
+ /* Null or negative framerates are impossible. */
+ fps = DEFAULT_FRAMERATE;
+ }
+ animation_set_framerate (status->animation, fps);
+ }
+ else if (strcmp (*names, "duration") == 0 && **values)
+ {
+ gint duration = (gint) g_ascii_strtoull (*values, NULL, 10);
+
+ animation_cel_animation_set_duration (animation, duration);
+ }
- if (--(cache->refs) == 0)
+ names++;
+ values++;
+ }
+ status->state = ANIMATION_STATE;
+ break;
+ case ANIMATION_STATE:
+ if (g_strcmp0 (element_name, "sequence") == 0)
+ {
+ status->track = g_new0 (Track, 1);
+ while (*names && *values)
+ {
+ if (strcmp (*names, "name") == 0)
{
- g_object_unref (cache->buffer);
- g_free (cache->composition);
+ status->track->title = g_strdup (*values);
}
+ names++;
+ values++;
}
+ priv->tracks = g_list_prepend (priv->tracks, status->track);
+ status->state = SEQUENCE_STATE;
}
- g_list_free (priv->cache);
- }
- if (priv->comments)
- {
- for (iter = priv->comments; iter; iter = iter->next)
+ else if (g_strcmp0 (element_name, "comments") == 0)
{
- if (iter->data)
+ status->state = COMMENTS_STATE;
+ }
+ else
+ {
+ g_set_error (error, 0, 0,
+ _("Tags <sequence> or <comments> expected. "
+ "Got \"%s\" instead."),
+ element_name);
+ return;
+ }
+ break;
+ case SEQUENCE_STATE:
+ if (g_strcmp0 (element_name, "frame") != 0)
+ {
+ g_set_error (error, 0, 0,
+ _("Tag <frame> expected. "
+ "Got \"%s\" instead."),
+ element_name);
+ return;
+ }
+ status->frame_position = -1;
+ status->frame_duration = -1;
+
+ while (*names && *values)
+ {
+ if (strcmp (*names, "position") == 0 && **values)
{
- g_free (iter->data);
+ gint position = g_ascii_strtoll (*values, NULL, 10);
+
+ if (position >= 0)
+ status->frame_position = position;
}
+ else if (strcmp (*names, "duration") == 0 && **values)
+ {
+ gint duration = g_ascii_strtoll (*values, NULL, 10);
+
+ if (duration > 0)
+ status->frame_duration = duration;
+ }
+
+ names++;
+ values++;
}
- g_list_free (priv->comments);
- }
- if (priv->tracks)
- {
- for (iter = priv->tracks; iter; iter = iter->next)
+ if (status->frame_position == -1 ||
+ status->frame_duration == -1)
{
- Track *track = iter->data;
+ g_set_error (error, 0, 0,
+ _("Tag <frame> expects the properties: "
+ "position, duration."));
+ }
+ status->state = FRAME_STATE;
+ break;
+ case FRAME_STATE:
+ if (g_strcmp0 (element_name, "layer") != 0)
+ {
+ g_set_error (error, 0, 0,
+ _("Tag <layer> expected. "
+ "Got \"%s\" instead."),
+ element_name);
+ return;
+ }
+ while (*names && *values)
+ {
+ if (strcmp (*names, "id") == 0 && **values)
+ {
+ GList *iter;
+ gint tattoo = g_ascii_strtoll (*values, NULL, 10);
+ gint track_length;
+ gint i;
+
+ track_length = g_list_length (status->track->frames);
- /* The item's data must always exist. */
- g_free (track->title);
- g_list_free (track->frames);
+ if (track_length < status->frame_position + status->frame_duration)
+ {
+ /* Make sure the list is long enough. */
+ for (i = track_length; i < status->frame_position + status->frame_duration; i++)
+ {
+ status->track->frames = g_list_prepend (status->track->frames,
+ NULL);
+ }
+ }
+ iter = status->track->frames;
+ for (i = 0; i < status->frame_position + status->frame_duration; i++)
+ {
+ if (i >= status->frame_position)
+ {
+ iter->data = GINT_TO_POINTER (tattoo);
+ }
+ iter = iter->next;
+ }
+ }
+
+ names++;
+ values++;
+ }
+ status->state = LAYER_STATE;
+ break;
+ case LAYER_STATE:
+ /* <layer> should have no child tag. */
+ g_set_error (error, 0, 0,
+ _("Unexpected child of <layer>: \"%s\"."),
+ element_name);
+ return;
+ case COMMENTS_STATE:
+ if (g_strcmp0 (element_name, "comment") != 0)
+ {
+ g_set_error (error, 0, 0,
+ _("Tag <comment> expected. "
+ "Got \"%s\" instead."),
+ element_name);
+ return;
+ }
+ status->frame_position = -1;
+ status->frame_duration = -1;
+
+ while (*names && *values)
+ {
+ if (strcmp (*names, "position") == 0 && **values)
+ {
+ gint position = (gint) g_ascii_strtoll (*values, NULL, 10);
+
+ status->frame_position = position;
+ break;
+ }
+
+ names++;
+ values++;
}
- g_list_free (priv->tracks);
+ status->state = COMMENT_STATE;
+ break;
+ case COMMENT_STATE:
+ /* <comment> should have no child tag. */
+ g_set_error (error, 0, 0,
+ _("Unexpected child of <comment>: <\"%s\">."),
+ element_name);
+ return;
+ default:
+ g_set_error (error, 0, 0,
+ _("Unknown state!"));
+ break;
+ }
+}
+
+static void
+animation_cel_animation_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ ParseStatus *status = (ParseStatus *) user_data;
+
+ switch (status->state)
+ {
+ case SEQUENCE_STATE:
+ case COMMENTS_STATE:
+ status->state = ANIMATION_STATE;
+ break;
+ case FRAME_STATE:
+ status->state = SEQUENCE_STATE;
+ break;
+ case LAYER_STATE:
+ status->state = FRAME_STATE;
+ break;
+ case ANIMATION_STATE:
+ status->state = END_STATE;
+ break;
+ case COMMENT_STATE:
+ status->state = COMMENTS_STATE;
+ break;
+ default: /* START/END_STATE */
+ /* invalid XML. I expect the parser to raise an error anyway.*/
+ break;
+ }
+}
+
+static void
+animation_cel_animation_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ ParseStatus *status = (ParseStatus *) user_data;
+ AnimationCelAnimation *cel_animation = ANIMATION_CEL_ANIMATION (status->animation);
+
+ switch (status->state)
+ {
+ case COMMENT_STATE:
+ if (status->frame_position == -1)
+ /* invalid comment tag. */
+ break;
+ /* Setting comment to a panel. */
+ animation_cel_animation_set_comment (cel_animation,
+ status->frame_position,
+ text);
+ status->frame_position = -1;
+ break;
+ default:
+ /* Ignoring text everywhere else. */
+ break;
}
- priv->cache = NULL;
- priv->comments = NULL;
- priv->tracks = NULL;
+}
+
+/**** Utils ****/
+
+static void
+animation_cel_animation_cleanup (AnimationCelAnimation *animation)
+{
+ g_list_free_full (animation->priv->cache,
+ (GDestroyNotify) animation_cel_animation_clean_cache);
+ animation->priv->cache = NULL;
+ g_list_free_full (animation->priv->comments,
+ (GDestroyNotify) g_free);
+ animation->priv->comments = NULL;
+ g_list_free_full (animation->priv->tracks,
+ (GDestroyNotify) animation_cel_animation_clean_track);
+ animation->priv->tracks = NULL;
}
static void
@@ -491,3 +987,22 @@ animation_cel_animation_cache_cmp (Cache *cache1,
}
return identical;
}
+
+static void
+animation_cel_animation_clean_cache (Cache *cache)
+{
+ if (--(cache->refs) == 0)
+ {
+ g_object_unref (cache->buffer);
+ g_free (cache->composition);
+ g_free (cache);
+ }
+}
+
+static void
+animation_cel_animation_clean_track (Track *track)
+{
+ g_free (track->title);
+ g_list_free (track->frames);
+ g_free (track);
+}
diff --git a/plug-ins/animation-play/core/animation-celanimation.h
b/plug-ins/animation-play/core/animation-celanimation.h
index a33e403..3e30fc4 100644
--- a/plug-ins/animation-play/core/animation-celanimation.h
+++ b/plug-ins/animation-play/core/animation-celanimation.h
@@ -55,4 +55,8 @@ void animation_cel_animation_set_comment (AnimationCelAnimation *an
const gchar * animation_cel_animation_get_comment (AnimationCelAnimation *animation,
gint position);
+void animation_cel_animation_set_duration (AnimationCelAnimation *animation,
+ gint duration);
+
+
#endif /* __ANIMATION_CEL_ANIMATION_H__ */
diff --git a/plug-ins/animation-play/core/animation.c b/plug-ins/animation-play/core/animation.c
index 5ca9569..7b9b8eb 100644
--- a/plug-ins/animation-play/core/animation.c
+++ b/plug-ins/animation-play/core/animation.c
@@ -442,6 +442,7 @@ animation_save_to_parasite (Animation *animation)
AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
GimpParasite *old_parasite;
const gchar *parasite_name;
+ const gchar *selected;
gchar *xml;
gboolean undo_step_started = FALSE;
CachedSettings settings;
@@ -455,10 +456,12 @@ animation_save_to_parasite (Animation *animation)
if (ANIMATION_IS_ANIMATIC (animation))
{
+ selected = "animatic";
parasite_name = PLUG_IN_PROC "/animatic";
}
else /* ANIMATION_IS_CEL_ANIMATION */
{
+ selected = "cel-animation";
parasite_name = PLUG_IN_PROC "/cel-animation";
}
/* If there was already parasites and they were all the same as the
@@ -470,6 +473,7 @@ animation_save_to_parasite (Animation *animation)
g_strcmp0 ((gchar *) gimp_parasite_data (old_parasite), xml)))
{
GimpParasite *parasite;
+
if (! undo_step_started)
{
gimp_image_undo_group_start (priv->image_id);
@@ -483,6 +487,26 @@ animation_save_to_parasite (Animation *animation)
}
gimp_parasite_free (old_parasite);
+ old_parasite = gimp_image_get_parasite (priv->image_id,
+ PLUG_IN_PROC "/selected");
+ if (! old_parasite ||
+ g_strcmp0 ((gchar *) gimp_parasite_data (old_parasite), selected))
+ {
+ GimpParasite *parasite;
+
+ if (! undo_step_started)
+ {
+ gimp_image_undo_group_start (priv->image_id);
+ undo_step_started = TRUE;
+ }
+ parasite = gimp_parasite_new (PLUG_IN_PROC "/selected",
+ GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE,
+ strlen (selected) + 1, selected);
+ gimp_image_attach_parasite (priv->image_id, parasite);
+ gimp_parasite_free (parasite);
+ }
+ gimp_parasite_free (old_parasite);
+
if (undo_step_started)
{
gimp_image_undo_group_end (priv->image_id);
@@ -598,7 +622,7 @@ animation_play (Animation *animation)
}
void
-animation_stop (Animation *animation)
+animation_stop (Animation *animation)
{
AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
@@ -672,8 +696,8 @@ void
animation_jump (Animation *animation,
gint index)
{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- GeglBuffer *buffer = NULL;
+ AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
+ GeglBuffer *buffer = NULL;
gint prev_pos = priv->position;
gboolean identical;
diff --git a/plug-ins/animation-play/core/animationanimatic.c
b/plug-ins/animation-play/core/animationanimatic.c
index 356036f..84abb0d 100644
--- a/plug-ins/animation-play/core/animationanimatic.c
+++ b/plug-ins/animation-play/core/animationanimatic.c
@@ -93,8 +93,8 @@ static GeglBuffer * animation_animatic_get_frame (Animation *animation
static gchar * animation_animatic_serialize (Animation *animation);
static gboolean animation_animatic_same (Animation *animation,
- gint previous_pos,
- gint next_pos);
+ gint pos1,
+ gint pos2);
/* XML parsing */
@@ -598,8 +598,8 @@ animation_animatic_serialize (Animation *animation)
static gboolean
animation_animatic_same (Animation *animation,
- gint previous_pos,
- gint next_pos)
+ gint pos1,
+ gint pos2)
{
AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
gint count = 0;
@@ -609,12 +609,12 @@ animation_animatic_same (Animation *animation,
for (i = 0; i < priv->n_panels; i++)
{
count += priv->durations[i];
- if (count >= previous_pos && count >= next_pos)
+ if (count >= pos1 && count >= pos2)
{
identical = TRUE;
break;
}
- else if (count >= previous_pos || count >= next_pos)
+ else if (count >= pos1 || count >= pos2)
{
identical = FALSE;
break;
diff --git a/plug-ins/animation-play/widgets/animation-dialog.c
b/plug-ins/animation-play/widgets/animation-dialog.c
index 744c8c7..232d613 100755
--- a/plug-ins/animation-play/widgets/animation-dialog.c
+++ b/plug-ins/animation-play/widgets/animation-dialog.c
@@ -337,6 +337,7 @@ animation_dialog_new (gint32 image_id)
animatic_selected = FALSE;
}
gimp_parasite_free (parasite);
+ parasite = NULL;
}
if (animatic_selected)
@@ -1200,11 +1201,6 @@ animation_dialog_set_animation (AnimationDialog *dialog,
G_CALLBACK (zoomcombo_changed),
dialog);
- /* Animation type. */
- g_signal_handlers_unblock_by_func (priv->animation_type_combo,
- G_CALLBACK (animation_type_changed),
- dialog);
-
/* Progress bar. */
g_signal_handlers_unblock_by_func (priv->progress,
G_CALLBACK (progress_entered),
@@ -1223,12 +1219,12 @@ animation_dialog_set_animation (AnimationDialog *dialog,
if (right_pane)
gtk_widget_destroy (right_pane);
- /* The Storyboard view. */
if (ANIMATION_IS_ANIMATIC (animation))
{
GtkWidget *scrolled_win;
GtkWidget *frame;
+ /* The Storyboard view. */
frame = gtk_frame_new (_("Storyboard"));
gtk_paned_pack2 (GTK_PANED (priv->hpaned), frame,
TRUE, TRUE);
@@ -1243,8 +1239,21 @@ animation_dialog_set_animation (AnimationDialog *dialog,
right_pane);
gtk_widget_show (right_pane);
+
+ /* The animation type box. */
+ gtk_combo_box_set_active (GTK_COMBO_BOX (priv->animation_type_combo), 0);
+ }
+ else
+ {
+ /* The animation type box. */
+ gtk_combo_box_set_active (GTK_COMBO_BOX (priv->animation_type_combo), 1);
}
+ /* Animation type. */
+ g_signal_handlers_unblock_by_func (priv->animation_type_combo,
+ G_CALLBACK (animation_type_changed),
+ dialog);
+
/* Animation. */
g_signal_connect (priv->animation, "proxy",
G_CALLBACK (proxy_changed),
@@ -1364,7 +1373,7 @@ animation_type_changed (GtkWidget *combo,
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
Animation *animation;
- GimpParasite *parasite;
+ GimpParasite *parasite = NULL;
const gchar *xml = NULL;
gint index;
@@ -1378,11 +1387,6 @@ animation_type_changed (GtkWidget *combo,
{
parasite = gimp_image_get_parasite (priv->image_id,
PLUG_IN_PROC "/animatic");
- if (parasite)
- {
- xml = g_strdup (gimp_parasite_data (parasite));
- gimp_parasite_free (parasite);
- }
}
else
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]