[gimp/wip/animation: 256/373] plug-ins: split the playback code out of the Animation class.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 256/373] plug-ins: split the playback code out of the Animation class.
- Date: Sat, 7 Oct 2017 02:16:14 +0000 (UTC)
commit 694027107216d958139c1c27440c18d33a3199d6
Author: Jehan <jehan girinstud io>
Date: Fri Nov 4 02:16:38 2016 +0100
plug-ins: split the playback code out of the Animation class.
plug-ins/animation-play/Makefile.am | 2 +
.../animation-play/core/animation-celanimation.c | 13 +-
plug-ins/animation-play/core/animation-playback.c | 628 ++++++++++++++++++++
plug-ins/animation-play/core/animation-playback.h | 86 +++
plug-ins/animation-play/core/animation.c | 512 +++--------------
plug-ins/animation-play/core/animation.h | 46 +-
plug-ins/animation-play/core/animationanimatic.c | 109 +---
plug-ins/animation-play/core/animationanimatic.h | 33 +-
plug-ins/animation-play/widgets/animation-dialog.c | 322 +++++-----
.../animation-play/widgets/animation-storyboard.c | 66 ++-
.../animation-play/widgets/animation-storyboard.h | 3 +-
plug-ins/animation-play/widgets/animation-xsheet.c | 49 +-
plug-ins/animation-play/widgets/animation-xsheet.h | 1 +
13 files changed, 1075 insertions(+), 795 deletions(-)
---
diff --git a/plug-ins/animation-play/Makefile.am b/plug-ins/animation-play/Makefile.am
index 4774dd7..ac66c6e 100644
--- a/plug-ins/animation-play/Makefile.am
+++ b/plug-ins/animation-play/Makefile.am
@@ -49,6 +49,8 @@ animation_play_SOURCES = \
core/animationanimatic.c \
core/animation-celanimation.h \
core/animation-celanimation.c \
+ core/animation-playback.h \
+ core/animation-playback.c \
widgets/animation-dialog.h \
widgets/animation-dialog.c \
widgets/animation-storyboard.h \
diff --git a/plug-ins/animation-play/core/animation-celanimation.c
b/plug-ins/animation-play/core/animation-celanimation.c
index 703605c..d049c2d 100644
--- a/plug-ins/animation-play/core/animation-celanimation.c
+++ b/plug-ins/animation-play/core/animation-celanimation.c
@@ -220,16 +220,6 @@ animation_cel_animation_set_layers (AnimationCelAnimation *animation,
frame_layer->data = 0;
}
animation_cel_animation_cache (animation, position);
- if (animation_get_position (ANIMATION (animation)) == position)
- {
- GeglBuffer *buffer;
-
- buffer = animation_get_frame (ANIMATION (animation), position);
- g_signal_emit_by_name (animation, "render",
- position, buffer, TRUE);
- if (buffer)
- g_object_unref (buffer);
- }
}
}
@@ -1088,8 +1078,9 @@ animation_cel_animation_cache (AnimationCelAnimation *animation,
/* This item exists and has a NULL data. */
g_list_nth (animation->priv->cache, pos)->data = cache;
-}
+ g_signal_emit_by_name (animation, "cache-invalidated", pos, 1);
+}
static gboolean
animation_cel_animation_cache_cmp (Cache *cache1,
diff --git a/plug-ins/animation-play/core/animation-playback.c
b/plug-ins/animation-play/core/animation-playback.c
new file mode 100644
index 0000000..e2e6321
--- /dev/null
+++ b/plug-ins/animation-play/core/animation-playback.c
@@ -0,0 +1,628 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * animation-playback.c
+ * Copyright (C) 2016 Jehan <jehan gimp org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <libgimp/gimp.h>
+
+#include "animation.h"
+#include "animation-playback.h"
+
+enum
+{
+ START,
+ STOP,
+ RANGE,
+ RENDER,
+ LOW_FRAMERATE,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_ANIMATION
+};
+
+struct _AnimationPlaybackPrivate
+{
+ Animation *animation;
+
+ /* State of the currently loaded playback. */
+ gint position;
+ /* Playback can be a subset of frames. */
+ guint start;
+ guint stop;
+
+ guint timer;
+ gint64 start_time;
+ gint64 frames_played;
+};
+
+
+#define ANIMATION_PLAYBACK_GET_PRIVATE(playback) \
+ G_TYPE_INSTANCE_GET_PRIVATE (playback, \
+ ANIMATION_PLAYBACK_TYPE_ANIMATION_PLAYBACK, \
+ AnimationPlaybackPrivate)
+
+static void animation_playback_finalize (GObject *object);
+static void animation_playback_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void animation_playback_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void on_cache_invalidated (Animation *animation,
+ gint position,
+ gint length,
+ AnimationPlayback *playback);
+
+/* Timer callback for playback. */
+static gboolean animation_playback_advance_frame_callback (AnimationPlayback *playback);
+
+
+G_DEFINE_TYPE (AnimationPlayback, animation_playback, G_TYPE_OBJECT)
+
+#define parent_class animation_playback_parent_class
+
+static guint animation_playback_signals[LAST_SIGNAL] = { 0 };
+
+static void
+animation_playback_class_init (AnimationPlaybackClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ /**
+ * AnimationPlayback::start:
+ * @playback: the #AnimationPlayback.
+ *
+ * The @playback starts to play.
+ */
+ animation_playback_signals[START] =
+ g_signal_new ("start",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (AnimationPlaybackClass, start),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ /**
+ * AnimationPlayback::stop:
+ * @playback: the #AnimationPlayback.
+ *
+ * The @playback stops playing.
+ */
+ animation_playback_signals[STOP] =
+ g_signal_new ("stop",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (AnimationPlaybackClass, stop),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ /**
+ * AnimationPlayback::range:
+ * @playback: the #AnimationPlayback.
+ * @start: the playback start frame.
+ * @stop: the playback last frame.
+ *
+ * The ::range signal is emitted when the playback range is
+ * updated.
+ */
+ animation_playback_signals[RANGE] =
+ g_signal_new ("range",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (AnimationPlaybackClass, range),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
+ /**
+ * AnimationPlayback::render:
+ * @playback: the #AnimationPlayback.
+ * @position: current position to be rendered.
+ * @buffer: the #GeglBuffer for the frame at @position.
+ * @must_draw_null: meaning of a %NULL @buffer.
+ * %TRUE means we have to draw an empty frame.
+ * %FALSE means the new frame is same as the current frame.
+ *
+ * Sends a request for render to the GUI.
+ */
+ animation_playback_signals[RENDER] =
+ g_signal_new ("render",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (AnimationPlaybackClass, render),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_INT,
+ GEGL_TYPE_BUFFER,
+ G_TYPE_BOOLEAN);
+ /**
+ * AnimationPlayback::low-framerate:
+ * @playback: the #AnimationPlayback.
+ * @actual_fps: the current playback framerate in fps.
+ *
+ * The ::low-framerate signal is emitted when the playback framerate
+ * is lower than expected. It is also emitted once when the framerate
+ * comes back to acceptable rate.
+ */
+ animation_playback_signals[LOW_FRAMERATE] =
+ g_signal_new ("low-framerate",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (AnimationPlaybackClass, low_framerate),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DOUBLE);
+
+ object_class->finalize = animation_playback_finalize;
+ object_class->set_property = animation_playback_set_property;
+ object_class->get_property = animation_playback_get_property;
+
+ /**
+ * AnimationPlayback:animation:
+ *
+ * The associated #Animation.
+ */
+ g_object_class_install_property (object_class, PROP_ANIMATION,
+ g_param_spec_object ("animation",
+ NULL, NULL,
+ ANIMATION_TYPE_ANIMATION,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (klass, sizeof (AnimationPlaybackPrivate));
+}
+
+static void
+animation_playback_init (AnimationPlayback *playback)
+{
+ playback->priv = G_TYPE_INSTANCE_GET_PRIVATE (playback,
+ ANIMATION_TYPE_PLAYBACK,
+ AnimationPlaybackPrivate);
+}
+
+/************ Public Functions ****************/
+
+AnimationPlayback *
+animation_playback_new (void)
+{
+ AnimationPlayback *playback;
+
+ playback = g_object_new (ANIMATION_TYPE_PLAYBACK,
+ NULL);
+
+ return playback;
+}
+
+void
+animation_playback_set_animation (AnimationPlayback *playback,
+ Animation *animation)
+{
+ g_object_set (playback,
+ "animation", animation,
+ NULL);
+}
+
+Animation *
+animation_playback_get_animation (AnimationPlayback *playback)
+{
+ return playback->priv->animation;
+}
+
+gint
+animation_playback_get_position (AnimationPlayback *playback)
+{
+ return playback->priv->position;
+}
+
+gboolean
+animation_playback_is_playing (AnimationPlayback *playback)
+{
+ return (playback->priv->timer != 0);
+}
+
+void
+animation_playback_play (AnimationPlayback *playback)
+{
+ gint duration;
+
+ duration = (gint) (1000.0 /
+ animation_get_framerate (playback->priv->animation));
+
+ if (playback->priv->timer)
+ {
+ /* It means we are already playing, so we should not need to play
+ * again.
+ * Still be liberal and simply remove the timer before creating a
+ * new one. */
+ g_source_remove (playback->priv->timer);
+ g_signal_emit (playback, animation_playback_signals[STOP], 0);
+ }
+
+ playback->priv->start_time = g_get_monotonic_time ();
+ playback->priv->frames_played = 1;
+
+ playback->priv->timer = g_timeout_add ((guint) duration,
+ (GSourceFunc) animation_playback_advance_frame_callback,
+ playback);
+ g_signal_emit (playback, animation_playback_signals[START], 0);
+}
+
+void
+animation_playback_stop (AnimationPlayback *playback)
+{
+ if (playback->priv->timer)
+ {
+ /* Stop playing by removing any playback timer. */
+ g_source_remove (playback->priv->timer);
+ playback->priv->timer = 0;
+ g_signal_emit (playback, animation_playback_signals[STOP], 0);
+ }
+}
+
+void
+animation_playback_next (AnimationPlayback *playback)
+{
+ Animation *animation = playback->priv->animation;
+ GeglBuffer *buffer = NULL;
+ gint previous_pos = playback->priv->position;
+ gboolean identical;
+
+ if (! playback->priv->animation)
+ return;
+
+ playback->priv->position = playback->priv->start +
+ ((playback->priv->position - playback->priv->start + 1) %
+ (playback->priv->stop - playback->priv->start + 1));
+
+ identical = ANIMATION_GET_CLASS (animation)->same (animation,
+ previous_pos,
+ playback->priv->position);
+ if (! identical)
+ {
+ buffer = animation_get_frame (animation, playback->priv->position);
+ }
+ g_signal_emit (playback, animation_playback_signals[RENDER], 0,
+ playback->priv->position, buffer, ! identical);
+ if (buffer != NULL)
+ {
+ g_object_unref (buffer);
+ }
+}
+
+void
+animation_playback_prev (AnimationPlayback *playback)
+{
+ Animation *animation = playback->priv->animation;
+ GeglBuffer *buffer = NULL;
+ gint prev_pos = playback->priv->position;
+ gboolean identical;
+
+ if (! playback->priv->animation)
+ return;
+
+ if (playback->priv->position == playback->priv->start)
+ {
+ playback->priv->position = animation_playback_get_stop (playback);
+ }
+ else
+ {
+ --playback->priv->position;
+ }
+
+ identical = ANIMATION_GET_CLASS (animation)->same (animation,
+ prev_pos,
+ playback->priv->position);
+ if (! identical)
+ {
+ buffer = animation_get_frame (animation, playback->priv->position);
+ }
+ g_signal_emit (playback, animation_playback_signals[RENDER], 0,
+ playback->priv->position, buffer, ! identical);
+ if (buffer)
+ g_object_unref (buffer);
+}
+
+void
+animation_playback_jump (AnimationPlayback *playback,
+ gint index)
+{
+ Animation *animation = playback->priv->animation;
+ GeglBuffer *buffer = NULL;
+ gint prev_pos = playback->priv->position;
+ gboolean identical;
+
+ if (! playback->priv->animation)
+ return;
+
+ if (index < playback->priv->start ||
+ index > playback->priv->stop)
+ return;
+ else
+ playback->priv->position = index;
+
+ identical = ANIMATION_GET_CLASS (animation)->same (animation,
+ prev_pos,
+ playback->priv->position);
+ if (! identical)
+ {
+ buffer = animation_get_frame (animation, playback->priv->position);
+ }
+ g_signal_emit (playback, animation_playback_signals[RENDER], 0,
+ playback->priv->position, buffer, ! identical);
+ if (buffer)
+ g_object_unref (buffer);
+}
+
+void
+animation_playback_set_start (AnimationPlayback *playback,
+ gint index)
+{
+ gint duration;
+
+ if (! playback->priv->animation)
+ return;
+
+ duration = animation_get_duration (playback->priv->animation);
+
+ if (index < 0 ||
+ index >= duration)
+ {
+ playback->priv->start = 0;
+ }
+ else
+ {
+ playback->priv->start = index;
+ }
+ if (playback->priv->stop < playback->priv->start)
+ {
+ playback->priv->stop = duration - 1;
+ }
+
+ g_signal_emit (playback, animation_playback_signals[RANGE], 0,
+ playback->priv->start, playback->priv->stop);
+
+ if (playback->priv->position < playback->priv->start ||
+ playback->priv->position > playback->priv->stop)
+ {
+ animation_playback_jump (playback, playback->priv->start);
+ }
+}
+
+gint
+animation_playback_get_start (AnimationPlayback *playback)
+{
+ return playback->priv->start;
+}
+
+void
+animation_playback_set_stop (AnimationPlayback *playback,
+ gint index)
+{
+ gint duration;
+
+ if (! playback->priv->animation)
+ return;
+
+ duration = animation_get_duration (playback->priv->animation);
+
+ if (index < 0 ||
+ index >= duration)
+ {
+ playback->priv->stop = duration - 1;
+ }
+ else
+ {
+ playback->priv->stop = index;
+ }
+ if (playback->priv->stop < playback->priv->start)
+ {
+ playback->priv->start = 0;
+ }
+ g_signal_emit (playback, animation_playback_signals[RANGE], 0,
+ playback->priv->start, playback->priv->stop);
+
+ if (playback->priv->position < playback->priv->start ||
+ playback->priv->position > playback->priv->stop)
+ {
+ animation_playback_jump (playback, playback->priv->start);
+ }
+}
+
+gint
+animation_playback_get_stop (AnimationPlayback *playback)
+{
+ return playback->priv->stop;
+}
+
+/************ Private Functions ****************/
+
+static void
+animation_playback_finalize (GObject *object)
+{
+ AnimationPlayback *playback = ANIMATION_PLAYBACK (object);
+
+ if (playback->priv->animation)
+ g_object_unref (playback->priv->animation);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+animation_playback_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationPlayback *playback = ANIMATION_PLAYBACK (object);
+
+ switch (property_id)
+ {
+ case PROP_ANIMATION:
+ {
+ Animation *animation;
+ GeglBuffer *buffer;
+
+ if (playback->priv->animation)
+ g_object_unref (playback->priv->animation);
+
+ animation = g_value_dup_object (value);
+ playback->priv->animation = animation;
+
+ if (! animation)
+ break;
+
+ if (! animation_loaded (animation))
+ animation_load (animation);
+ /* Default playback is the full range of frames. */
+ playback->priv->position = 0;
+ playback->priv->start = 0;
+ playback->priv->stop = animation_get_duration (animation) - 1;
+
+ g_signal_emit_by_name (animation, "loaded");
+ g_signal_connect (animation, "cache-invalidated",
+ G_CALLBACK (on_cache_invalidated), playback);
+
+ /* Once loaded, let's ask render. */
+ buffer = animation_get_frame (animation, playback->priv->position);
+ g_signal_emit (playback, animation_playback_signals[RENDER], 0,
+ playback->priv->position, buffer, TRUE);
+
+ if (buffer)
+ g_object_unref (buffer);
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+animation_playback_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationPlayback *playback = ANIMATION_PLAYBACK (object);
+
+ switch (property_id)
+ {
+ case PROP_ANIMATION:
+ g_value_set_object (value, playback->priv->animation);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+on_cache_invalidated (Animation *animation,
+ gint position,
+ gint length,
+ AnimationPlayback *playback)
+{
+ gint cur_position;
+
+ cur_position = animation_playback_get_position (playback);
+
+ if (cur_position >= position &&
+ cur_position < position + length)
+ {
+ GeglBuffer *buffer;
+
+ buffer = animation_get_frame (animation, cur_position);
+ g_signal_emit_by_name (playback, "render",
+ cur_position, buffer, TRUE);
+ if (buffer)
+ {
+ g_object_unref (buffer);
+ }
+ }
+}
+
+static gboolean
+animation_playback_advance_frame_callback (AnimationPlayback *playback)
+{
+ gdouble framerate;
+ gint64 duration;
+ gint64 duration_since_start;
+ static gboolean prev_low_framerate = FALSE;
+
+ framerate = animation_get_framerate (playback->priv->animation);
+
+ animation_playback_next (playback);
+ duration = (gint) (1000.0 / framerate);
+
+ duration_since_start = (g_get_monotonic_time () - playback->priv->start_time) / 1000;
+ duration = duration - (duration_since_start - playback->priv->frames_played * duration);
+
+ if (duration < 1)
+ {
+ if (prev_low_framerate)
+ {
+ /* Let's only warn the user for several subsequent slow frames. */
+ gdouble real_framerate;
+
+ real_framerate = (gdouble) playback->priv->frames_played * 1000.0 / duration_since_start;
+
+ if (real_framerate < framerate)
+ g_signal_emit (playback, animation_playback_signals[LOW_FRAMERATE], 0,
+ real_framerate);
+ }
+ duration = 1;
+ prev_low_framerate = TRUE;
+ }
+ else
+ {
+ if (prev_low_framerate)
+ {
+ /* Let's reset framerate warning. */
+ g_signal_emit (playback, animation_playback_signals[LOW_FRAMERATE], 0,
+ framerate);
+ }
+ prev_low_framerate = FALSE;
+ }
+ playback->priv->frames_played++;
+
+ playback->priv->timer = g_timeout_add ((guint) duration,
+ (GSourceFunc) animation_playback_advance_frame_callback,
+ (AnimationPlayback *) playback);
+
+ return G_SOURCE_REMOVE;
+}
diff --git a/plug-ins/animation-play/core/animation-playback.h
b/plug-ins/animation-play/core/animation-playback.h
new file mode 100644
index 0000000..e7ba300
--- /dev/null
+++ b/plug-ins/animation-play/core/animation-playback.h
@@ -0,0 +1,86 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * animation_playback.h
+ * Copyright (C) 2016 Jehan <jehan gimp org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ANIMATION_PLAYBACK_H__
+#define __ANIMATION_PLAYBACK_H__
+
+#define ANIMATION_TYPE_PLAYBACK (animation_playback_get_type ())
+#define ANIMATION_PLAYBACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANIMATION_TYPE_PLAYBACK,
AnimationPlayback))
+#define ANIMATION_PLAYBACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANIMATION_TYPE_PLAYBACK,
AnimationPlaybackClass))
+#define ANIMATION_IS_PLAYBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANIMATION_TYPE_PLAYBACK))
+#define ANIMATION_IS_PLAYBACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANIMATION_TYPE_PLAYBACK))
+#define ANIMATION_PLAYBACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANIMATION_TYPE_PLAYBACK,
AnimationPlaybackClass))
+
+typedef struct _AnimationPlayback AnimationPlayback;
+typedef struct _AnimationPlaybackClass AnimationPlaybackClass;
+typedef struct _AnimationPlaybackPrivate AnimationPlaybackPrivate;
+
+struct _AnimationPlayback
+{
+ GObject parent_instance;
+
+ AnimationPlaybackPrivate *priv;
+};
+
+struct _AnimationPlaybackClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*start) (AnimationPlayback *playback);
+ void (*stop) (AnimationPlayback *playback);
+ void (*range) (AnimationPlayback *playback,
+ gint start,
+ gint stop);
+ void (*render) (AnimationPlayback *playback,
+ gint position,
+ GeglBuffer *buffer,
+ gboolean must_draw_null);
+ void (*low_framerate) (AnimationPlayback *playback,
+ gdouble actual_fps);
+};
+
+GType animation_playback_get_type (void);
+
+AnimationPlayback * animation_playback_new (void);
+
+void animation_playback_set_animation (AnimationPlayback *playback,
+ Animation *animation);
+Animation * animation_playback_get_animation (AnimationPlayback *playback);
+
+gint animation_playback_get_position (AnimationPlayback *playback);
+
+gboolean animation_playback_is_playing (AnimationPlayback *playback);
+void animation_playback_play (AnimationPlayback *playback);
+void animation_playback_stop (AnimationPlayback *playback);
+void animation_playback_next (AnimationPlayback *playback);
+void animation_playback_prev (AnimationPlayback *playback);
+void animation_playback_jump (AnimationPlayback *playback,
+ gint index);
+
+void animation_playback_set_start (AnimationPlayback *playback,
+ gint index);
+gint animation_playback_get_start (AnimationPlayback *playback);
+
+void animation_playback_set_stop (AnimationPlayback *playback,
+ gint index);
+gint animation_playback_get_stop (AnimationPlayback *playback);
+
+#endif /* __ANIMATION_PLAYBACK_H__ */
diff --git a/plug-ins/animation-play/core/animation.c b/plug-ins/animation-play/core/animation.c
index ad7a8cc..0f6c8f1 100644
--- a/plug-ins/animation-play/core/animation.c
+++ b/plug-ins/animation-play/core/animation.c
@@ -42,16 +42,12 @@ CachedSettings;
enum
{
- LOADING_START,
LOADING,
LOADED,
- START,
- STOP,
+ CACHE_INVALIDATED,
+ DURATION_CHANGED,
FRAMERATE_CHANGED,
- PLAYBACK_RANGE,
- RENDER,
- LOW_FRAMERATE,
- PROXY,
+ PROXY_CHANGED,
LAST_SIGNAL
};
@@ -65,26 +61,15 @@ typedef struct _AnimationPrivate AnimationPrivate;
struct _AnimationPrivate
{
- gint32 image_id;
- gchar *xml;
+ gint32 image_id;
+ gchar *xml;
- gdouble framerate;
-
- guint playback_timer;
-
- /* State of the currently loaded animation. */
- gint position;
- /* Playback can be a subset of frames. */
- guint playback_start;
- guint playback_stop;
+ gdouble framerate;
/* Proxy settings generates a reload. */
- gdouble proxy_ratio;
+ gdouble proxy_ratio;
- gboolean loaded;
-
- gint64 playback_start_time;
- gint64 frames_played;
+ gboolean loaded;
};
@@ -93,6 +78,7 @@ struct _AnimationPrivate
ANIMATION_TYPE_ANIMATION, \
AnimationPrivate)
+static void animation_finalize (GObject *object);
static void animation_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -103,12 +89,9 @@ static void animation_get_property (GObject *object,
GParamSpec *pspec);
/* Base implementation of virtual methods. */
-static gboolean animation_real_same (Animation *animation,
- gint prev_pos,
- gint next_pos);
-
-/* Timer callback for playback. */
-static gboolean animation_advance_frame_callback (Animation *animation);
+static gboolean animation_real_same (Animation *animation,
+ gint prev_pos,
+ gint next_pos);
G_DEFINE_TYPE (Animation, animation, G_TYPE_OBJECT)
@@ -122,37 +105,22 @@ animation_class_init (AnimationClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
/**
- * Animation::loading-start:
- * @animation: the animation loading.
- *
- * The ::loading-start signal is emitted when loading starts.
- * GUI widgets depending on a consistent state of @animation should
- * become unresponsive.
- */
- animation_signals[LOADING_START] =
- g_signal_new ("loading-start",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 0);
- /**
* Animation::loading:
* @animation: the animation loading.
* @ratio: fraction loaded [0-1].
*
- * The ::loading signal must be emitted by subclass of Animation.
+ * The ::loading signal must be emitted by a subclass of Animation.
* It can be used by a GUI to display a progress bar during loading.
+ * GUI widgets depending on a consistent state of @animation should
+ * become unresponsive.
*/
animation_signals[LOADING] =
g_signal_new ("loading",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
- 0,
+ G_STRUCT_OFFSET (AnimationClass, loading),
NULL, NULL,
- NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE,
1,
G_TYPE_DOUBLE);
@@ -160,8 +128,6 @@ animation_class_init (AnimationClass *klass)
* Animation::loaded:
* @animation: the animation loading.
* @duration: number of frames.
- * @playback_start: the playback start frame.
- * @playback_stop: the playback last frame.
* @width: display width in pixels.
* @height: display height in pixels.
*
@@ -173,125 +139,64 @@ animation_class_init (AnimationClass *klass)
g_signal_new ("loaded",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
- 0,
+ G_STRUCT_OFFSET (AnimationClass, loaded),
NULL, NULL,
- NULL,
+ g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
- 5,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INT);
+ 0);
/**
- * Animation::render:
+ * Animation::cache-invalidated:
* @animation: the animation.
- * @position: current position to be rendered.
- * @buffer: the #GeglBuffer for the frame at @position.
- * @must_draw_null: meaning of a %NULL @buffer.
- * %TRUE means we have to draw an empty frame.
- * %FALSE means the new frame is same as the current frame.
+ * @position: the first frame position whose cache is invalid.
+ * @length: the number of invalidated frames from @position.
*
- * Sends a request for render to the GUI.
+ * The ::cache-invalidated signal must be emitted when the contents
+ * of one or more successive frames change.
*/
- animation_signals[RENDER] =
- g_signal_new ("render",
+ animation_signals[CACHE_INVALIDATED] =
+ g_signal_new ("cache-invalidated",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
- 0,
+ G_STRUCT_OFFSET (AnimationClass, cache_invalidated),
NULL, NULL,
NULL,
G_TYPE_NONE,
- 3,
+ 2,
G_TYPE_INT,
- GEGL_TYPE_BUFFER,
- G_TYPE_BOOLEAN);
- /**
- * Animation::start:
- * @animation: the animation.
- *
- * The @animation starts to play.
- */
- animation_signals[START] =
- g_signal_new ("start",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 0);
+ G_TYPE_INT);
/**
- * Animation::stops:
+ * Animation::duration:
* @animation: the animation.
+ * @duration: the new duration of @animation in number of frames.
*
- * The @animation stops playing.
+ * The ::playback-range signal must be emitted when the duration of
+ * @animation changes.
*/
- animation_signals[STOP] =
- g_signal_new ("stop",
+ animation_signals[DURATION_CHANGED] =
+ g_signal_new ("duration-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
- 0,
+ G_STRUCT_OFFSET (AnimationClass, duration_changed),
NULL, NULL,
- NULL,
+ g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
- 0);
+ 1,
+ G_TYPE_INT);
/**
* Animation::framerate-changed:
* @animation: the animation.
- * @framerate: the new framerate in frames per second.
+ * @framerate: the new framerate of @animation in frames per second.
*
- * The ::framerate-changed signal is emitted when framerate has
- * changed.
+ * The ::playback-range signal is emitted when the framerate of
+ * @animation changes.
*/
animation_signals[FRAMERATE_CHANGED] =
g_signal_new ("framerate-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 1,
- G_TYPE_DOUBLE);
- /**
- * Animation::playback-range:
- * @animation: the animation.
- * @playback_start: the playback start frame.
- * @playback_stop: the playback last frame.
- * @playback_duration: the playback duration (in frames).
- *
- * The ::playback-range signal is emitted when the playback range is
- * updated.
- */
- animation_signals[PLAYBACK_RANGE] =
- g_signal_new ("playback-range",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 3,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INT);
- /**
- * Animation::low-framerate:
- * @animation: the animation.
- * @actual_fps: the current playback framerate in fps.
- *
- * The ::low-framerate signal is emitted when the playback framerate
- * is lower than expected. It is also emitted once when the framerate
- * comes back to acceptable rate.
- */
- animation_signals[LOW_FRAMERATE] =
- g_signal_new ("low-framerate-playback",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_FIRST,
- 0,
+ G_STRUCT_OFFSET (AnimationClass, framerate_changed),
NULL, NULL,
- NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE,
1,
G_TYPE_DOUBLE);
@@ -302,17 +207,18 @@ animation_class_init (AnimationClass *klass)
*
* The ::proxy signal is emitted to announce a change of proxy size.
*/
- animation_signals[PROXY] =
- g_signal_new ("proxy",
+ animation_signals[PROXY_CHANGED] =
+ g_signal_new ("proxy-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
- 0,
+ G_STRUCT_OFFSET (AnimationClass, proxy),
NULL, NULL,
- NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE,
1,
G_TYPE_DOUBLE);
+ object_class->finalize = animation_finalize;
object_class->set_property = animation_set_property;
object_class->get_property = animation_get_property;
@@ -345,7 +251,7 @@ animation_init (Animation *animation)
gimp_get_data (PLUG_IN_PROC, &settings);
/* Acceptable settings for the default. */
- priv->framerate = settings.framerate; /* fps */
+ priv->framerate = settings.framerate;
priv->proxy_ratio = 1.0;
}
@@ -370,7 +276,7 @@ animation_new (gint32 image_id,
}
gint32
-animation_get_image_id (Animation *animation)
+animation_get_image_id (Animation *animation)
{
AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
@@ -381,47 +287,25 @@ void
animation_load (Animation *animation)
{
AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- GeglBuffer *buffer;
- gint width, height;
- gint duration;
priv->loaded = FALSE;
- g_signal_emit (animation, animation_signals[LOADING_START], 0);
+ g_signal_emit (animation, animation_signals[LOADING], 0, 0.0);
if (priv->xml)
ANIMATION_GET_CLASS (animation)->load_xml (animation,
priv->xml);
else
ANIMATION_GET_CLASS (animation)->load (animation);
+
/* XML is only used for the first load.
* Any next loads will use internal data. */
g_free (priv->xml);
priv->xml = NULL;
- duration = ANIMATION_GET_CLASS (animation)->get_duration (animation);
- priv->position = 0;
-
- /* Default playback is the full range of frames. */
- priv->playback_start = 0;
- priv->playback_stop = duration - 1;
-
priv->loaded = TRUE;
- animation_get_size (animation, &width, &height);
- g_signal_emit (animation, animation_signals[LOADED], 0,
- duration,
- priv->playback_start,
- priv->playback_stop,
- width,
- height);
-
- /* Once loaded, let's ask render. */
- buffer = animation_get_frame (animation, priv->position);
- g_signal_emit (animation, animation_signals[RENDER], 0,
- priv->position, buffer, TRUE);
-
- if (buffer)
- g_object_unref (buffer);
+ /* XXX */
+ /*g_signal_emit (animation, animation_signals[LOADED], 0);*/
}
void
@@ -502,14 +386,6 @@ animation_save_to_parasite (Animation *animation)
}
gint
-animation_get_position (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
-
- return priv->position;
-}
-
-gint
animation_get_duration (Animation *animation)
{
return ANIMATION_GET_CLASS (animation)->get_duration (animation);
@@ -526,7 +402,7 @@ animation_set_proxy (Animation *animation,
if (priv->proxy_ratio != ratio)
{
priv->proxy_ratio = ratio;
- g_signal_emit (animation, animation_signals[PROXY], 0, ratio);
+ g_signal_emit (animation, animation_signals[PROXY_CHANGED], 0, ratio);
/* A proxy change implies a reload. */
animation_load (animation);
@@ -569,222 +445,6 @@ animation_get_frame (Animation *animation,
return ANIMATION_GET_CLASS (animation)->get_frame (animation, pos);
}
-gboolean
-animation_is_playing (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
-
- return (priv->playback_timer != 0);
-}
-
-void
-animation_play (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- gint duration;
-
- duration = (gint) (1000.0 / animation_get_framerate (animation));
-
- if (priv->playback_timer)
- {
- /* It means we are already playing, so we should not need to play
- * again.
- * Still be liberal and simply remove the timer before creating a
- * new one. */
- g_source_remove (priv->playback_timer);
- }
-
- priv->playback_start_time = g_get_monotonic_time ();
- priv->frames_played = 1;
-
- priv->playback_timer = g_timeout_add ((guint) duration,
- (GSourceFunc) animation_advance_frame_callback,
- animation);
- g_signal_emit (animation, animation_signals[START], 0);
-}
-
-void
-animation_stop (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
-
- if (priv->playback_timer)
- {
- /* Stop playing by removing any playback timer. */
- g_source_remove (priv->playback_timer);
- priv->playback_timer = 0;
- g_signal_emit (animation, animation_signals[STOP], 0);
- }
-}
-
-void
-animation_next (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- GeglBuffer *buffer = NULL;
- gint previous_pos = priv->position;
- gboolean identical;
-
- priv->position = animation_get_playback_start (animation) +
- ((priv->position - animation_get_playback_start (animation) + 1) %
- (animation_get_playback_stop (animation) - animation_get_playback_start (animation) +
1));
-
- identical = ANIMATION_GET_CLASS (animation)->same (animation,
- previous_pos,
- priv->position);
- if (! identical)
- {
- buffer = animation_get_frame (animation, priv->position);
- }
- g_signal_emit (animation, animation_signals[RENDER], 0,
- priv->position, buffer, ! identical);
- if (buffer != NULL)
- {
- g_object_unref (buffer);
- }
-}
-
-void
-animation_prev (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- GeglBuffer *buffer = NULL;
- gint prev_pos = priv->position;
- gboolean identical;
-
- if (priv->position == animation_get_playback_start (animation))
- {
- priv->position = animation_get_playback_stop (animation);
- }
- else
- {
- --priv->position;
- }
-
- identical = ANIMATION_GET_CLASS (animation)->same (animation,
- prev_pos,
- priv->position);
- if (! identical)
- {
- buffer = animation_get_frame (animation, priv->position);
- }
- g_signal_emit (animation, animation_signals[RENDER], 0,
- priv->position, buffer, ! identical);
- if (buffer)
- g_object_unref (buffer);
-}
-
-void
-animation_jump (Animation *animation,
- gint index)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- GeglBuffer *buffer = NULL;
- gint prev_pos = priv->position;
- gboolean identical;
-
- if (index < priv->playback_start ||
- index > priv->playback_stop)
- return;
- else
- priv->position = index;
-
- identical = ANIMATION_GET_CLASS (animation)->same (animation,
- prev_pos,
- priv->position);
- if (! identical)
- {
- buffer = animation_get_frame (animation, priv->position);
- }
- g_signal_emit (animation, animation_signals[RENDER], 0,
- priv->position, buffer, ! identical);
- if (buffer)
- g_object_unref (buffer);
-}
-
-void
-animation_set_playback_start (Animation *animation,
- gint frame_number)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- gint duration;
-
- duration = animation_get_duration (animation);
-
- if (frame_number < 0 ||
- frame_number >= duration)
- {
- priv->playback_start = 0;
- }
- else
- {
- priv->playback_start = frame_number;
- }
- if (priv->playback_stop < priv->playback_start)
- {
- priv->playback_stop = duration - 1;
- }
-
- g_signal_emit (animation, animation_signals[PLAYBACK_RANGE], 0,
- priv->playback_start, priv->playback_stop,
- duration);
-
- if (priv->position < priv->playback_start ||
- priv->position > priv->playback_stop)
- {
- animation_jump (animation, priv->playback_start);
- }
-}
-
-gint
-animation_get_playback_start (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
-
- return priv->playback_start;
-}
-
-void
-animation_set_playback_stop (Animation *animation,
- gint frame_number)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- gint duration;
-
- duration = animation_get_duration (animation);
-
- if (frame_number < 0 ||
- frame_number >= duration)
- {
- priv->playback_stop = duration - 1;
- }
- else
- {
- priv->playback_stop = frame_number;
- }
- if (priv->playback_stop < priv->playback_start)
- {
- priv->playback_start = 0;
- }
- g_signal_emit (animation, animation_signals[PLAYBACK_RANGE], 0,
- priv->playback_start, priv->playback_stop,
- duration);
-
- if (priv->position < priv->playback_start ||
- priv->position > priv->playback_stop)
- {
- animation_jump (animation, priv->playback_start);
- }
-}
-
-gint
-animation_get_playback_stop (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
-
- return priv->playback_stop;
-}
-
void
animation_set_framerate (Animation *animation,
gdouble fps)
@@ -818,6 +478,18 @@ animation_loaded (Animation *animation)
/************ Private Functions ****************/
static void
+animation_finalize (GObject *object)
+{
+ Animation *animation = ANIMATION (object);
+ AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
+
+ if (priv->xml)
+ g_free (priv->xml);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
animation_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -867,49 +539,3 @@ animation_real_same (Animation *animation,
/* By default all frames are supposed different. */
return (previous_pos == next_pos);
}
-
-static gboolean
-animation_advance_frame_callback (Animation *animation)
-{
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
- gint64 duration;
- gint64 duration_since_start;
- static gboolean prev_low_framerate = FALSE;
-
- animation_next (animation);
- duration = (gint) (1000.0 / animation_get_framerate (animation));
-
- duration_since_start = (g_get_monotonic_time () - priv->playback_start_time) / 1000;
- duration = duration - (duration_since_start - priv->frames_played * duration);
-
- if (duration < 1)
- {
- if (prev_low_framerate)
- {
- /* Let's only warn the user for several subsequent slow frames. */
- gdouble real_framerate = (gdouble) priv->frames_played * 1000.0 / duration_since_start;
- if (real_framerate < priv->framerate)
- g_signal_emit (animation, animation_signals[LOW_FRAMERATE], 0,
- real_framerate);
- }
- duration = 1;
- prev_low_framerate = TRUE;
- }
- else
- {
- if (prev_low_framerate)
- {
- /* Let's reset framerate warning. */
- g_signal_emit (animation, animation_signals[LOW_FRAMERATE], 0,
- animation_get_framerate (animation));
- }
- prev_low_framerate = FALSE;
- }
- priv->frames_played++;
-
- priv->playback_timer = g_timeout_add ((guint) duration,
- (GSourceFunc) animation_advance_frame_callback,
- (Animation *) animation);
-
- return G_SOURCE_REMOVE;
-}
diff --git a/plug-ins/animation-play/core/animation.h b/plug-ins/animation-play/core/animation.h
index cf826b5..de47fbc 100644
--- a/plug-ins/animation-play/core/animation.h
+++ b/plug-ins/animation-play/core/animation.h
@@ -40,22 +40,35 @@ struct _AnimationClass
{
GObjectClass parent_class;
+ /* Signals */
+ void (*loading) (Animation *animation,
+ gdouble ratio);
+ void (*loaded) (Animation *animation);
+
+ void (*cache_invalidated) (Animation *animation,
+ gint position);
+ void (*duration_changed) (Animation *animation,
+ gint duration);
+ void (*framerate_changed) (Animation *animation,
+ gdouble fps);
+ void (*proxy) (Animation *animation,
+ gdouble ratio);
+
/* Defaults to returning FALSE for any different position. */
gboolean (*same) (Animation *animation,
gint prev_pos,
gint next_pos);
/* These virtual methods must be implemented by any subclass. */
- void (*load) (Animation *animation);
- void (*load_xml) (Animation *animation,
- const gchar *xml);
- gint (*get_duration) (Animation *animation);
-
+ void (*load) (Animation *animation);
+ void (*load_xml) (Animation *animation,
+ const gchar *xml);
+ gint (*get_duration) (Animation *animation);
- GeglBuffer * (*get_frame) (Animation *animation,
- gint pos);
+ GeglBuffer * (*get_frame) (Animation *animation,
+ gint pos);
- gchar * (*serialize) (Animation *animation);
+ gchar * (*serialize) (Animation *animation);
};
GType animation_get_type (void);
@@ -70,7 +83,6 @@ void animation_load (Animation *animation);
void animation_save_to_parasite (Animation *animation);
-gint animation_get_position (Animation *animation);
gint animation_get_duration (Animation *animation);
void animation_set_proxy (Animation *animation,
@@ -83,22 +95,6 @@ void animation_get_size (Animation *animation,
GeglBuffer * animation_get_frame (Animation *animation,
gint frame_number);
-
-gboolean animation_is_playing (Animation *animation);
-void animation_play (Animation *animation);
-void animation_stop (Animation *animation);
-void animation_next (Animation *animation);
-void animation_prev (Animation *animation);
-void animation_jump (Animation *animation,
- gint index);
-
-void animation_set_playback_start (Animation *animation,
- gint frame_number);
-gint animation_get_playback_start (Animation *animation);
-void animation_set_playback_stop (Animation *animation,
- gint frame_number);
-gint animation_get_playback_stop (Animation *animation);
-
void animation_set_framerate (Animation *animation,
gdouble fps);
gdouble animation_get_framerate (Animation *animation);
diff --git a/plug-ins/animation-play/core/animationanimatic.c
b/plug-ins/animation-play/core/animationanimatic.c
index 756876a..e792648 100644
--- a/plug-ins/animation-play/core/animationanimatic.c
+++ b/plug-ins/animation-play/core/animationanimatic.c
@@ -79,7 +79,7 @@ struct _AnimationAnimaticPrivate
ANIMATION_TYPE_ANIMATIC, \
AnimationAnimaticPrivate)
-static void animation_animatic_finalize (GObject *object);
+static void animation_animatic_finalize (GObject *object);
/* Virtual methods */
@@ -99,11 +99,11 @@ static gboolean animation_animatic_same (Animation *animatio
/* 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);
+ 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,
@@ -120,8 +120,6 @@ static void animation_animatic_text (GMarkupParseContext *context
static void animation_animatic_cache (AnimationAnimatic *animation,
gint panel,
gboolean recursion);
-static gint animation_animatic_get_layer (AnimationAnimatic *animation,
- gint pos);
/* Tag handling (from layer names) */
@@ -229,50 +227,19 @@ animation_animatic_set_panel_duration (AnimationAnimatic *animatic,
{
AnimationAnimaticPrivate *priv = GET_PRIVATE (animatic);
Animation *animation = ANIMATION (animatic);
- gint prev_length = animation_get_duration (animation);
- gint playback_start = animation_get_playback_start (animation);
- gint playback_stop = animation_get_playback_stop (animation);
- gint position = animation_get_position (animation);
- gint layer_id;
- gint length;
+ gint duration;
g_return_if_fail (panel_duration >= 0 &&
panel_num >= 0 &&
panel_num < priv->n_panels);
- layer_id = animation_animatic_get_layer (animatic, position);
-
priv->durations[panel_num] = panel_duration;
- length = animation_get_duration (animation);
+ duration = animation_get_duration (animation);
- if (playback_start >= length)
- {
- playback_start = 0;
- }
- if (playback_stop >= length ||
- playback_stop == prev_length - 1)
- {
- playback_stop = length - 1;
- }
g_signal_emit (animatic, signals[PANEL_DURATION], 0,
panel_num, panel_duration);
- g_signal_emit_by_name (animatic, "playback-range",
- playback_start, playback_stop,
- animation_get_duration (animation));
- if (position >= length)
- {
- animation_jump (animation, length - 1);
- }
- else if (layer_id != animation_animatic_get_layer (animatic, position))
- {
- GeglBuffer *buffer;
-
- buffer = animation_get_frame (animation, position);
- g_signal_emit_by_name (animation, "render",
- position, buffer, TRUE);
- if (buffer)
- g_object_unref (buffer);
- }
+ g_signal_emit_by_name (animation, "duration-changed",
+ duration);
}
gint
@@ -313,6 +280,7 @@ animation_animatic_get_comment (AnimationAnimatic *animatic,
g_return_val_if_fail (panel_num >= 0 &&
panel_num < priv->n_panels,
0);
+
return priv->comments[panel_num];
}
@@ -342,6 +310,7 @@ animation_animatic_get_combine (AnimationAnimatic *animatic,
g_return_val_if_fail (panel_num >= 0 &&
panel_num < priv->n_panels,
FALSE);
+
return priv->combine[panel_num];
}
@@ -370,22 +339,23 @@ animation_animatic_get_panel (AnimationAnimatic *animation,
return -1;
}
-void animation_animatic_jump_panel (AnimationAnimatic *animation,
- gint panel)
+gint
+animation_animatic_get_position (AnimationAnimatic *animation,
+ gint panel)
{
AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
- /* Get the first frame position for a given panel. */
gint pos = 0;
gint i;
- g_return_if_fail (panel < priv->n_panels);
+ g_return_val_if_fail (panel < priv->n_panels,
+ priv->n_panels - 1);
for (i = 0; i < panel; i++)
{
pos += priv->durations[i];
}
- animation_jump (ANIMATION (animation), pos);
+ return pos;
}
/**** Virtual methods ****/
@@ -868,7 +838,7 @@ animation_animatic_cache (AnimationAnimatic *animatic,
GeglBuffer *backdrop_buffer = NULL;
gint layer_offx;
gint layer_offy;
- gint position;
+ /*gint position;*/
gint preview_width;
gint preview_height;
gint32 image_id;
@@ -907,6 +877,11 @@ animation_animatic_cache (AnimationAnimatic *animatic,
layer_offx, layer_offy);
g_object_unref (buffer);
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ animation_animatic_get_position (animatic,
+ panel),
+ 1);
+
/* If next panel is in "combine" mode, it must also be re-cached.
* And so on, recursively. */
if (recursion &&
@@ -915,42 +890,6 @@ animation_animatic_cache (AnimationAnimatic *animatic,
{
animation_animatic_cache (animatic, panel + 1, TRUE);
}
-
- /* Finally re-render if we are currently showing this panel. */
- position = animation_get_position (animation);
- if (animation_animatic_get_panel (animatic, position) == panel)
- {
- buffer = animation_get_frame (animation, position);
- g_signal_emit_by_name (animation, "render",
- position, buffer, TRUE);
- if (buffer)
- {
- g_object_unref (buffer);
- }
- }
-}
-
-static gint
-animation_animatic_get_layer (AnimationAnimatic *animation,
- gint pos)
-{
- AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
- gint count = 0;
- gint i = -1;
-
- if (priv->n_panels > 0 &&
- pos >= 0 &&
- pos < animation_animatic_get_duration (ANIMATION (animation)))
- {
- for (i = priv->n_panels - 1; i >= 0; i--)
- {
- count += priv->durations[i];
- if (count >= pos)
- break;
- }
- }
-
- return i;
}
/**** TAG UTILS ****/
diff --git a/plug-ins/animation-play/core/animationanimatic.h
b/plug-ins/animation-play/core/animationanimatic.h
index 12e6180..fccd85c 100644
--- a/plug-ins/animation-play/core/animationanimatic.h
+++ b/plug-ins/animation-play/core/animationanimatic.h
@@ -46,25 +46,26 @@ struct _AnimationAnimaticClass
GType animation_animatic_get_type (void);
void animation_animatic_set_panel_duration (AnimationAnimatic *animatic,
- gint panel_num,
+ gint panel,
gint duration);
gint animation_animatic_get_panel_duration (AnimationAnimatic *animatic,
- gint panel_num);
+ gint panel);
-void animation_animatic_set_comment (AnimationAnimatic *animatic,
- gint panel_num,
- const gchar *comment);
-const gchar * animation_animatic_get_comment (AnimationAnimatic *animatic,
- gint panel_num);
+void animation_animatic_set_comment (AnimationAnimatic *animatic,
+ gint panel,
+ const gchar *comment);
+const gchar * animation_animatic_get_comment (AnimationAnimatic *animatic,
+ gint panel);
-void animation_animatic_set_combine (AnimationAnimatic *animatic,
- gint panel_num,
- gboolean combine);
-const gboolean animation_animatic_get_combine (AnimationAnimatic *animatic,
- gint panel_num);
+void animation_animatic_set_combine (AnimationAnimatic *animatic,
+ gint panel,
+ gboolean combine);
+const gboolean animation_animatic_get_combine (AnimationAnimatic *animatic,
+ gint panel);
+
+gint animation_animatic_get_panel (AnimationAnimatic *animation,
+ gint pos);
+gint animation_animatic_get_position (AnimationAnimatic *animation,
+ gint panel);
-gint animation_animatic_get_panel (AnimationAnimatic *animation,
- gint pos);
-void animation_animatic_jump_panel (AnimationAnimatic *animation,
- gint panel);
#endif /* __ANIMATION_ANIMATIC_H__ */
diff --git a/plug-ins/animation-play/widgets/animation-dialog.c
b/plug-ins/animation-play/widgets/animation-dialog.c
index 184ba87..35d8f3d 100755
--- a/plug-ins/animation-play/widgets/animation-dialog.c
+++ b/plug-ins/animation-play/widgets/animation-dialog.c
@@ -31,6 +31,7 @@
#include "core/animation.h"
#include "core/animationanimatic.h"
#include "core/animation-celanimation.h"
+#include "core/animation-playback.h"
#include "animation-dialog.h"
#include "animation-layer-view.h"
@@ -57,54 +58,55 @@ typedef struct _AnimationDialogPrivate AnimationDialogPrivate;
struct _AnimationDialogPrivate
{
- gint32 image_id;
+ gint32 image_id;
- Animation *animation;
- gdouble zoom;
+ Animation *animation;
+ AnimationPlayback *playback;
+ gdouble zoom;
/* GUI */
- GtkWidget *play_bar;
- GtkWidget *progress_bar;
- GtkWidget *settings_bar;
+ GtkWidget *play_bar;
+ GtkWidget *progress_bar;
+ GtkWidget *settings_bar;
- GtkWidget *animation_type_combo;
- GtkWidget *fpscombo;
- GtkWidget *zoomcombo;
- GtkWidget *proxycombo;
+ GtkWidget *animation_type_combo;
+ GtkWidget *fpscombo;
+ GtkWidget *zoomcombo;
+ GtkWidget *proxycombo;
- GtkWidget *progress;
- GtkWidget *startframe_spin;
- GtkWidget *endframe_spin;
+ GtkWidget *progress;
+ GtkWidget *startframe_spin;
+ GtkWidget *endframe_spin;
- GtkWidget *view_bar;
- GtkWidget *refresh;
+ GtkWidget *view_bar;
+ GtkWidget *refresh;
- GtkWidget *drawing_area;
- guchar *drawing_area_data;
- guint drawing_area_width;
- guint drawing_area_height;
+ GtkWidget *drawing_area;
+ guchar *drawing_area_data;
+ guint drawing_area_width;
+ guint drawing_area_height;
- GtkWidget *shape_window;
- GtkWidget *shape_drawing_area;
- guchar *shape_drawing_area_data;
- guint shape_drawing_area_width;
- guint shape_drawing_area_height;
+ GtkWidget *shape_window;
+ GtkWidget *shape_drawing_area;
+ guchar *shape_drawing_area_data;
+ guint shape_drawing_area_width;
+ guint shape_drawing_area_height;
/* The hpaned (left is preview, right is layer list. */
- GtkWidget *hpaned;
- GtkWidget *layer_list;
+ GtkWidget *hpaned;
+ GtkWidget *layer_list;
/* The vpaned (bottom is timeline, above is preview). */
- GtkWidget *vpaned;
- GtkWidget *xsheet;
+ GtkWidget *vpaned;
+ GtkWidget *xsheet;
/* Actions */
- GtkUIManager *ui_manager;
+ GtkUIManager *ui_manager;
- GtkActionGroup *play_actions;
- GtkActionGroup *settings_actions;
- GtkActionGroup *view_actions;
- GtkActionGroup *various_actions;
+ GtkActionGroup *play_actions;
+ GtkActionGroup *settings_actions;
+ GtkActionGroup *view_actions;
+ GtkActionGroup *various_actions;
};
#define GET_PRIVATE(dialog) \
@@ -198,24 +200,14 @@ static gboolean popup_menu (GtkWidget *widget,
static void show_loading_progress (Animation *animation,
gdouble load_rate,
AnimationDialog *dialog);
-static void animation_update_progress (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- AnimationDialog *dialog);
-static void block_ui (Animation *animation,
- AnimationDialog *dialog);
static void unblock_ui (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- gint preview_width,
- gint preview_height,
AnimationDialog *dialog);
-static void playback_range_changed (Animation *animation,
+static void duration_changed (AnimationPlayback *playback,
+ gint duration,
+ AnimationDialog *dialog);
+static void playback_range_changed (AnimationPlayback *playback,
gint playback_start,
gint playback_stop,
- gint length,
AnimationDialog *dialog);
static void proxy_changed (Animation *animation,
gdouble fps,
@@ -223,7 +215,7 @@ static void proxy_changed (Animation *animation,
static void framerate_changed (Animation *animation,
gdouble fps,
AnimationDialog *dialog);
-static void low_framerate_cb (Animation *animation,
+static void low_framerate_cb (AnimationPlayback *playback,
gdouble real_framerate,
AnimationDialog *dialog);
@@ -244,7 +236,7 @@ static gboolean shape_released (GtkWidget *widget);
static gboolean shape_motion (GtkWidget *widget,
GdkEventMotion *event);
-static void render_callback (Animation *animation,
+static void render_callback (AnimationPlayback *animation,
gint frame_number,
GeglBuffer *buffer,
gboolean must_draw_null,
@@ -276,6 +268,8 @@ static void show_goto_progress (AnimationDialog *dialog,
static void show_playing_progress (AnimationDialog *dialog);
/* Utils */
+static void update_progress (AnimationDialog *dialog);
+static void block_ui (AnimationDialog *dialog);
static gboolean is_detached (AnimationDialog *dialog);
static void play_pause (AnimationDialog *dialog);
@@ -313,6 +307,9 @@ animation_dialog_class_init (AnimationDialogClass *klass)
static void
animation_dialog_init (AnimationDialog *dialog)
{
+ AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
+
+ priv->playback = animation_playback_new ();
}
/**** Public Functions ****/
@@ -326,7 +323,6 @@ animation_dialog_new (gint32 image_id)
const gchar *xml = NULL;
gboolean animatic_selected = TRUE;
- /* If this animation has specific settings already, override the global ones. */
parasite = gimp_image_get_parasite (image_id,
PLUG_IN_PROC "/selected");
if (parasite)
@@ -367,7 +363,6 @@ animation_dialog_new (gint32 image_id)
NULL);
animation_dialog_set_animation (ANIMATION_DIALOG (dialog),
animation);
- animation_load (animation);
return dialog;
}
@@ -861,6 +856,9 @@ animation_dialog_finalize (GObject *object)
if (priv->animation)
g_object_unref (priv->animation);
+ if (priv->playback)
+ g_object_unref (priv->playback);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
/* When this window ends, the plugin ends. */
@@ -1098,6 +1096,9 @@ animation_dialog_set_animation (AnimationDialog *dialog,
G_CALLBACK (framerate_changed),
dialog);
g_signal_handlers_disconnect_by_func (priv->animation,
+ G_CALLBACK (duration_changed),
+ dialog);
+ g_signal_handlers_disconnect_by_func (priv->playback,
G_CALLBACK (playback_range_changed),
dialog);
@@ -1105,15 +1106,12 @@ animation_dialog_set_animation (AnimationDialog *dialog,
(GCallback) show_loading_progress,
dialog);
g_signal_handlers_disconnect_by_func (priv->animation,
- (GCallback) block_ui,
- dialog);
- g_signal_handlers_disconnect_by_func (priv->animation,
(GCallback) unblock_ui,
dialog);
g_signal_handlers_disconnect_by_func (priv->animation,
G_CALLBACK (render_callback),
dialog);
- g_signal_handlers_disconnect_by_func (priv->animation,
+ g_signal_handlers_disconnect_by_func (priv->playback,
G_CALLBACK (low_framerate_cb),
dialog);
}
@@ -1168,7 +1166,7 @@ animation_dialog_set_animation (AnimationDialog *dialog,
G_CALLBACK (proxycombo_changed),
dialog);
/* Settings: fps */
- fps = animation_get_framerate (animation);
+ fps = animation_get_framerate (priv->animation);
gtk_combo_box_set_active (GTK_COMBO_BOX (priv->fpscombo), -1);
for (index = 0; index < 5; index++)
@@ -1242,7 +1240,8 @@ animation_dialog_set_animation (AnimationDialog *dialog,
gtk_frame_set_label (GTK_FRAME (frame), _("Storyboard"));
/* The Storyboard view. */
- storyboard = animation_storyboard_new (ANIMATION_ANIMATIC (animation));
+ storyboard = animation_storyboard_new (ANIMATION_ANIMATIC (animation),
+ priv->playback);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_win),
storyboard);
gtk_widget_show (storyboard);
@@ -1281,7 +1280,7 @@ animation_dialog_set_animation (AnimationDialog *dialog,
gtk_widget_show (frame);
priv->xsheet = animation_xsheet_new (ANIMATION_CEL_ANIMATION (animation),
- priv->layer_list);
+ priv->playback, priv->layer_list);
gtk_container_add (GTK_CONTAINER (frame), priv->xsheet);
gtk_widget_show (priv->xsheet);
}
@@ -1292,33 +1291,34 @@ animation_dialog_set_animation (AnimationDialog *dialog,
dialog);
/* Animation. */
- g_signal_connect (priv->animation, "proxy",
+ g_signal_connect (priv->animation, "proxy-changed",
G_CALLBACK (proxy_changed),
dialog);
g_signal_connect (priv->animation, "framerate-changed",
G_CALLBACK (framerate_changed),
dialog);
- g_signal_connect (priv->animation,
- "playback-range",
+ g_signal_connect (priv->animation, "duration-changed",
+ G_CALLBACK (duration_changed),
+ dialog);
+ g_signal_connect (priv->playback, "range",
G_CALLBACK (playback_range_changed),
dialog);
g_signal_connect (priv->animation, "loading",
(GCallback) show_loading_progress,
dialog);
- g_signal_connect (priv->animation, "loading-start",
- (GCallback) block_ui,
- dialog);
g_signal_connect (priv->animation, "loaded",
(GCallback) unblock_ui,
dialog);
- g_signal_connect (priv->animation, "render",
+ g_signal_connect (priv->playback, "render",
G_CALLBACK (render_callback),
dialog);
- g_signal_connect (priv->animation, "low-framerate-playback",
+ g_signal_connect (priv->playback, "low-framerate",
G_CALLBACK (low_framerate_cb),
dialog);
+ /* Set the playback */
+ animation_playback_set_animation (priv->playback, animation);
}
static void
@@ -1369,7 +1369,7 @@ update_ui_sensitivity (AnimationDialog *dialog)
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
gboolean animated;
- animated = animation_get_playback_stop (priv->animation) - animation_get_playback_start (priv->animation)
1;
+ animated = animation_playback_get_stop (priv->playback) - animation_playback_get_start (priv->playback) >
1;
/* Play actions only if we selected several frames between start/end. */
gtk_action_group_set_sensitive (priv->play_actions, animated);
gtk_widget_set_sensitive (GTK_WIDGET (priv->play_bar), animated);
@@ -1397,7 +1397,7 @@ close_callback (GtkAction *action,
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
- animation_stop (priv->animation);
+ animation_playback_stop (priv->playback);
gtk_widget_destroy (GTK_WIDGET (dialog));
}
@@ -1621,7 +1621,7 @@ proxycombo_activated (GtkEntry *combo_entry,
{
gboolean was_playing;
- was_playing = animation_is_playing (priv->animation);
+ was_playing = animation_playback_is_playing (priv->playback);
animation_set_proxy (priv->animation, ratio);
update_scale (dialog, get_zoom (dialog, -1));
@@ -1733,7 +1733,7 @@ adjustment_pressed (GtkWidget *widget,
GtkAdjustment *adj = gtk_spin_button_get_adjustment (spin);
gtk_adjustment_set_value (adj,
- (gdouble) animation_get_position (priv->animation) + 1.0);
+ (gdouble) animation_playback_get_position (priv->playback) + 1.0);
/* We don't want the middle click to have another usage (in
* particular, there is likely no need to copy-paste in these spin
@@ -1754,7 +1754,7 @@ startframe_changed (GtkAdjustment *adjustment,
if (! priv->animation)
return;
- animation_set_playback_start (priv->animation, (gint) value - 1);
+ animation_playback_set_start (priv->playback, (gint) value - 1);
update_ui_sensitivity (dialog);
}
@@ -1769,7 +1769,7 @@ endframe_changed (GtkAdjustment *adjustment,
if (! priv->animation)
return;
- animation_set_playback_stop (priv->animation, (gint) value - 1);
+ animation_playback_set_stop (priv->playback, (gint) value - 1);
update_ui_sensitivity (dialog);
}
@@ -1780,15 +1780,15 @@ play_callback (GtkToggleAction *action,
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
- if (! animation_is_playing (priv->animation))
+ if (! animation_playback_is_playing (priv->playback))
{
gtk_action_set_icon_name (GTK_ACTION (action), "media-playback-pause");
- animation_play (priv->animation);
+ animation_playback_play (priv->playback);
}
else
{
gtk_action_set_icon_name (GTK_ACTION (action), "media-playback-start");
- animation_stop (priv->animation);
+ animation_playback_stop (priv->playback);
/* The framerate combo might have been modified to display slowness
* warnings. */
@@ -1799,7 +1799,7 @@ play_callback (GtkToggleAction *action,
g_object_set (action,
"tooltip",
- animation_is_playing (priv->animation) ? _("Pause playback") : _("Start playback"),
+ animation_playback_is_playing (priv->playback) ? _("Pause playback") : _("Start playback"),
NULL);
}
@@ -1809,9 +1809,9 @@ step_back_callback (GtkAction *action,
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
- if (animation_is_playing (priv->animation))
+ if (animation_playback_is_playing (priv->playback))
play_pause (dialog);
- animation_prev (priv->animation);
+ animation_playback_prev (priv->playback);
}
static void
@@ -1820,9 +1820,9 @@ step_callback (GtkAction *action,
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
- if (animation_is_playing (priv->animation))
- animation_stop (priv->animation);
- animation_next (priv->animation);
+ if (animation_playback_is_playing (priv->playback))
+ animation_playback_stop (priv->playback);
+ animation_playback_next (priv->playback);
}
static void
@@ -1832,12 +1832,12 @@ rewind_callback (GtkAction *action,
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
gboolean was_playing;
- was_playing = animation_is_playing (priv->animation);
+ was_playing = animation_playback_is_playing (priv->playback);
if (was_playing)
play_pause (dialog);
- animation_jump (priv->animation, animation_get_playback_start (priv->animation));
+ animation_playback_jump (priv->playback, animation_playback_get_start (priv->playback));
/* If we were playing, start playing again. */
if (was_playing)
@@ -1899,7 +1899,7 @@ detach_callback (GtkToggleAction *action,
/* Force a refresh after detachment/attachment. */
buffer = animation_get_frame (priv->animation,
- animation_get_position (priv->animation));
+ animation_playback_get_position (priv->playback));
render_frame (dialog, buffer, TRUE);
/* clean up */
if (buffer != NULL)
@@ -1931,7 +1931,7 @@ show_loading_progress (Animation *animation,
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
gchar *text;
- block_ui (animation, dialog);
+ block_ui (dialog);
/* update the dialog's progress bar */
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress), load_rate);
@@ -1946,85 +1946,32 @@ show_loading_progress (Animation *animation,
}
static void
-animation_update_progress (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- AnimationDialog *dialog)
-{
- AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
- gint frame_spin_size;
- gint last_frame = num_frames;
-
- frame_spin_size = (gint) (log10 (last_frame + 1 - (last_frame % 10))) + 1;
- gtk_entry_set_width_chars (GTK_ENTRY (priv->startframe_spin), frame_spin_size);
- gtk_entry_set_width_chars (GTK_ENTRY (priv->endframe_spin), frame_spin_size);
-
- gtk_adjustment_configure (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->startframe_spin)),
- (gdouble) playback_start + 1.0,
- 1.0,
- (gdouble) last_frame,
- 1.0, 5.0, 0.0);
- gtk_adjustment_configure (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->endframe_spin)),
- (gdouble) playback_stop + 1.0,
- (gdouble) playback_start + 1.0,
- (gdouble) last_frame,
- 1.0, 5.0, 0.0);
-
- update_ui_sensitivity (dialog);
-}
-
-static void
-block_ui (Animation *animation,
- AnimationDialog *dialog)
+unblock_ui (Animation *animation,
+ AnimationDialog *dialog)
{
- AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
-
- if (animation_is_playing (priv->animation))
- play_pause (dialog);
-
- gtk_action_group_set_sensitive (priv->play_actions, FALSE);
- gtk_widget_set_sensitive (priv->play_bar, FALSE);
- gtk_widget_set_sensitive (priv->progress_bar, FALSE);
- gtk_action_group_set_sensitive (priv->settings_actions, FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (priv->settings_bar), FALSE);
- gtk_action_group_set_sensitive (priv->view_actions, FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (priv->view_bar), FALSE);
+ update_progress (dialog);
+ animation_dialog_refresh (dialog);
}
static void
-unblock_ui (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- gint preview_width,
- gint preview_height,
- AnimationDialog *dialog)
+duration_changed (AnimationPlayback *playback,
+ gint duration,
+ AnimationDialog *dialog)
{
- animation_update_progress (animation,
- num_frames,
- playback_start,
- playback_stop,
- dialog);
- animation_dialog_refresh (dialog);
+ update_progress (dialog);
}
static void
-playback_range_changed (Animation *animation,
- gint playback_start,
- gint playback_stop,
- gint length,
- AnimationDialog *dialog)
+playback_range_changed (AnimationPlayback *playback,
+ gint playback_start,
+ gint playback_stop,
+ AnimationDialog *dialog)
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
GtkAdjustment *startframe_adjust;
GtkAdjustment *stopframe_adjust;
- animation_update_progress (animation,
- length,
- playback_start,
- playback_stop,
- dialog);
+ update_progress (dialog);
startframe_adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->startframe_spin));
stopframe_adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->endframe_spin));
@@ -2100,9 +2047,9 @@ framerate_changed (Animation *animation,
}
static void
-low_framerate_cb (Animation *animation,
- gdouble real_framerate,
- AnimationDialog *dialog)
+low_framerate_cb (AnimationPlayback *playback,
+ gdouble real_framerate,
+ AnimationDialog *dialog)
{
AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
gchar *text;
@@ -2290,7 +2237,7 @@ da_size_callback (GtkWidget *drawing_area,
GeglBuffer *buffer;
buffer = animation_get_frame (priv->animation,
- animation_get_position (priv->animation));
+ animation_playback_get_position (priv->playback));
render_frame (dialog, buffer, TRUE);
/* clean up */
if (buffer != NULL)
@@ -2371,11 +2318,11 @@ shape_motion (GtkWidget *widget,
}
static void
-render_callback (Animation *animation,
- gint frame_number,
- GeglBuffer *buffer,
- gboolean must_draw_null,
- AnimationDialog *dialog)
+render_callback (AnimationPlayback *playback,
+ gint frame_number,
+ GeglBuffer *buffer,
+ gboolean must_draw_null,
+ AnimationDialog *dialog)
{
render_frame (dialog, buffer, must_draw_null);
@@ -2391,7 +2338,7 @@ render_on_realize (GtkWidget *drawing_area,
GeglBuffer *buffer;
buffer = animation_get_frame (priv->animation,
- animation_get_position (priv->animation));
+ animation_playback_get_position (priv->playback));
render_frame (dialog, buffer, TRUE);
/* clean up */
if (buffer != NULL)
@@ -2590,7 +2537,7 @@ progress_button (GtkWidget *widget,
((gdouble) allocation.width /
((gdouble) duration - 0.99)));
- animation_jump (priv->animation, frame);
+ animation_playback_jump (priv->playback, frame);
}
return FALSE;
@@ -2678,17 +2625,64 @@ show_playing_progress (AnimationDialog *dialog)
/* update the dialog's progress bar */
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress),
- ((gfloat) animation_get_position (priv->animation) /
+ ((gfloat) animation_playback_get_position (priv->playback) /
(gfloat) (animation_get_duration (priv->animation) - 0.999)));
text = g_strdup_printf (_("Frame %d of %d"),
- animation_get_position (priv->animation) + 1,
+ animation_playback_get_position (priv->playback) + 1,
animation_get_duration (priv->animation));
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progress), text);
g_free (text);
}
+static void
+update_progress (AnimationDialog *dialog)
+{
+ AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
+ gint frame_spin_size;
+ gint duration = animation_get_duration (priv->animation);
+ gint playback_start;
+ gint playback_stop;
+
+ playback_start = animation_playback_get_start (priv->playback);
+ playback_stop = animation_playback_get_stop (priv->playback);
+
+ frame_spin_size = (gint) (log10 (duration + 1 - (duration % 10))) + 1;
+ gtk_entry_set_width_chars (GTK_ENTRY (priv->startframe_spin), frame_spin_size);
+ gtk_entry_set_width_chars (GTK_ENTRY (priv->endframe_spin), frame_spin_size);
+
+ gtk_adjustment_configure (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->startframe_spin)),
+ (gdouble) playback_start + 1.0,
+ 1.0,
+ (gdouble) duration,
+ 1.0, 5.0, 0.0);
+ gtk_adjustment_configure (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->endframe_spin)),
+ (gdouble) playback_stop + 1.0,
+ (gdouble) playback_start + 1.0,
+ (gdouble) duration,
+ 1.0, 5.0, 0.0);
+
+ update_ui_sensitivity (dialog);
+}
+
+static void
+block_ui (AnimationDialog *dialog)
+{
+ AnimationDialogPrivate *priv = GET_PRIVATE (dialog);
+
+ if (animation_playback_is_playing (priv->playback))
+ play_pause (dialog);
+
+ gtk_action_group_set_sensitive (priv->play_actions, FALSE);
+ gtk_widget_set_sensitive (priv->play_bar, FALSE);
+ gtk_widget_set_sensitive (priv->progress_bar, FALSE);
+ gtk_action_group_set_sensitive (priv->settings_actions, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->settings_bar), FALSE);
+ gtk_action_group_set_sensitive (priv->view_actions, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->view_bar), FALSE);
+}
+
static gboolean
is_detached (AnimationDialog *dialog)
{
diff --git a/plug-ins/animation-play/widgets/animation-storyboard.c
b/plug-ins/animation-play/widgets/animation-storyboard.c
index 613c2de..feaaa30 100644
--- a/plug-ins/animation-play/widgets/animation-storyboard.c
+++ b/plug-ins/animation-play/widgets/animation-storyboard.c
@@ -28,6 +28,7 @@
#include "libgimp/stdplugins-intl.h"
#include "core/animationanimatic.h"
+#include "core/animation-playback.h"
#include "animation-storyboard.h"
@@ -41,6 +42,7 @@ enum
struct _AnimationStoryboardPrivate
{
AnimationAnimatic *animation;
+ AnimationPlayback *playback;
gint current_panel;
@@ -63,20 +65,15 @@ static void animation_storyboard_finalize (GObject *obj
/* Callbacks on animation */
static void animation_storyboard_load (Animation *animation,
- G_GNUC_UNUSED gint num_frames,
- G_GNUC_UNUSED gint playback_start,
- G_GNUC_UNUSED gint playback_stop,
- G_GNUC_UNUSED gint preview_width,
- G_GNUC_UNUSED gint preview_height,
AnimationStoryboard *view);
-static void animation_storyboard_rendered (Animation *animation,
+static void animation_storyboard_rendered (AnimationPlayback *playback,
gint frame_number,
GeglBuffer *buffer,
gboolean must_draw_null,
AnimationStoryboard *view);
static void animation_storyboard_duration_spin_changed (GtkSpinButton *spinbutton,
- AnimationAnimatic *animation);
+ AnimationStoryboard *storyboard);
static gboolean animation_storyboard_comment_keypress (GtkWidget *entry,
GdkEventKey *event,
@@ -86,7 +83,7 @@ static void animation_storyboard_comment_changed (GtkTextBuffer *tex
static void animation_storyboard_disposal_toggled (GtkToggleButton *button,
AnimationAnimatic *animatic);
static void animation_storyboard_button_clicked (GtkWidget *widget,
- AnimationAnimatic *animatic);
+ AnimationStoryboard *storyboard);
G_DEFINE_TYPE (AnimationStoryboard, animation_storyboard, GTK_TYPE_TABLE)
@@ -136,13 +133,17 @@ animation_storyboard_init (AnimationStoryboard *view)
* Creates a new layer view tied to @animation, ready to be displayed.
*/
GtkWidget *
-animation_storyboard_new (AnimationAnimatic *animation)
+animation_storyboard_new (AnimationAnimatic *animation,
+ AnimationPlayback *playback)
{
- GtkWidget *layer_view;
+ GtkWidget *layer_view;
+ AnimationStoryboard *storyboard;
layer_view = g_object_new (ANIMATION_TYPE_STORYBOARD,
"animation", animation,
NULL);
+ storyboard = ANIMATION_STORYBOARD (layer_view);
+ storyboard->priv->playback = playback;
return layer_view;
}
@@ -228,11 +229,6 @@ animation_storyboard_finalize (GObject *object)
*/
static void
animation_storyboard_load (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- gint preview_width,
- gint preview_height,
AnimationStoryboard *view)
{
AnimationAnimatic *animatic = ANIMATION_ANIMATIC (animation);
@@ -299,7 +295,7 @@ animation_storyboard_load (Animation *animation,
GINT_TO_POINTER (panel_num));
g_signal_connect (panel_button, "clicked",
G_CALLBACK (animation_storyboard_button_clicked),
- animation);
+ view);
view->priv->panel_buttons = g_list_prepend (view->priv->panel_buttons,
panel_button);
@@ -392,7 +388,7 @@ animation_storyboard_load (Animation *animation,
GINT_TO_POINTER (panel_num));
g_signal_connect (duration, "value-changed",
(GCallback) animation_storyboard_duration_spin_changed,
- animation);
+ view);
gtk_widget_show (duration);
disposal = gtk_toggle_button_new ();
@@ -419,14 +415,14 @@ animation_storyboard_load (Animation *animation,
disposal);
gtk_widget_show (disposal);
}
- g_signal_connect (animation, "render",
+ g_signal_connect (view->priv->playback, "render",
(GCallback) animation_storyboard_rendered,
view);
gimp_image_delete (image_id);
}
static void
-animation_storyboard_rendered (Animation *animation,
+animation_storyboard_rendered (AnimationPlayback *playback,
gint frame_number,
GeglBuffer *buffer,
gboolean must_draw_null,
@@ -436,7 +432,7 @@ animation_storyboard_rendered (Animation *animation,
GtkWidget *arrow;
gint panel;
- panel = animation_animatic_get_panel (ANIMATION_ANIMATIC (animation),
+ panel = animation_animatic_get_panel (view->priv->animation,
frame_number);
if (view->priv->current_panel >= 0)
{
@@ -456,18 +452,33 @@ animation_storyboard_rendered (Animation *animation,
}
static void
-animation_storyboard_duration_spin_changed (GtkSpinButton *spinbutton,
- AnimationAnimatic *animation)
+animation_storyboard_duration_spin_changed (GtkSpinButton *spinbutton,
+ AnimationStoryboard *storyboard)
{
gpointer panel_num;
gint duration;
+ gint panel_position;
+ gint position;
panel_num = g_object_get_data (G_OBJECT (spinbutton), "panel-num");
duration = gtk_spin_button_get_value_as_int (spinbutton);
- animation_animatic_set_panel_duration (animation,
+ position = animation_playback_get_position (storyboard->priv->playback);
+ panel_position = animation_animatic_get_position (storyboard->priv->animation,
+ GPOINTER_TO_INT (panel_num));
+ if (position >= panel_position)
+ {
+ gint cur_duration;
+
+ cur_duration = animation_animatic_get_panel_duration (storyboard->priv->animation,
+ GPOINTER_TO_INT (panel_num));
+ position += duration - cur_duration;
+ }
+
+ animation_animatic_set_panel_duration (storyboard->priv->animation,
GPOINTER_TO_INT (panel_num),
duration);
+ animation_playback_jump (storyboard->priv->playback, position);
}
static gboolean
@@ -535,11 +546,14 @@ animation_storyboard_disposal_toggled (GtkToggleButton *button,
}
static void
-animation_storyboard_button_clicked (GtkWidget *widget,
- AnimationAnimatic *animatic)
+animation_storyboard_button_clicked (GtkWidget *widget,
+ AnimationStoryboard *storyboard)
{
gpointer panel_num;
+ gint position;
panel_num = g_object_get_data (G_OBJECT (widget), "panel-num");
- animation_animatic_jump_panel (animatic, GPOINTER_TO_INT (panel_num));
+ position = animation_animatic_get_position (storyboard->priv->animation,
+ GPOINTER_TO_INT (panel_num));
+ animation_playback_jump (storyboard->priv->playback, position);
}
diff --git a/plug-ins/animation-play/widgets/animation-storyboard.h
b/plug-ins/animation-play/widgets/animation-storyboard.h
index f92a23e..cb7452b 100644
--- a/plug-ins/animation-play/widgets/animation-storyboard.h
+++ b/plug-ins/animation-play/widgets/animation-storyboard.h
@@ -46,7 +46,8 @@ struct _AnimationStoryboardClass
GType animation_storyboard_get_type (void) G_GNUC_CONST;
-GtkWidget * animation_storyboard_new (AnimationAnimatic *animation);
+GtkWidget * animation_storyboard_new (AnimationAnimatic *animation,
+ AnimationPlayback *playback);
#endif /* __ANIMATION_STORYBOARD_H__ */
diff --git a/plug-ins/animation-play/widgets/animation-xsheet.c
b/plug-ins/animation-play/widgets/animation-xsheet.c
index 4161f3d..c7aaa9a 100755
--- a/plug-ins/animation-play/widgets/animation-xsheet.c
+++ b/plug-ins/animation-play/widgets/animation-xsheet.c
@@ -25,6 +25,8 @@
#include <libgimp/gimp.h>
+#include "core/animation.h"
+#include "core/animation-playback.h"
#include "core/animation-celanimation.h"
#include "animation-layer-view.h"
@@ -42,6 +44,8 @@ enum
struct _AnimationXSheetPrivate
{
AnimationCelAnimation *animation;
+ AnimationPlayback *playback;
+
GtkWidget *layer_view;
GtkWidget *track_layout;
@@ -72,17 +76,13 @@ static void animation_xsheet_reset_layout (AnimationXSheet *xsheet);
/* Callbacks on animation. */
static void on_animation_loaded (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- gint preview_width,
- gint preview_height,
- AnimationXSheet *xsheet);
-static void on_animation_rendered (Animation *animation,
- gint frame_number,
- GeglBuffer *buffer,
- gboolean must_draw_null,
AnimationXSheet *xsheet);
+/* Callbacks on callback. */
+static void on_animation_rendered (AnimationPlayback *animation,
+ gint frame_number,
+ GeglBuffer *buffer,
+ gboolean must_draw_null,
+ AnimationXSheet *xsheet);
/* Callbacks on layer view. */
static void on_layer_selection (AnimationLayerView *view,
@@ -160,6 +160,7 @@ animation_xsheet_init (AnimationXSheet *xsheet)
GtkWidget *
animation_xsheet_new (AnimationCelAnimation *animation,
+ AnimationPlayback *playback,
GtkWidget *layer_view)
{
GtkWidget *xsheet;
@@ -168,6 +169,10 @@ animation_xsheet_new (AnimationCelAnimation *animation,
"animation", animation,
"layer-view", layer_view,
NULL);
+ ANIMATION_XSHEET (xsheet)->priv->playback = playback;
+ g_signal_connect (ANIMATION_XSHEET (xsheet)->priv->playback,
+ "render",
+ G_CALLBACK (on_animation_rendered), xsheet);
return xsheet;
}
@@ -199,8 +204,6 @@ animation_xsheet_constructed (GObject *object)
/* Reload everything when we reload the animation. */
g_signal_connect_after (xsheet->priv->animation, "loaded",
G_CALLBACK (on_animation_loaded), xsheet);
- g_signal_connect (xsheet->priv->animation, "render",
- G_CALLBACK (on_animation_rendered), xsheet);
}
static void
@@ -254,6 +257,9 @@ animation_xsheet_finalize (GObject *object)
{
AnimationXSheet *xsheet = ANIMATION_XSHEET (object);
+ g_signal_handlers_disconnect_by_func (ANIMATION_XSHEET (xsheet)->priv->playback,
+ G_CALLBACK (on_animation_rendered),
+ xsheet);
if (xsheet->priv->animation)
g_object_unref (xsheet->priv->animation);
if (xsheet->priv->layer_view)
@@ -478,22 +484,17 @@ on_layer_selection (AnimationLayerView *view,
static void
on_animation_loaded (Animation *animation,
- gint num_frames,
- gint playback_start,
- gint playback_stop,
- gint preview_width,
- gint preview_height,
AnimationXSheet *xsheet)
{
animation_xsheet_reset_layout (xsheet);
}
static void
-on_animation_rendered (Animation *animation,
- gint frame_number,
- GeglBuffer *buffer,
- gboolean must_draw_null,
- AnimationXSheet *xsheet)
+on_animation_rendered (AnimationPlayback *playback,
+ gint frame_number,
+ GeglBuffer *buffer,
+ gboolean must_draw_null,
+ AnimationXSheet *xsheet)
{
GtkWidget *button;
@@ -522,8 +523,8 @@ animation_xsheet_frame_clicked (GtkWidget *button,
position = g_object_get_data (G_OBJECT (button), "frame-position");
- animation_jump (ANIMATION (xsheet->priv->animation),
- GPOINTER_TO_INT (position) + 1);
+ animation_playback_jump (xsheet->priv->playback,
+ GPOINTER_TO_INT (position));
if (xsheet->priv->active_pos_button)
{
GtkToggleButton *active_button;
diff --git a/plug-ins/animation-play/widgets/animation-xsheet.h
b/plug-ins/animation-play/widgets/animation-xsheet.h
index 9346419..4a4dfba 100755
--- a/plug-ins/animation-play/widgets/animation-xsheet.h
+++ b/plug-ins/animation-play/widgets/animation-xsheet.h
@@ -47,6 +47,7 @@ struct _AnimationXSheetClass
GType animation_xsheet_get_type (void) G_GNUC_CONST;
GtkWidget * animation_xsheet_new (AnimationCelAnimation *animation,
+ AnimationPlayback *playback,
GtkWidget *layer_view);
#endif /* __ANIMATION_XSHEET_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]