[clutter] timeline: Add progress-based marker API



commit 65a024af9256b9d01c12a7ca2775a291ce6fa7ab
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Feb 20 22:14:46 2013 +0000

    timeline: Add progress-based marker API
    
    Being able to set a marker at a normalized point on a timeline, instead
    of using a specific time, is a nice fit with the current Timeline class
    API.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=694319

 clutter/clutter-timeline.c                   |  146 +++++++++++++++++++++-----
 clutter/clutter-timeline.h                   |    4 +
 clutter/clutter.symbols                      |    1 +
 doc/reference/clutter/clutter-sections.txt   |    1 +
 tests/conform/timeline.c                     |    8 +-
 tests/data/test-script-timeline-markers.json |    3 +-
 6 files changed, 133 insertions(+), 30 deletions(-)
---
diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c
index 135335e..7fe8f5f 100644
--- a/clutter/clutter-timeline.c
+++ b/clutter/clutter-timeline.c
@@ -169,8 +169,14 @@ struct _ClutterTimelinePrivate
 
 typedef struct {
   gchar *name;
-  guint msecs;
   GQuark quark;
+
+  union {
+    guint msecs;
+    gdouble progress;
+  } data;
+
+  guint is_relative : 1;
 } TimelineMarker;
 
 enum
@@ -205,14 +211,29 @@ enum
 static guint timeline_signals[LAST_SIGNAL] = { 0, };
 
 static TimelineMarker *
-timeline_marker_new (const gchar *name,
-                     guint        msecs)
+timeline_marker_new_time (const gchar *name,
+                          guint        msecs)
 {
-  TimelineMarker *marker = g_slice_new0 (TimelineMarker);
+  TimelineMarker *marker = g_slice_new (TimelineMarker);
 
   marker->name = g_strdup (name);
   marker->quark = g_quark_from_string (marker->name);
-  marker->msecs = msecs;
+  marker->is_relative = FALSE;
+  marker->data.msecs = msecs;
+
+  return marker;
+}
+
+static TimelineMarker *
+timeline_marker_new_progress (const gchar *name,
+                              gdouble      progress)
+{
+  TimelineMarker *marker = g_slice_new (TimelineMarker);
+
+  marker->name = g_strdup (name);
+  marker->quark = g_quark_from_string (marker->name);
+  marker->is_relative = TRUE;
+  marker->data.progress = CLAMP (progress, 0.0, 1.0);
 
   return marker;
 }
@@ -256,9 +277,16 @@ clutter_timeline_add_marker_internal (ClutterTimeline *timeline,
   old_marker = g_hash_table_lookup (priv->markers_by_name, marker->name);
   if (old_marker != NULL)
     {
+      guint msecs;
+
+      if (old_marker->is_relative)
+        msecs = old_marker->data.progress * priv->duration;
+      else
+        msecs = old_marker->data.msecs;
+
       g_warning ("A marker named '%s' already exists at time %d",
                  old_marker->name,
-                 old_marker->msecs);
+                 msecs);
       timeline_marker_free (marker);
       return;
     }
@@ -315,12 +343,13 @@ parse_timeline_markers (JsonArray *array,
   object = json_node_get_object (element);
 
   if (!(json_object_has_member (object, "name") &&
-        json_object_has_member (object, "time")))
+        (json_object_has_member (object, "time") ||
+         json_object_has_member (object, "progress"))))
     {
       g_warning ("The marker definition in a ClutterTimeline description "
-                 "must be an object with the 'name' and 'time' members, "
-                 "but the element %d of the 'markers' array does not have "
-                 "either",
+                 "must be an object with the 'name' and either the 'time' "
+                 "or the 'progress' members, but the element %d of the "
+                 "'markers' array does not have any of them.",
                  index_);
       return;
     }
@@ -333,8 +362,12 @@ parse_timeline_markers (JsonArray *array,
       markers = NULL;
     }
 
-  marker = timeline_marker_new (json_object_get_string_member (object, "name"),
-                                json_object_get_int_member (object, "time"));
+  if (json_object_has_member (object, "time"))
+    marker = timeline_marker_new_time (json_object_get_string_member (object, "name"),
+                                       json_object_get_int_member (object, "time"));
+  else
+    marker = timeline_marker_new_progress (json_object_get_string_member (object, "name"),
+                                           json_object_get_double_member (object, "progress"));
 
   markers = g_list_prepend (markers, marker);
 
