[gimp/wip/animation: 233/373] plug-ins: save and load animatic info as XML.



commit f17d29807ef56d89e42894a00ab5ee3a9c4dd961
Author: Jehan <jehan girinstud io>
Date:   Wed Jun 15 18:28:13 2016 +0200

    plug-ins: save and load animatic info as XML.
    
    Right now, only the framerate, panel comments and durations are loaded.
    This is still work-in-progress.

 plug-ins/animation-play/animation-utils.h          |    9 +-
 plug-ins/animation-play/core/animation.c           |   22 +-
 plug-ins/animation-play/core/animation.h           |   10 +-
 plug-ins/animation-play/core/animationanimatic.c   |  385 ++++++++++++++++++--
 plug-ins/animation-play/widgets/animation-dialog.c |   23 +-
 .../animation-play/widgets/animation-storyboard.c  |   36 ++-
 6 files changed, 424 insertions(+), 61 deletions(-)
---
diff --git a/plug-ins/animation-play/animation-utils.h b/plug-ins/animation-play/animation-utils.h
index 09e084b..de3dcb5 100755
--- a/plug-ins/animation-play/animation-utils.h
+++ b/plug-ins/animation-play/animation-utils.h
@@ -21,9 +21,12 @@
 #ifndef __ANIMATION_UTILS_H__
 #define __ANIMATION_UTILS_H__
 
