[clutter] timeline: Add progress functions



commit 7ec975ed3d60c8861dc0a89e873ed928628f5270
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Fri Feb 17 16:06:28 2012 +0000

    timeline: Add progress functions
    
    The whole progress computation should not be done using a separate
    class: it should be part of the Timeline class.

 clutter/clutter-timeline.c                 |  249 ++++++++++++++++++++++++++--
 clutter/clutter-timeline.h                 |   29 +++-
 clutter/clutter.symbols                    |    3 +
 doc/reference/clutter/clutter-sections.txt |    3 +
 4 files changed, 270 insertions(+), 14 deletions(-)
---
diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c
index 84e9a73..c247238 100644
--- a/clutter/clutter-timeline.c
+++ b/clutter/clutter-timeline.c
@@ -98,6 +98,7 @@
 #endif
 
 #include "clutter-debug.h"
+#include "clutter-easing.h"
 #include "clutter-enum-types.h"
 #include "clutter-main.h"
 #include "clutter-marshal.h"
@@ -139,6 +140,11 @@ struct _ClutterTimelinePrivate
   /* The number of times the timeline has repeated */
   gint current_repeat;
 
+  ClutterTimelineProgressFunc progress_func;
+  gpointer progress_data;
+  GDestroyNotify progress_notify;
+  ClutterAnimationMode progress_mode;
+
   guint is_playing         : 1;
 
   /* If we've just started playing and haven't yet gotten
@@ -164,6 +170,7 @@ enum
   PROP_DIRECTION,
   PROP_AUTO_REVERSE,
   PROP_REPEAT_COUNT,
+  PROP_PROGRESS_MODE,
 
   PROP_LAST
 };
@@ -417,6 +424,10 @@ clutter_timeline_set_property (GObject      *object,
       clutter_timeline_set_repeat_count (timeline, g_value_get_int (value));
       break;
 
+    case PROP_PROGRESS_MODE:
+      clutter_timeline_set_progress_mode (timeline, g_value_get_enum (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -458,6 +469,10 @@ clutter_timeline_get_property (GObject    *object,
       g_value_set_int (value, priv->repeat_count);
       break;
 
+    case PROP_PROGRESS_MODE:
+      g_value_set_enum (value, priv->progress_mode);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -497,6 +512,14 @@ clutter_timeline_dispose (GObject *object)
       priv->delay_id = 0;
     }
 
+  if (priv->progress_notify != NULL)
+    {
+      priv->progress_notify (priv->progress_data);
+      priv->progress_func = NULL;
+      priv->progress_data = NULL;
+      priv->progress_notify = NULL;
+    }
+
   G_OBJECT_CLASS (clutter_timeline_parent_class)->dispose (object);
 }
 
@@ -609,13 +632,26 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
                       0,
                       CLUTTER_PARAM_READWRITE);
 
-  object_class->dispose      = clutter_timeline_dispose;
-  object_class->finalize     = clutter_timeline_finalize;
+  /**
+   * ClutterTimeline:progress-mode:
+   *
+   * Controls the way a #ClutterTimeline computes the normalized progress.
+   *
+   * Since: 1.10
+   */
+  obj_props[PROP_PROGRESS_MODE] =
+    g_param_spec_enum ("progress-mode",
+                       P_("Progress Mode"),
+                       P_("How the timeline should compute the progress"),
+                       CLUTTER_TYPE_ANIMATION_MODE,
+                       CLUTTER_LINEAR,
+                       CLUTTER_PARAM_READWRITE);
+
+  object_class->dispose = clutter_timeline_dispose;
+  object_class->finalize = clutter_timeline_finalize;
   object_class->set_property = clutter_timeline_set_property;
   object_class->get_property = clutter_timeline_get_property;
-  g_object_class_install_properties (object_class,
-                                     PROP_LAST,
-                                     obj_props);
+  g_object_class_install_properties (object_class, PROP_LAST, obj_props);
 
   /**
    * ClutterTimeline::new-frame:
@@ -639,8 +675,12 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
    * ClutterTimeline::completed:
    * @timeline: the #ClutterTimeline which received the signal
    *
-   * The ::completed signal is emitted when the timeline reaches the
-   * number of frames specified by the ClutterTimeline:num-frames property.
+   * The #ClutterTimeline::completed signal is emitted when the timeline's
+   * elapsed time reaches the value of the #ClutterTimeline:duration
+   * property.
+   *
+   * This signal will be emitted even if the #ClutterTimeline is set to be
+   * repeating.
    */
   timeline_signals[COMPLETED] =
     g_signal_new (I_("completed"),
@@ -734,9 +774,7 @@ clutter_timeline_init (ClutterTimeline *self)
     G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_TIMELINE,
                                  ClutterTimelinePrivate);
 