@@ -858,8 +891,8 @@ have_passed_time (const struct CheckIfMarkerHitClosure *data,
 
       /* Otherwise it's just a simple test if the time is in range of
          the previous time and the new time */
-      return (msecs > data->new_time - data->delta
-              && msecs <= data->new_time);
+      return (msecs > data->new_time - data->delta &&
+              msecs <= data->new_time);
     }
   else
     {
@@ -872,8 +905,8 @@ have_passed_time (const struct CheckIfMarkerHitClosure *data,
 
       /* Otherwise it's just a simple test if the time is in range of
          the previous time and the new time */
-      return (msecs >= data->new_time
-              && msecs < data->new_time + data->delta);
+      return (msecs >= data->new_time &&
+              msecs < data->new_time + data->delta);
     }
 }
 
@@ -882,14 +915,21 @@ check_if_marker_hit (const gchar *name,
                      TimelineMarker *marker,
                      struct CheckIfMarkerHitClosure *data)
 {
-  if (have_passed_time (data, marker->msecs))
+  gint msecs;
+
+  if (marker->is_relative)
+    msecs = (gdouble) data->duration * marker->data.progress;
+  else
+    msecs = marker->data.msecs;
+
+  if (have_passed_time (data, msecs))
     {
       CLUTTER_NOTE (SCHEDULER, "Marker '%s' reached", name);
 
       g_signal_emit (data->timeline, timeline_signals[MARKER_REACHED],
                      marker->quark,
                      name,
-                     marker->msecs);
+                     msecs);
     }
 }
 
@@ -1724,21 +1764,60 @@ _clutter_timeline_do_tick (ClutterTimeline *timeline,
 }
 
 /**
+ * clutter_timeline_add_marker:
+ * @timeline: a #ClutterTimeline
+ * @marker_name: the unique name for this marker
+ * @progress: the normalized value of the position of the martke
+ *
+ * Adds a named marker that will be hit when the timeline has reached
+ * the specified @progress.
+ *
+ * Markers are unique string identifiers for a given position on the
+ * timeline. Once @timeline reaches the given @progress of its duration,
+ * if will emit a ::marker-reached signal for each marker attached to
+ * that particular point.
+ *
+ * A marker can be removed with clutter_timeline_remove_marker(). The
+ * timeline can be advanced to a marker using
+ * clutter_timeline_advance_to_marker().
+ *
+ * See also: clutter_timeline_add_marker_at_time()
+ *
+ * Since: 1.14
+ */
+void
+clutter_timeline_add_marker (ClutterTimeline *timeline,
+                             const gchar     *marker_name,
+                             gdouble          progress)
+{
+  TimelineMarker *marker;
+
+  g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
+  g_return_if_fail (marker_name != NULL);
+
+  marker = timeline_marker_new_progress (marker_name, progress);
+  clutter_timeline_add_marker_internal (timeline, marker);
+}
+
+/**
  * clutter_timeline_add_marker_at_time:
  * @timeline: a #ClutterTimeline
  * @marker_name: the unique name for this marker
  * @msecs: position of the marker in milliseconds
  *
  * Adds a named marker that will be hit when the timeline has been
- * running for @msecs milliseconds. Markers are unique string
- * identifiers for a given time. Once @timeline reaches
- * @msecs, it will emit a ::marker-reached signal for each marker
- * attached to that time.
+ * running for @msecs milliseconds.
+ *
+ * Markers are unique string identifiers for a given position on the
+ * timeline. Once @timeline reaches the given @msecs, it will emit
+ * a ::marker-reached signal for each marker attached to that position.
  *
  * A marker can be removed with clutter_timeline_remove_marker(). The
  * timeline can be advanced to a marker using
  * clutter_timeline_advance_to_marker().
  *
+ * See also: clutter_timeline_add_marker()
+ *
  * Since: 0.8
  */
 void
@@ -1752,12 +1831,13 @@ clutter_timeline_add_marker_at_time (ClutterTimeline *timeline,
   g_return_if_fail (marker_name != NULL);
   g_return_if_fail (msecs <= clutter_timeline_get_duration (timeline));
 
-  marker = timeline_marker_new (marker_name, msecs);
+  marker = timeline_marker_new_time (marker_name, msecs);
   clutter_timeline_add_marker_internal (timeline, marker);
 }
 
 struct CollectMarkersClosure
 {
+  guint duration;
   guint msecs;
   GArray *markers;
 };
