[gimp/wip/animation: 233/373] plug-ins: save and load animatic info as XML.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 233/373] plug-ins: save and load animatic info as XML.
- Date: Sat, 7 Oct 2017 02:14:18 +0000 (UTC)
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]