-  priv->duration = 0;
-  priv->delay = 0;
-  priv->elapsed_time = 0;
+  priv->progress_mode = CLUTTER_LINEAR;
 }
 
 struct CheckIfMarkerHitClosure
@@ -1429,9 +1467,13 @@ clutter_timeline_set_duration (ClutterTimeline *timeline,
  * clutter_timeline_get_progress:
  * @timeline: a #ClutterTimeline
  *
- * The position of the timeline in a [0, 1] interval.
+ * The position of the timeline in a normalized [-1, 2] interval.
+ *
+ * The return value of this function is determined by the progress
+ * mode set using clutter_timeline_set_progress_mode(), or by the
+ * progress function set using clutter_timeline_set_progress_func().
  *
- * Return value: the position of the timeline.
+ * Return value: the normalized current position in the timeline.
  *
  * Since: 0.6
  */
@@ -1444,7 +1486,14 @@ clutter_timeline_get_progress (ClutterTimeline *timeline)
 
   priv = timeline->priv;
 
-  return (gdouble) priv->elapsed_time / (gdouble) priv->duration;
+  /* short-circuit linear progress */
+  if (priv->progress_func == NULL)
+    return (gdouble) priv->elapsed_time / (gdouble) priv->duration;
+  else
+    return priv->progress_func (timeline,
+                                (gdouble) priv->elapsed_time,
+                                (gdouble) priv->duration,
+                                priv->progress_data);
 }
 
 /**
@@ -1948,3 +1997,177 @@ clutter_timeline_get_repeat_count (ClutterTimeline *timeline)
 
   return timeline->priv->repeat_count;
 }
+
+/**
+ * clutter_timeline_set_progress_func:
+ * @timeline: a #ClutterTimeline
+ * @func: (scope notify) (allow-none): a progress function, or %NULL
+ * @data: (closure): data to pass to @func
+ * @notify: a function to be called when the progress function is removed
+ *    or the timeline is disposed
+ *
+ * Sets a custom progress function for @timeline. The progress function will
+ * be called by clutter_timeline_get_progress() and will be used to compute
+ * the progress value based on the elapsed time and the total duration of the
+ * timeline.
+ *
+ * If @func is not %NULL, the #ClutterTimeline:progress-mode property will
+ * be set to %CLUTTER_CUSTOM_MODE.
+ *
+ * If @func is %NULL, any previously set progress function will be unset, and
+ * the #ClutterTimeline:progress-mode property will be set to %CLUTTER_LINEAR.
+ *
+ * Since: 1.10
+ */
+void
+clutter_timeline_set_progress_func (ClutterTimeline             *timeline,
+                                    ClutterTimelineProgressFunc  func,
+                                    gpointer                     data,
+                                    GDestroyNotify               notify)
+{
+  ClutterTimelinePrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
+
+  priv = timeline->priv;
+
+  if (priv->progress_notify != NULL)
+    priv->progress_notify (priv->progress_data);
+
+  priv->progress_func = func;
+  priv->progress_data = data;
+  priv->progress_notify = notify;
+
+  if (priv->progress_func != NULL)
+    priv->progress_mode = CLUTTER_CUSTOM_MODE;
+  else
+    priv->progress_mode = CLUTTER_LINEAR;
+
+  g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_PROGRESS_MODE]);
+}
+
+/*< private >
+ * _clutter_animation_modes:
+ *
+ * A mapping of animation modes and easing functions.
+ */
+static const struct {
+  ClutterAnimationMode mode;
+  ClutterEasingFunc func;
+  const char *name;
+} _clutter_animation_modes[] = {
+  { CLUTTER_CUSTOM_MODE,         NULL, "custom" },
+
+  { CLUTTER_LINEAR,              clutter_linear, "linear" },
+  { CLUTTER_EASE_IN_QUAD,        clutter_ease_in_quad, "easeInQuad" },
+  { CLUTTER_EASE_OUT_QUAD,       clutter_ease_out_quad, "easeOutQuad" },
+  { CLUTTER_EASE_IN_OUT_QUAD,    clutter_ease_in_out_quad, "easeInOutQuad" },
+  { CLUTTER_EASE_IN_CUBIC,       clutter_ease_in_cubic, "easeInCubic" },
+  { CLUTTER_EASE_OUT_CUBIC,      clutter_ease_out_cubic, "easeOutCubic" },
+  { CLUTTER_EASE_IN_OUT_CUBIC,   clutter_ease_in_out_cubic, "easeInOutCubic" },
+  { CLUTTER_EASE_IN_QUART,       clutter_ease_in_quart, "easeInQuart" },
+  { CLUTTER_EASE_OUT_QUART,      clutter_ease_out_quart, "easeOutQuart" },
+  { CLUTTER_EASE_IN_OUT_QUART,   clutter_ease_in_out_quart, "easeInOutQuart" },
+  { CLUTTER_EASE_IN_QUINT,       clutter_ease_in_quint, "easeInQuint" },
+  { CLUTTER_EASE_OUT_QUINT,      clutter_ease_out_quint, "easeOutQuint" },
+  { CLUTTER_EASE_IN_OUT_QUINT,   clutter_ease_in_out_quint, "easeInOutQuint" },
+  { CLUTTER_EASE_IN_SINE,        clutter_ease_in_sine, "easeInSine" },
+  { CLUTTER_EASE_OUT_SINE,       clutter_ease_out_sine, "easeOutSine" },
+  { CLUTTER_EASE_IN_OUT_SINE,    clutter_ease_in_out_sine, "easeInOutSine" },
+  { CLUTTER_EASE_IN_EXPO,        clutter_ease_in_expo, "easeInExpo" },
+  { CLUTTER_EASE_OUT_EXPO,       clutter_ease_out_expo, "easeOutExpo" },
+  { CLUTTER_EASE_IN_OUT_EXPO,    clutter_ease_in_out_expo, "easeInOutExpo" },
+  { CLUTTER_EASE_IN_CIRC,        clutter_ease_in_circ, "easeInCirc" },
+  { CLUTTER_EASE_OUT_CIRC,       clutter_ease_out_circ, "easeOutCirc" },
+  { CLUTTER_EASE_IN_OUT_CIRC,    clutter_ease_in_out_circ, "easeInOutCirc" },
+  { CLUTTER_EASE_IN_ELASTIC,     clutter_ease_in_elastic, "easeInElastic" },
+  { CLUTTER_EASE_OUT_ELASTIC,    clutter_ease_out_elastic, "easeOutElastic" },
+  { CLUTTER_EASE_IN_OUT_ELASTIC, clutter_ease_in_out_elastic, "easeInOutElastic" },
+  { CLUTTER_EASE_IN_BACK,        clutter_ease_in_back, "easeInBack" },
+  { CLUTTER_EASE_OUT_BACK,       clutter_ease_out_back, "easeOutBack" },
+  { CLUTTER_EASE_IN_OUT_BACK,    clutter_ease_in_out_back, "easeInOutBack" },
+  { CLUTTER_EASE_IN_BOUNCE,      clutter_ease_in_bounce, "easeInBounce" },
+  { CLUTTER_EASE_OUT_BOUNCE,     clutter_ease_out_bounce, "easeOutBounce" },
+  { CLUTTER_EASE_IN_OUT_BOUNCE,  clutter_ease_in_out_bounce, "easeInOutBounce" },
+
+  { CLUTTER_ANIMATION_LAST,      NULL, "sentinel" },
+};
+
+static gdouble
+clutter_timeline_progress_func (ClutterTimeline *timeline,
+                                gdouble          elapsed,
+                                gdouble          duration,
+                                gpointer         user_data G_GNUC_UNUSED)
+{
+  ClutterTimelinePrivate *priv = timeline->priv;
+  ClutterEasingFunc easing_func;
+
+  g_assert (_clutter_animation_modes[priv->progress_mode].mode == priv->progress_mode);
+  g_assert (_clutter_animation_modes[priv->progress_mode].func != NULL);
+
+  easing_func = _clutter_animation_modes[priv->progress_mode].func;
+
+  return easing_func (elapsed, duration);
+}
+
+/**
+ * clutter_timeline_set_progress_mode:
+ * @timeline: a #ClutterTimeline
+ * @mode: the progress mode, as a #ClutterAnimationMode
+ *
+ * Sets the progress function using a value from the #ClutterAnimationMode
+ * enumeration. The @mode cannot be %CLUTTER_CUSTOM_MODE or bigger than
+ * %CLUTTER_ANIMATION_LAST.
+ *
+ * Since: 1.10
+ */
+void
+clutter_timeline_set_progress_mode (ClutterTimeline      *timeline,
+                                    ClutterAnimationMode  mode)
+{
+  ClutterTimelinePrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
+  g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
+  g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
+
+  priv = timeline->priv;
+
+  if (priv->progress_mode == mode)
+    return;
+
+  if (priv->progress_notify != NULL)
+    priv->progress_notify (priv->progress_data);
+
+  priv->progress_mode = mode;
+
+  /* short-circuit linear progress */
+  if (priv->progress_mode != CLUTTER_LINEAR)
+    priv->progress_func = clutter_timeline_progress_func;
+  else
+    priv->progress_func = NULL;
+
+  priv->progress_data = NULL;
+  priv->progress_notify = NULL;
+
+  g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_PROGRESS_MODE]);
+}
+
+/**
+ * clutter_timeline_get_progress_mode:
+ * @timeline: a #ClutterTimeline
+ *
+ * Retrieves the progress mode set using clutter_timeline_set_progress_mode()
+ * or clutter_timeline_set_progress_func().
+ *
+ * Return value: a #ClutterAnimationMode
+ *
+ * Since: 1.10
+ */
+ClutterAnimationMode
+clutter_timeline_get_progress_mode (ClutterTimeline *timeline)
+{
+  g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), CLUTTER_LINEAR);
+
+  return timeline->priv->progress_mode;
+}
diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h
index 0a20187..b910dc7 100644
--- a/clutter/clutter-timeline.h
+++ b/clutter/clutter-timeline.h
@@ -43,6 +43,24 @@ typedef struct _ClutterTimelineClass   ClutterTimelineClass;
 typedef struct _ClutterTimelinePrivate ClutterTimelinePrivate;
 
 /**
+ * ClutterTimelineProgressFunc:
+ * @timeline: a #ClutterTimeline
+ * @elapsed: the elapsed time, in milliseconds
+ * @total: the total duration of the timeline, in milliseconds,
+ * @user_data: data passed to the function
+ *
+ * A function for defining a custom progress.
+ *
+ * Return value: the progress, as a floating point value between -1.0 and 2.0.
+ *
+ * Since: 1.10
+ */
+typedef gdouble (* ClutterTimelineProgressFunc) (ClutterTimeline *timeline,
+                                                 gdouble          elapsed,
+                                                 gdouble          total,
+                                                 gpointer         user_data);
+
+/**
  * ClutterTimeline:
  *
  * The #ClutterTimeline structure contains only private data
@@ -53,7 +71,8 @@ typedef struct _ClutterTimelinePrivate ClutterTimelinePrivate;
 struct _ClutterTimeline
 {
   /*< private >*/
