[gimp/wip/animation: 126/197] plug-ins: save the current animation playback state.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 126/197] plug-ins: save the current animation playback state.
- Date: Sat, 7 Oct 2017 03:09:02 +0000 (UTC)
commit c295a9ca48a9f82bbe41bc2c02efc9f5ec78b641
Author: Jehan <jehan girinstud io>
Date: Wed Jan 18 02:26:22 2017 +0100
plug-ins: save the current animation playback state.
Current position, and start/stop loop frames are relevant to the
work-in-progress in current animation project.
This is a first version. I'm still wondering about the current relation
between Animation and AnimationPlayback and therefore code architecture.
plug-ins/animation-play/core/animation-animatic.c | 13 +-
.../animation-play/core/animation-celanimation.c | 22 ++-
plug-ins/animation-play/core/animation-playback.c | 157 +++++++++++++++++++-
plug-ins/animation-play/core/animation-playback.h | 4 +-
plug-ins/animation-play/core/animation.c | 16 ++-
plug-ins/animation-play/core/animation.h | 6 +-
plug-ins/animation-play/widgets/animation-dialog.c | 36 +++--
7 files changed, 216 insertions(+), 38 deletions(-)
---
diff --git a/plug-ins/animation-play/core/animation-animatic.c
b/plug-ins/animation-play/core/animation-animatic.c
index c91152b..2088980 100644
--- a/plug-ins/animation-play/core/animation-animatic.c
+++ b/plug-ins/animation-play/core/animation-animatic.c
@@ -95,7 +95,8 @@ static gboolean animation_animatic_same (Animation *animat
static void animation_animatic_purge_cache (Animation *animation);
static void animation_animatic_reset_defaults (Animation *animation);
-static gchar * animation_animatic_serialize (Animation *animation);
+static gchar * animation_animatic_serialize (Animation *animation,
+ const gchar *playback_xml);
static gboolean animation_animatic_deserialize (Animation *animation,
const gchar *xml,
GError **error);
@@ -196,9 +197,6 @@ animation_animatic_finalize (GObject *object)
AnimationAnimaticPrivate *priv = GET_PRIVATE (object);
gint i;
- /* Save first, before cleaning anything. */
- animation_save_to_parasite (ANIMATION (object));
-
if (priv->tattoos)
g_free (priv->tattoos);
if (priv->durations)
@@ -503,7 +501,8 @@ animation_animatic_reset_defaults (Animation *animation)
}
static gchar *
-animation_animatic_serialize (Animation *animation)
+animation_animatic_serialize (Animation *animation,
+ const gchar *playback_xml)
{
AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
gchar *text;
@@ -512,9 +511,9 @@ animation_animatic_serialize (Animation *animation)
text = g_strdup_printf ("<animation type=\"animatic\" framerate=\"%f\" "
" duration=\"%d\" width=\"\" height=\"\">"
- "<sequence>",
+ "%s<sequence>",
animation_get_framerate (animation),
- priv->n_panels);
+ priv->n_panels, playback_xml);
for (i = 0; i < priv->n_panels; i++)
{
gchar *panel;
diff --git a/plug-ins/animation-play/core/animation-celanimation.c
b/plug-ins/animation-play/core/animation-celanimation.c
index 419bb0a..0d0f55d 100644
--- a/plug-ins/animation-play/core/animation-celanimation.c
+++ b/plug-ins/animation-play/core/animation-celanimation.c
@@ -87,6 +87,7 @@ typedef enum
{
START_STATE,
ANIMATION_STATE,
+ PLAYBACK_STATE,
SEQUENCE_STATE,
FRAME_STATE,
LAYER_STATE,
@@ -126,7 +127,8 @@ static gboolean animation_cel_animation_same (Animation *a
static void animation_cel_animation_purge_cache (Animation *animation);
static void animation_cel_animation_reset_defaults (Animation *animation);
-static gchar * animation_cel_animation_serialize (Animation *animation);
+static gchar * animation_cel_animation_serialize (Animation *animation,
+ const gchar *playback_xml);
static gboolean animation_cel_animation_deserialize (Animation *animation,
const gchar *xml,
GError **error);
@@ -202,9 +204,6 @@ 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);
@@ -783,7 +782,8 @@ animation_cel_animation_reset_defaults (Animation *animation)
}
static gchar *
-animation_cel_animation_serialize (Animation *animation)
+animation_cel_animation_serialize (Animation *animation,
+ const gchar *playback_xml)
{
AnimationCelAnimationPrivate *priv;
gchar *xml;
@@ -795,9 +795,9 @@ animation_cel_animation_serialize (Animation *animation)
priv = ANIMATION_CEL_ANIMATION (animation)->priv;
xml = g_strdup_printf ("<animation type=\"cels\" framerate=\"%f\" "
- " duration=\"%d\" width=\"\" height=\"\">",
+ " duration=\"%d\" width=\"\" height=\"\">%s",
animation_get_framerate (animation),
- priv->duration);
+ priv->duration, playback_xml);
for (iter = priv->tracks; iter; iter = iter->next)
{
@@ -1041,6 +1041,10 @@ animation_cel_animation_start_element (GMarkupParseContext *context,
{
status->state = COMMENTS_STATE;
}
+ else if (g_strcmp0 (element_name, "playback") == 0)
+ {
+ status->state = PLAYBACK_STATE;
+ }
else
{
g_set_error (error, 0, 0,
@@ -1050,6 +1054,9 @@ animation_cel_animation_start_element (GMarkupParseContext *context,
return;
}
break;
+ case PLAYBACK_STATE:
+ /* Leave processing to the playback. */
+ break;
case SEQUENCE_STATE:
if (g_strcmp0 (element_name, "frame") != 0)
{
@@ -1200,6 +1207,7 @@ animation_cel_animation_end_element (GMarkupParseContext *context,
{
case SEQUENCE_STATE:
case COMMENTS_STATE:
+ case PLAYBACK_STATE:
status->state = ANIMATION_STATE;
break;
case FRAME_STATE:
diff --git a/plug-ins/animation-play/core/animation-playback.c
b/plug-ins/animation-play/core/animation-playback.c
index 04907d3..50ca135 100644
--- a/plug-ins/animation-play/core/animation-playback.c
+++ b/plug-ins/animation-play/core/animation-playback.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <libgimp/gimp.h>
+#include "libgimp/stdplugins-intl.h"
#include "animation.h"
#include "animation-playback.h"
@@ -59,6 +60,12 @@ struct _AnimationPlaybackPrivate
gint64 frames_played;
};
+typedef struct
+{
+ AnimationPlayback *playback;
+
+ gint level;
+} ParseStatus;
#define ANIMATION_PLAYBACK_GET_PRIVATE(playback) \
G_TYPE_INSTANCE_GET_PRIVATE (playback, \
@@ -86,6 +93,18 @@ static void on_cache_invalidated (Animation *
/* Timer callback for playback. */
static gboolean animation_playback_advance_frame_callback (AnimationPlayback *playback);
+/* XML parsing */
+static void animation_playback_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+static void animation_playback_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
+
G_DEFINE_TYPE (AnimationPlayback, animation_playback, G_TYPE_OBJECT)
@@ -230,13 +249,55 @@ animation_playback_new (void)
return playback;
}
+gchar *
+animation_playback_serialize (AnimationPlayback *playback)
+{
+ gchar *xml;
+
+ xml = g_strdup_printf ("<playback position=\"%d\" "
+ "start=\"%d\" stop=\"%d\"/>",
+ playback->priv->position,
+ playback->priv->start,
+ playback->priv->stop);
+ return xml;
+}
+
void
animation_playback_set_animation (AnimationPlayback *playback,
- Animation *animation)
+ Animation *animation,
+ const gchar *xml)
{
g_object_set (playback,
"animation", animation,
NULL);
+
+ if (xml)
+ {
+ /* Reset to last known playback status. */
+ const GMarkupParser markup_parser =
+ {
+ animation_playback_start_element,
+ animation_playback_end_element,
+ NULL, /* text */
+ NULL, /* passthrough */
+ NULL /* error */
+ };
+ GMarkupParseContext *context;
+ ParseStatus status = { 0, };
+ GError *error = NULL;
+
+ status.playback = playback;
+ status.level = 0;
+ context = g_markup_parse_context_new (&markup_parser,
+ 0, &status, NULL);
+ g_markup_parse_context_parse (context, xml, strlen (xml), &error);
+ if (error == NULL)
+ g_markup_parse_context_end_parse (context, &error);
+ g_markup_parse_context_free (context);
+ if (error)
+ g_warning ("Error parsing XML: %s", error->message);
+ g_clear_error (&error);
+ }
}
Animation *
@@ -656,3 +717,97 @@ animation_playback_advance_frame_callback (AnimationPlayback *playback)
return G_SOURCE_REMOVE;
}
+
+static void
+animation_playback_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ const gchar **names = attribute_names;
+ const gchar **values = attribute_values;
+ ParseStatus *status = (ParseStatus *) user_data;
+ AnimationPlayback *playback = status->playback;
+
+ if (status->level == 1 && g_strcmp0 (element_name, "playback") == 0)
+ {
+ gint duration;
+
+ duration = animation_get_duration (playback->priv->animation);
+ while (*names && *values)
+ {
+ if (strcmp (*names, "position") == 0 && **values)
+ {
+ gint position = g_ascii_strtoll (*values, NULL, 10);
+
+ if (position >= duration)
+ {
+ g_set_error (error, 0, 0,
+ _("Playback position %d out of range [0, %d]."),
+ position, duration - 1);
+ }
+ else
+ {
+ playback->priv->position = position;
+ }
+ }
+ else if (strcmp (*names, "start") == 0 && **values)
+ {
+ gint start = g_ascii_strtoll (*values, NULL, 10);
+
+ if (start >= duration)
+ {
+ g_set_error (error, 0, 0,
+ _("Playback start %d out of range [0, %d]."),
+ start, duration - 1);
+ }
+ else
+ {
+ playback->priv->start = start;
+ }
+ }
+ else if (strcmp (*names, "stop") == 0 && **values)
+ {
+ gint stop = g_ascii_strtoll (*values, NULL, 10);
+
+ if (stop >= duration)
+ {
+ g_set_error (error, 0, 0,
+ _("Playback stop %d out of range [0, %d]."),
+ stop, duration - 1);
+ }
+ else
+ {
+ playback->priv->stop = stop;
+ playback->priv->stop_at_end = (stop == duration - 1);
+ }
+ }
+
+ names++;
+ values++;
+ }
+ if (playback->priv->stop < playback->priv->start)
+ {
+ playback->priv->stop = duration - 1;
+ playback->priv->stop_at_end = TRUE;
+ }
+
+ if (playback->priv->position < playback->priv->start ||
+ playback->priv->position > playback->priv->stop)
+ {
+ playback->priv->position = playback->priv->start;
+ }
+ }
+ status->level++;
+}
+
+static void
+animation_playback_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ ((ParseStatus *) user_data)->level--;
+}
diff --git a/plug-ins/animation-play/core/animation-playback.h
b/plug-ins/animation-play/core/animation-playback.h
index e7ba300..08d59ff 100644
--- a/plug-ins/animation-play/core/animation-playback.h
+++ b/plug-ins/animation-play/core/animation-playback.h
@@ -60,9 +60,11 @@ struct _AnimationPlaybackClass
GType animation_playback_get_type (void);
AnimationPlayback * animation_playback_new (void);
+gchar * animation_playback_serialize (AnimationPlayback *playback);
void animation_playback_set_animation (AnimationPlayback *playback,
- Animation *animation);
+ Animation *animation,
+ const gchar *xml);
Animation * animation_playback_get_animation (AnimationPlayback *playback);
gint animation_playback_get_position (AnimationPlayback *playback);
diff --git a/plug-ins/animation-play/core/animation.c b/plug-ins/animation-play/core/animation.c
index 654ec3a..72be739 100644
--- a/plug-ins/animation-play/core/animation.c
+++ b/plug-ins/animation-play/core/animation.c
@@ -169,7 +169,7 @@ animation_class_init (AnimationClass *klass)
* @animation: the animation.
* @duration: the new duration of @animation in number of frames.
*
- * The ::playback-range signal must be emitted when the duration of
+ * The ::duration signal must be emitted when the duration of
* @animation changes.
*/
animation_signals[DURATION_CHANGED] =
@@ -187,7 +187,7 @@ animation_class_init (AnimationClass *klass)
* @animation: the animation.
* @framerate: the new framerate of @animation in frames per second.
*
- * The ::playback-range signal is emitted when the framerate of
+ * The ::framerate-changed signal is emitted when the framerate of
* @animation changes.
*/
animation_signals[FRAMERATE_CHANGED] =
@@ -311,7 +311,8 @@ animation_load (Animation *animation)
}
void
-animation_save_to_parasite (Animation *animation)
+animation_save_to_parasite (Animation *animation,
+ const gchar *playback_xml)
{
AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
GimpParasite *old_parasite;
@@ -326,7 +327,8 @@ animation_save_to_parasite (Animation *animation)
gimp_set_data (PLUG_IN_PROC, &settings, sizeof (&settings));
/* Then as a parasite for the specific image. */
- xml = ANIMATION_GET_CLASS (animation)->serialize (animation);
+ xml = ANIMATION_GET_CLASS (animation)->serialize (animation,
+ playback_xml);
if (ANIMATION_IS_ANIMATIC (animation))
{
@@ -360,6 +362,8 @@ animation_save_to_parasite (Animation *animation)
gimp_parasite_free (parasite);
}
gimp_parasite_free (old_parasite);
+ if (xml)
+ g_free (xml);
old_parasite = gimp_image_get_parasite (priv->image_id,
PLUG_IN_PROC "/selected");
@@ -543,8 +547,10 @@ animation_get_property (GObject *object,
{
gchar *xml;
- xml = ANIMATION_GET_CLASS (animation)->serialize (animation);
+ xml = ANIMATION_GET_CLASS (animation)->serialize (animation,
+ NULL);
g_value_take_string (value, xml);
+ g_free (xml);
}
break;
diff --git a/plug-ins/animation-play/core/animation.h b/plug-ins/animation-play/core/animation.h
index 59be8bc..5cfc62a 100644
--- a/plug-ins/animation-play/core/animation.h
+++ b/plug-ins/animation-play/core/animation.h
@@ -68,7 +68,8 @@ struct _AnimationClass
void (*purge_cache) (Animation *animation);
void (*reset_defaults) (Animation *animation);
- gchar * (*serialize) (Animation *animation);
+ gchar * (*serialize) (Animation *animation,
+ const gchar *playback_xml);
gboolean (*deserialize) (Animation *animation,
const gchar *xml,
GError **error);
@@ -84,7 +85,8 @@ gint32 animation_get_image_id (Animation *animation);
void animation_load (Animation *animation);
-void animation_save_to_parasite (Animation *animation);
+void animation_save_to_parasite (Animation *animation,
+ const gchar *playback_xml);
gint animation_get_duration (Animation *animation);
diff --git a/plug-ins/animation-play/widgets/animation-dialog.c
b/plug-ins/animation-play/widgets/animation-dialog.c
index ed0c2b6..8f3e8e7 100755
--- a/plug-ins/animation-play/widgets/animation-dialog.c
+++ b/plug-ins/animation-play/widgets/animation-dialog.c
@@ -143,7 +143,8 @@ static void connect_accelerators (GtkUIManager *ui_manager,
GtkActionGroup *group);
static void animation_dialog_set_animation (AnimationDialog *dialog,
- Animation *animation);
+ Animation *animation,
+ const gchar *xml);
static gboolean on_dialog_expose (GtkWidget *widget,
GdkEvent *event,
@@ -336,7 +337,7 @@ animation_dialog_new (gint32 image_id)
GtkWidget *dialog;
Animation *animation;
GimpParasite *parasite;
- const gchar *xml = NULL;
+ gchar *xml = NULL;
gboolean animatic_selected = TRUE;
parasite = gimp_image_get_parasite (image_id,
@@ -371,14 +372,14 @@ animation_dialog_new (gint32 image_id)
}
animation = animation_new (image_id, animatic_selected, xml);
- g_free ((gchar *) xml);
dialog = g_object_new (ANIMATION_TYPE_DIALOG,
"type", GTK_WINDOW_TOPLEVEL,
"image", image_id,
NULL);
animation_dialog_set_animation (ANIMATION_DIALOG (dialog),
- animation);
+ animation, xml);
+ g_free (xml);
return dialog;
}
@@ -948,7 +949,13 @@ static void
animation_dialog_finalize (GObject *object)
{
AnimationDialog *dialog = ANIMATION_DIALOG (object);
- AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
+ AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
+ gchar *playback_xml;
+
+ /* Save first, before cleaning anything. */
+ playback_xml = animation_playback_serialize (priv->playback);
+ animation_save_to_parasite (priv->animation, playback_xml);
+ g_free (playback_xml);
if (priv->shape_window)
gtk_widget_destroy (GTK_WIDGET (priv->shape_window));
@@ -1177,7 +1184,8 @@ connect_accelerators (GtkUIManager *ui_manager,
static void
animation_dialog_set_animation (AnimationDialog *dialog,
- Animation *animation)
+ Animation *animation,
+ const gchar *xml)
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
GtkWidget *frame;
@@ -1390,8 +1398,8 @@ animation_dialog_set_animation (AnimationDialog *dialog,
G_CALLBACK (low_framerate_cb),
dialog);
- /* Set the playback */
- animation_playback_set_animation (priv->playback, animation);
+ /* Set the playback and its default state. */
+ animation_playback_set_animation (priv->playback, animation, xml);
if (gtk_widget_get_realized (GTK_WIDGET (dialog)))
on_dialog_expose (GTK_WIDGET (dialog), NULL, priv->animation);
@@ -1467,10 +1475,10 @@ static void
animation_type_changed (GtkWidget *combo,
AnimationDialog *dialog)
{
- AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
Animation *animation;
+ AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
GimpParasite *parasite = NULL;
- const gchar *xml = NULL;
+ gchar *xml = NULL;
gint index;
index = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
@@ -1494,12 +1502,10 @@ animation_type_changed (GtkWidget *combo,
xml = g_strdup (gimp_parasite_data (parasite));
gimp_parasite_free (parasite);
}
- animation = animation_new (priv->image_id,
- (index == 0),
- xml);
- g_free ((gchar *) xml);
+ animation = animation_new (priv->image_id, (index == 0), xml);
animation_dialog_set_animation (ANIMATION_DIALOG (dialog),
- animation);
+ animation, xml);
+ g_free (xml);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]