-#define PLUG_IN_PROC   "plug-in-animationplay"
-#define PLUG_IN_BINARY "animation-play"
-#define PLUG_IN_ROLE   "gimp-animation-playback"
+#define PLUG_IN_PROC       "plug-in-animationplay"
+#define PLUG_IN_BINARY     "animation-play"
+#define PLUG_IN_ROLE       "gimp-animation-playback"
+
+#define MAX_FRAMERATE      300.0
+#define DEFAULT_FRAMERATE  24.0
 
 void total_alpha_preview (guchar *drawing_data,
                           guint   drawing_width,
diff --git a/plug-ins/animation-play/core/animation.c b/plug-ins/animation-play/core/animation.c
index de3cc59..95d40d1 100644
--- a/plug-ins/animation-play/core/animation.c
+++ b/plug-ins/animation-play/core/animation.c
@@ -56,6 +56,7 @@ typedef struct _AnimationPrivate AnimationPrivate;
 struct _AnimationPrivate
 {
   gint32       image_id;
+  gchar       *xml;
 
   gdouble      framerate;
 
@@ -343,14 +344,18 @@ animation_init (Animation *animation)
 /************ Public Functions ****************/
 
 Animation *
-animation_new (gint32   image_id,
-               gboolean xsheet)
+animation_new (gint32       image_id,
+               const gchar *xml)
 {
-  Animation *animation;
+  Animation        *animation;
+  AnimationPrivate *priv;
 
   animation = g_object_new (ANIMATION_TYPE_ANIMATIC,
                             "image", image_id,
                             NULL);
+  priv = ANIMATION_GET_PRIVATE (animation);
+  priv->xml = g_strdup (xml);
+
   return animation;
 }
 
@@ -377,7 +382,16 @@ animation_load (Animation *animation,
   priv->proxy_ratio = proxy_ratio;
   g_signal_emit (animation, animation_signals[PROXY], 0, proxy_ratio);
 
-  ANIMATION_GET_CLASS (animation)->load (animation, proxy_ratio);
+  if (priv->xml)
+    ANIMATION_GET_CLASS (animation)->load_xml (animation,
+                                               priv->xml,
+                                               proxy_ratio);
+  else
+    ANIMATION_GET_CLASS (animation)->load (animation, proxy_ratio);
+  /* XML is only used for the first load.
+   * Any next loads will use internal data. */
+  g_free (priv->xml);
+  priv->xml = NULL;
 
   priv->start_pos = ANIMATION_GET_CLASS (animation)->get_start_position (animation);
   priv->position  = priv->start_pos;
diff --git a/plug-ins/animation-play/core/animation.h b/plug-ins/animation-play/core/animation.h
index 21d9418..9399156 100644
--- a/plug-ins/animation-play/core/animation.h
+++ b/plug-ins/animation-play/core/animation.h
@@ -49,8 +49,11 @@ struct _AnimationClass
                                       gint       next_pos);
 
   /* These virtual methods must be implemented by any subclass. */
-  void         (*load)          (Animation  *animation,
-                                 gdouble     proxy_ratio);
+  void         (*load)          (Animation   *animation,
+                                 gdouble      proxy_ratio);
+  void         (*load_xml)      (Animation   *animation,
+                                 const gchar *xml,
+                                 gdouble      proxy_ratio);
   gint         (*get_length)    (Animation   *animation);
 
 
@@ -67,7 +70,8 @@ struct _AnimationClass
 GType         animation_get_type (void);
 
 Animation   * animation_new                (gint32       image_id,
-                                            gboolean     xsheet);
+                                            const gchar *xml);
+
 gint32        animation_get_image_id       (Animation   *animation);
 
 void          animation_load               (Animation   *animation,
diff --git a/plug-ins/animation-play/core/animationanimatic.c 
b/plug-ins/animation-play/core/animationanimatic.c
index 060aecf..7250930 100644
--- a/plug-ins/animation-play/core/animationanimatic.c
+++ b/plug-ins/animation-play/core/animationanimatic.c
@@ -23,8 +23,33 @@
 #include <libgimp/gimp.h>
 #include <libgimp/stdplugins-intl.h>
 
+#include "animation-utils.h"
 #include "animationanimatic.h"
 
+typedef enum
+{
+  START_STATE,
+  ANIMATION_STATE,
+  SEQUENCE_STATE,
+  PANEL_STATE,
+  LAYER_STATE,
+  END_SEQUENCE_STATE,
+  COMMENTS_STATE,
+  COMMENT_STATE,
+  END_STATE
+} AnimationParseState;
+
+typedef struct
+{
+  Animation           *animation;
+  AnimationParseState  state;
+
+  gint                 panel;
+  gint                 duration;
+
+  gint                 xml_level;
+} ParseStatus;
+
 enum
 {
   IMAGE_DURATION,
@@ -62,19 +87,42 @@ static void         animation_animatic_finalize   (GObject           *object);
 
 /* Virtual methods */
 
-static gint         animation_animatic_get_length (Animation         *animation);
-static void         animation_animatic_get_size   (Animation         *animation,
-                                                   gint              *width,
-                                                   gint              *height);
-
-static void         animation_animatic_load       (Animation         *animation,
-                                                   gdouble            proxy_ratio);
-static GeglBuffer * animation_animatic_get_frame  (Animation         *animation,
-                                                   gint               pos);
-static gchar      * animation_animatic_serialize  (Animation         *animation);
-static gboolean     animation_animatic_same       (Animation         *animation,
-                                                   gint               previous_pos,
-                                                   gint               next_pos);
+static gint         animation_animatic_get_length  (Animation         *animation);
+static void         animation_animatic_get_size    (Animation         *animation,
+                                                    gint              *width,
+                                                    gint              *height);
+
+static void         animation_animatic_load        (Animation         *animation,
+                                                    gdouble            proxy_ratio);
+static void         animation_animatic_load_xml    (Animation         *animation,
+                                                    const gchar       *xml,
+                                                    gdouble            proxy_ratio);
+static GeglBuffer * animation_animatic_get_frame   (Animation         *animation,
+                                                    gint               pos);
+static gchar      * animation_animatic_serialize   (Animation         *animation);
+
+static gboolean     animation_animatic_same        (Animation         *animation,
+                                                    gint               previous_pos,
+                                                    gint               next_pos);
+
+/* XML parsing */
+
+static void      animation_animatic_start_element (GMarkupParseContext *context,
+                                                    const gchar         *element_name,
+                                                    const gchar        **attribute_names,
+                                                    const gchar        **attribute_values,
+                                                    gpointer             user_data,
+                                                    GError             **error);
+static void      animation_animatic_end_element   (GMarkupParseContext *context,
+                                                   const gchar         *element_name,
+                                                   gpointer             user_data,
+                                                   GError             **error);
+
+static void      animation_animatic_text          (GMarkupParseContext  *context,
+                                                   const gchar          *text,
+                                                   gsize                 text_len,
+                                                   gpointer              user_data,
+                                                   GError              **error);
 
 /* Utils */
 
@@ -127,12 +175,13 @@ animation_animatic_class_init (AnimationAnimaticClass *klass)
 
   object_class->finalize = animation_animatic_finalize;
 
-  anim_class->get_length = animation_animatic_get_length;
-  anim_class->get_size   = animation_animatic_get_size;
-  anim_class->load       = animation_animatic_load;
-  anim_class->get_frame  = animation_animatic_get_frame;
-  anim_class->serialize  = animation_animatic_serialize;
-  anim_class->same       = animation_animatic_same;
+  anim_class->get_length  = animation_animatic_get_length;
+  anim_class->get_size    = animation_animatic_get_size;
+  anim_class->load        = animation_animatic_load;
+  anim_class->load_xml    = animation_animatic_load_xml;
+  anim_class->get_frame   = animation_animatic_get_frame;
+  anim_class->serialize   = animation_animatic_serialize;
+  anim_class->same        = animation_animatic_same;
 
   g_type_class_add_private (klass, sizeof (AnimationAnimaticPrivate));
 }
@@ -432,6 +481,52 @@ animation_animatic_load (Animation *animation,
   g_free (layers);
 }
 
+static void
+animation_animatic_load_xml (Animation   *animation,
+                             const gchar *xml,
+                             gdouble      proxy_ratio)
+{
+  const GMarkupParser markup_parser =
+    {
+      animation_animatic_start_element,
+      animation_animatic_end_element,
+      animation_animatic_text,
+      NULL,  /*  passthrough  */
+      NULL   /*  error        */
+    };
+  GMarkupParseContext *context;
+  ParseStatus          status = { 0, };
+  GError              *error  = NULL;
+
+  g_return_if_fail (xml != NULL);
+
+  /* Init with a default load. */
+  animation_animatic_load (animation, proxy_ratio);
+
+  /* Parse XML to update. */
+  status.state = START_STATE;
+  status.animation = animation;
+  status.xml_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)
+    {
+      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_animatic_load (animation, proxy_ratio);
+}
+
 static GeglBuffer *
 animation_animatic_get_frame (Animation *animation,
                               gint       pos)
@@ -477,45 +572,48 @@ animation_animatic_serialize (Animation *animation)
   gchar                    *tmp;
   gint                      i;
 
-  text = g_strdup_printf ("<animation framerate=\"%f\" type=\"animatic\"><sequence>",
-                          animation_get_framerate (animation));
+  text = g_strdup_printf ("<animation type=\"animatic\" framerate=\"%f\" "
+                          " duration=\"%d\" width=\"\" height=\"\">"
+                          "<sequence>",
+                          animation_get_framerate (animation),
+                          priv->n_panels);
   for (i = 0; i < priv->n_panels; i++)
     {
       gchar  *panel;
-      gchar  *layer_name;
-      gint32 *panels;
-      gint    n_panels;
-
-      panels = gimp_image_get_layers (priv->panels, &n_panels);
-      layer_name = gimp_item_get_name (panels[n_panels - (i + 1)]);
 
-      panel = g_markup_printf_escaped ("<panel title=\"%s\" duration=\"%d\" layer=\"%d\">",
-                                       layer_name, priv->durations[i],
+      panel = g_markup_printf_escaped ("<panel duration=\"%d\">"
+                                       "<layer id=\"%d\"/></panel>",
+                                       priv->durations[i],
                                        priv->tattoos[i]);
-      g_free (layer_name);
 
       tmp = text;
       text = g_strconcat (text, panel, NULL);
       g_free (tmp);
       g_free (panel);
+    }
+  tmp = text;
+  text = g_strconcat (text, "</sequence><comments>", NULL);
+  g_free (tmp);
 
+  /* New loop for comments. */
+  for (i = 0; i < priv->n_panels; i++)
+    {
       if (priv->comments[i])
         {
           gchar *comment;
 
-          comment = g_markup_printf_escaped ("<notes title=\"Notes\">%s</notes>",
+          /* Comments are for a given panel, not for a frame position. */
+          comment = g_markup_printf_escaped ("<comment panel=\"%d\">%s</comment>",
+                                             i + 1,
                                              priv->comments[i]);
           tmp = text;
           text = g_strconcat (text, comment, NULL);
           g_free (tmp);
           g_free (comment);
         }
-      tmp = text;
-      text = g_strconcat (text, "</panel>", NULL);
-      g_free (tmp);
     }
   tmp = text;
-  text = g_strconcat (text, "</sequence></animation>", NULL);
+  text = g_strconcat (text, "</comments></animation>", NULL);
   g_free (tmp);
 
   return text;
@@ -549,6 +647,223 @@ animation_animatic_same (Animation *animation,
   return identical;
 }
 
+static void
+animation_animatic_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;
+  AnimationAnimaticPrivate  *priv   = GET_PRIVATE (status->animation);
+
+  status->xml_level++;
+  switch (status->state)
+    {
+    case START_STATE:
+      if (g_strcmp0 (element_name, "animation") != 0)
+        {
+          g_set_error (error, 0, 0,
+                       _("Unknown animation tag: \"%s\"."),
+                       element_name);
+          return;
+        }
+      while (*names && *values)
+        {
+          if (strcmp (*names, "type") == 0)
+            {
+              if (! **values || strcmp (*values, "animatic") != 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);
+            }
+
+          names++;
+          values++;
+        }
+      status->state = ANIMATION_STATE;
+      break;
+    case ANIMATION_STATE:
+      if (g_strcmp0 (element_name, "sequence") != 0)
+        {
+          g_set_error (error, 0, 0,
+                       _("Unknown sequence tag: \"%s\"."),
+                       element_name);
+          return;
+        }
+      status->state = SEQUENCE_STATE;
+      break;
+    case SEQUENCE_STATE:
+      if (g_strcmp0 (element_name, "panel") != 0)
+        {
+          g_set_error (error, 0, 0,
+                       _("Unknown panel tag: \"%s\"."),
+                       element_name);
+          return;
+        }
+      status->panel++;
+      while (*names && *values)
+        {
+          if (strcmp (*names, "duration") == 0 && **values)
+            {
+              gint duration = g_ascii_strtoll (*values, NULL, 10);
+
+              if (duration > 0)
+                priv->durations[status->panel - 1] = duration;
+            }
+
+          names++;
+          values++;
+        }
+      status->state = PANEL_STATE;
+      break;
+    case PANEL_STATE:
+      if (g_strcmp0 (element_name, "layer") != 0)
+        {
+          g_set_error (error, 0, 0,
+                       _("Unknown layer tag: \"%s\"."),
+                       element_name);
+          return;
+        }
+      status->state = LAYER_STATE;
+      break;
+    case LAYER_STATE:
+      /* <layer> should have no child tag. */
+      g_set_error (error, 0, 0,
+                   _("Unknown layer tag: \"%s\"."),
+                   element_name);
+      return;
+    case END_SEQUENCE_STATE:
+      if (g_strcmp0 (element_name, "comments") != 0)
+        {
+          g_set_error (error, 0, 0,
+                       _("Unknown comments tag: \"%s\"."),
+                       element_name);
+          return;
+        }
+      status->state = COMMENTS_STATE;
+      break;
+    case COMMENTS_STATE:
+      if (g_strcmp0 (element_name, "comment") != 0)
+        {
+          g_set_error (error, 0, 0,
+                       _("Unknown comment tag: \"%s\"."),
+                       element_name);
+          return;
+        }
+      status->panel = -1;
+      while (*names && *values)
+        {
+          if (strcmp (*names, "panel") == 0 && **values)
+            {
+              gint panel = (gint) g_ascii_strtoll (*values, NULL, 10);
+
+              status->panel = panel;
+              break;
+            }
+
+          names++;
+          values++;
+        }
+      status->state = COMMENT_STATE;
+      break;
+    case COMMENT_STATE:
+      /* <comment> should have no child tag. */
+      g_set_error (error, 0, 0,
+                   _("Unknown layer tag: \"%s\"."),
+                   element_name);
+      return;
+    default:
+      g_set_error (error, 0, 0,
+                   _("Unknown state!"));
+      break;
+    }
+}
+
+static void
+animation_animatic_end_element (GMarkupParseContext *context,
+                                const gchar         *element_name,
+                                gpointer             user_data,
+                                GError             **error)
+{
+  ParseStatus *status = (ParseStatus *) user_data;
+
+  status->xml_level--;
+
+  switch (status->state)
+    {
+    case SEQUENCE_STATE:
+    case COMMENTS_STATE:
+      status->state = END_SEQUENCE_STATE;
+      break;
+    case PANEL_STATE:
+      status->state = SEQUENCE_STATE;
+      break;
+    case LAYER_STATE:
+      status->state = PANEL_STATE;
+      break;
+    case END_SEQUENCE_STATE:
+    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_animatic_text (GMarkupParseContext  *context,
+                         const gchar          *text,
+                         gsize                 text_len,
+                         gpointer              user_data,
+                         GError              **error)
+{
+  ParseStatus *status = (ParseStatus *) user_data;
+  AnimationAnimatic *animatic = ANIMATION_ANIMATIC (status->animation);
+
+  switch (status->state)
+    {
+    case COMMENT_STATE:
+      if (status->panel == -1)
+        /* invalid comment tag. */
+        break;
+      /* Setting comment to a panel. */
+      animation_animatic_set_comment (animatic,
+                                      status->panel,
+                                      text);
+      status->panel = -1;
+      break;
+    default:
+      /* Ignoring text everywhere else. */
+      break;
+    }
+}
+
 /**** Utils ****/
 
 static gint
diff --git a/plug-ins/animation-play/widgets/animation-dialog.c 
b/plug-ins/animation-play/widgets/animation-dialog.c
index 60a80f0..7a039b7 100755
--- a/plug-ins/animation-play/widgets/animation-dialog.c
+++ b/plug-ins/animation-play/widgets/animation-dialog.c
@@ -36,7 +36,6 @@
 
 #include "libgimp/stdplugins-intl.h"
 
-#define MAX_FRAMERATE  300.0
 #define DITHERTYPE     GDK_RGB_DITHER_NORMAL
 
 /* Settings we cache assuming they may be the user's
@@ -333,6 +332,7 @@ animation_dialog_new (gint32 image_id)
   GtkWidget      *dialog;
   Animation      *animation;
   GimpParasite   *parasite;
+  const gchar    *xml = NULL;
   CachedSettings  settings;
 
   /* Acceptable default settings. */
@@ -343,16 +343,15 @@ animation_dialog_new (gint32 image_id)
 
   /* If this animation has specific settings already, override the global ones. */
   parasite = gimp_image_get_parasite (image_id,
-                                      PLUG_IN_PROC "/framerate");
+                                      PLUG_IN_PROC "/animation-0");
   if (parasite)
     {
-      const gdouble *rate = gimp_parasite_data (parasite);
-
-      settings.framerate = *rate;
+      xml = g_strdup (gimp_parasite_data (parasite));
       gimp_parasite_free (parasite);
     }
 
-  animation = animation_new (image_id, FALSE);
+  animation = animation_new (image_id, xml);
+  g_free ((gchar *) xml);
 
   dialog = g_object_new (ANIMATION_TYPE_DIALOG,
                          "type",  GTK_WINDOW_TOPLEVEL,
@@ -361,7 +360,6 @@ animation_dialog_new (gint32 image_id)
   animation_dialog_set_animation (ANIMATION_DIALOG (dialog),
                                   animation);
 
-  animation_set_framerate (animation, settings.framerate);
   animation_load (animation, 1.0);
 
   return dialog;
@@ -1262,6 +1260,7 @@ animation_dialog_save_settings (AnimationDialog *dialog)
 {
   AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
   GimpParasite           *old_parasite;
+  gchar                  *xml;
   gboolean                undo_step_started = FALSE;
   CachedSettings          cached_settings;
 
@@ -1270,14 +1269,15 @@ animation_dialog_save_settings (AnimationDialog *dialog)
 
   gimp_set_data (PLUG_IN_PROC, &cached_settings, sizeof (&cached_settings));
 
+  xml = animation_serialize (priv->animation);
   /* Then as a parasite for the specific image.
    * If there was already parasites and they were all the same as the
    * current state, do not resave them.
    * This prevents setting the image in a dirty state while it stayed
    * the same. */
-  old_parasite = gimp_image_get_parasite (priv->image_id, PLUG_IN_PROC "/framerate");
+  old_parasite = gimp_image_get_parasite (priv->image_id, PLUG_IN_PROC "/animation-0");
   if (! old_parasite ||
-      *(gdouble *) gimp_parasite_data (old_parasite) != cached_settings.framerate)
+      (gchar *) gimp_parasite_data (old_parasite) != xml)
     {
       GimpParasite *parasite;
       if (! undo_step_started)
@@ -1285,10 +1285,9 @@ animation_dialog_save_settings (AnimationDialog *dialog)
           gimp_image_undo_group_start (priv->image_id);
           undo_step_started = TRUE;
         }
-      parasite = gimp_parasite_new (PLUG_IN_PROC "/framerate",
+      parasite = gimp_parasite_new (PLUG_IN_PROC "/animation-0",
                                     GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE,
-                                    sizeof (cached_settings.framerate),
-                                    &cached_settings.framerate);
+                                    strlen (xml) + 1, xml);
       gimp_image_attach_parasite (priv->image_id, parasite);
       gimp_parasite_free (parasite);
     }
diff --git a/plug-ins/animation-play/widgets/animation-storyboard.c 
b/plug-ins/animation-play/widgets/animation-storyboard.c
index ee5c528..79a5ad7 100644
--- a/plug-ins/animation-play/widgets/animation-storyboard.c
+++ b/plug-ins/animation-play/widgets/animation-storyboard.c
@@ -66,6 +66,9 @@ static void animation_storyboard_load                  (Animation           *ani
 static void animation_storyboard_duration_spin_changed (GtkSpinButton       *spinbutton,
                                                         AnimationAnimatic   *animation);
 
+static void animation_storyboard_comment_changed       (GtkTextBuffer       *text_buffer,
+                                                        AnimationAnimatic   *animatic);
+
 G_DEFINE_TYPE (AnimationStoryboard, animation_storyboard, GTK_TYPE_TABLE)
 
 #define parent_class animation_storyboard_parent_class
@@ -275,6 +278,12 @@ animation_storyboard_load (Animation           *animation,
           if (comment_contents != NULL)
             gtk_text_buffer_insert_at_cursor (buffer, comment_contents, -1);
 
+          g_object_set_data (G_OBJECT (buffer), "panel-num",
+                             GINT_TO_POINTER (panel_num));
+          g_signal_connect (buffer, "changed",
+                            (GCallback) animation_storyboard_comment_changed,
+                            animation);
+
           g_free (image_name);
         }
 
@@ -296,7 +305,7 @@ animation_storyboard_load (Animation           *animation,
                         0, /* Do not expand nor fill, nor shrink. */
                         0, /* Do not expand nor fill, nor shrink. */
                         0, 1);
-      g_object_set_data (G_OBJECT (duration), "layer-position",
+      g_object_set_data (G_OBJECT (duration), "panel-num",
                          GINT_TO_POINTER (panel_num));
       g_signal_connect (duration, "value-changed",
                         (GCallback) animation_storyboard_duration_spin_changed,
@@ -322,13 +331,32 @@ static void
 animation_storyboard_duration_spin_changed (GtkSpinButton     *spinbutton,
                                             AnimationAnimatic *animation)
 {
-  gpointer layer_pos;
+  gpointer panel_num;
   gint     duration;
 
-  layer_pos = g_object_get_data (G_OBJECT (spinbutton), "layer-position");
+  panel_num = g_object_get_data (G_OBJECT (spinbutton), "panel-num");
   duration = gtk_spin_button_get_value_as_int (spinbutton);
 
   animation_animatic_set_duration (animation,
-                                   GPOINTER_TO_INT (layer_pos),
+                                   GPOINTER_TO_INT (panel_num),
                                    duration);
 }
+
+static void
+animation_storyboard_comment_changed (GtkTextBuffer     *text_buffer,
+                                      AnimationAnimatic *animatic)
+{
+  gchar       *text;
+  GtkTextIter  start;
+  GtkTextIter  end;
+  gpointer     panel_num;
+
+  panel_num = g_object_get_data (G_OBJECT (text_buffer), "panel-num");
+
+  gtk_text_buffer_get_bounds (text_buffer, &start, &end);
+  text = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
+  animation_animatic_set_comment (animatic,
+                                  GPOINTER_TO_INT (panel_num),
+                                  text);
+  g_free (text);
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]