-  GObject parent;
+  GObject parent_instance;
+
   ClutterTimelinePrivate *priv;
 };
 
@@ -138,6 +157,14 @@ gboolean                        clutter_timeline_has_marker             (Clutter
 void                            clutter_timeline_advance_to_marker      (ClutterTimeline          *timeline,
                                                                          const gchar              *marker_name);
 
+void                            clutter_timeline_set_progress_func      (ClutterTimeline          *timeline,
+                                                                         ClutterTimelineProgressFunc func,
+                                                                         gpointer                  data,
+                                                                         GDestroyNotify            notify);
+void                            clutter_timeline_set_progress_mode      (ClutterTimeline          *timeline,
+                                                                         ClutterAnimationMode      mode);
+ClutterAnimationMode            clutter_timeline_get_progress_mode      (ClutterTimeline          *timeline);
+
 G_END_DECLS
 
 #endif /* _CLUTTER_TIMELINE_H__ */
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index 961b552..8728071 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -1265,6 +1265,7 @@ clutter_timeline_get_direction
 clutter_timeline_get_duration
 clutter_timeline_get_elapsed_time
 clutter_timeline_get_loop
+clutter_timeline_get_progress_mode
 clutter_timeline_get_progress
 clutter_timeline_get_repeat_count
 clutter_timeline_get_type
@@ -1279,6 +1280,8 @@ clutter_timeline_set_delay
 clutter_timeline_set_direction
 clutter_timeline_set_duration
 clutter_timeline_set_loop
+clutter_timeline_set_progress_func
+clutter_timeline_set_progress_mode
 clutter_timeline_set_repeat_count
 clutter_timeline_skip
 clutter_timeline_start
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 59aa861..264af00 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -729,6 +729,9 @@ clutter_timeline_set_direction
 clutter_timeline_get_direction
 clutter_timeline_set_auto_reverse
 clutter_timeline_get_auto_reverse
+clutter_timeline_set_progress_mode
+clutter_timeline_get_progress_mode
+clutter_timeline_set_progress_func
 clutter_timeline_set_loop
 clutter_timeline_get_loop
 



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