[gimp/wip/animation: 126/197] plug-ins: save the current animation playback state.



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]