@@ -1767,7 +1847,14 @@ collect_markers (const gchar *key,
                  TimelineMarker *marker,
                  struct CollectMarkersClosure *data)
 {
-  if (marker->msecs == data->msecs)
+  guint msecs;
+
+  if (marker->is_relative)
+    msecs = marker->data.progress * data->duration;
+  else
+    msecs = marker->data.msecs;
+
+  if (msecs == data->msecs)
     {
       gchar *name_copy = g_strdup (key);
       g_array_append_val (data->markers, name_copy);
@@ -1827,6 +1914,7 @@ clutter_timeline_list_markers (ClutterTimeline *timeline,
     {
       struct CollectMarkersClosure data;
 
+      data.duration = priv->duration;
       data.msecs = msecs;
       data.markers = g_array_new (TRUE, FALSE, sizeof (gchar *));
 
@@ -1864,6 +1952,7 @@ clutter_timeline_advance_to_marker (ClutterTimeline *timeline,
 {
   ClutterTimelinePrivate *priv;
   TimelineMarker *marker;
+  guint msecs;
 
   g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
   g_return_if_fail (marker_name != NULL);
@@ -1877,13 +1966,18 @@ clutter_timeline_advance_to_marker (ClutterTimeline *timeline,
     }
 
   marker = g_hash_table_lookup (priv->markers_by_name, marker_name);
-  if (!marker)
+  if (marker == NULL)
     {
       g_warning ("No marker named '%s' found.", marker_name);
       return;
     }
 
-  clutter_timeline_advance (timeline, marker->msecs);
+  if (marker->is_relative)
+    msecs = marker->data.progress * priv->duration;
+  else
+    msecs = marker->data.msecs;
+
+  clutter_timeline_advance (timeline, msecs);
 }
 
 /**
diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h
index a1a2dc6..c31f8df 100644
--- a/clutter/clutter-timeline.h
+++ b/clutter/clutter-timeline.h
@@ -148,6 +148,10 @@ void                            clutter_timeline_set_delay
                                                                                  guint                     
msecs);
 guint                           clutter_timeline_get_delay                      (ClutterTimeline          
*timeline);
 guint                           clutter_timeline_get_delta                      (ClutterTimeline          
*timeline);
+CLUTTER_AVAILABLE_IN_1_14
+void                            clutter_timeline_add_marker                     (ClutterTimeline          
*timeline,
+                                                                                 const gchar              
*marker_name,
+                                                                                 gdouble                   
progress);
 void                            clutter_timeline_add_marker_at_time             (ClutterTimeline          
*timeline,
                                                                                  const gchar              
*marker_name,
                                                                                  guint                     
msecs);
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index d025fef..37b0ce3 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -1484,6 +1484,7 @@ clutter_threads_init
 clutter_threads_leave
 clutter_threads_remove_repaint_func
 clutter_threads_set_lock_functions
+clutter_timeline_add_marker
 clutter_timeline_add_marker_at_time
 clutter_timeline_advance
 clutter_timeline_advance_to_marker
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 7bdfbb3..1e4471a 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -746,6 +746,7 @@ clutter_timeline_get_progress
 clutter_timeline_is_playing
 
 <SUBSECTION>
+clutter_timeline_add_marker
 clutter_timeline_add_marker_at_time
 clutter_timeline_has_marker
 clutter_timeline_list_markers
diff --git a/tests/conform/timeline.c b/tests/conform/timeline.c
index a4471dd..55822ff 100644
--- a/tests/conform/timeline.c
+++ b/tests/conform/timeline.c
@@ -343,15 +343,17 @@ timeline_markers_from_script (TestConformSimpleFixture *fixture,
   g_assert (clutter_timeline_has_marker (timeline, "marker1"));
   g_assert (!clutter_timeline_has_marker (timeline, "foo"));
   g_assert (clutter_timeline_has_marker (timeline, "marker2"));
+  g_assert (clutter_timeline_has_marker (timeline, "marker3"));
 
   markers = clutter_timeline_list_markers (timeline, -1, &n_markers);
-  g_assert_cmpint (n_markers, ==, 3);
+  g_assert_cmpint (n_markers, ==, 4);
   g_strfreev (markers);
 
   markers = clutter_timeline_list_markers (timeline, 500, &n_markers);
-  g_assert_cmpint (n_markers, ==, 1);
+  g_assert_cmpint (n_markers, ==, 2);
   g_assert (markers != NULL);
-  g_assert_cmpstr (markers[0], ==, "marker1");
+  g_assert_cmpstr (markers[0], ==, "marker3");
+  g_assert_cmpstr (markers[1], ==, "marker1");
   g_strfreev (markers);
 
   g_object_unref (script);
diff --git a/tests/data/test-script-timeline-markers.json b/tests/data/test-script-timeline-markers.json
index 9dacecb..f5fff5c 100644
--- a/tests/data/test-script-timeline-markers.json
+++ b/tests/data/test-script-timeline-markers.json
@@ -6,6 +6,7 @@
   "markers" : [
     { "name" : "marker0", "time" : 250 },
     { "name" : "marker1", "time" : 500 },
-    { "name" : "marker2", "time" : 750 }
+    { "name" : "marker2", "time" : 750 },
+    { "name" : "marker3", "progress" : 0.5 }
   ]
 }


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