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
This commit is contained in:
parent
a8c68c78d8
commit
65a024af92
@ -169,8 +169,14 @@ struct _ClutterTimelinePrivate
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gchar *name;
|
gchar *name;
|
||||||
guint msecs;
|
|
||||||
GQuark quark;
|
GQuark quark;
|
||||||
|
|
||||||
|
union {
|
||||||
|
guint msecs;
|
||||||
|
gdouble progress;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
guint is_relative : 1;
|
||||||
} TimelineMarker;
|
} TimelineMarker;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -205,14 +211,29 @@ enum
|
|||||||
static guint timeline_signals[LAST_SIGNAL] = { 0, };
|
static guint timeline_signals[LAST_SIGNAL] = { 0, };
|
||||||
|
|
||||||
static TimelineMarker *
|
static TimelineMarker *
|
||||||
timeline_marker_new (const gchar *name,
|
timeline_marker_new_time (const gchar *name,
|
||||||
guint msecs)
|
guint msecs)
|
||||||
{
|
{
|
||||||
TimelineMarker *marker = g_slice_new0 (TimelineMarker);
|
TimelineMarker *marker = g_slice_new (TimelineMarker);
|
||||||
|
|
||||||
marker->name = g_strdup (name);
|
marker->name = g_strdup (name);
|
||||||
marker->quark = g_quark_from_string (marker->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;
|
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);
|
old_marker = g_hash_table_lookup (priv->markers_by_name, marker->name);
|
||||||
if (old_marker != NULL)
|
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",
|
g_warning ("A marker named '%s' already exists at time %d",
|
||||||
old_marker->name,
|
old_marker->name,
|
||||||
old_marker->msecs);
|
msecs);
|
||||||
timeline_marker_free (marker);
|
timeline_marker_free (marker);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -315,12 +343,13 @@ parse_timeline_markers (JsonArray *array,
|
|||||||
object = json_node_get_object (element);
|
object = json_node_get_object (element);
|
||||||
|
|
||||||
if (!(json_object_has_member (object, "name") &&
|
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 "
|
g_warning ("The marker definition in a ClutterTimeline description "
|
||||||
"must be an object with the 'name' and 'time' members, "
|
"must be an object with the 'name' and either the 'time' "
|
||||||
"but the element %d of the 'markers' array does not have "
|
"or the 'progress' members, but the element %d of the "
|
||||||
"either",
|
"'markers' array does not have any of them.",
|
||||||
index_);
|
index_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -333,8 +362,12 @@ parse_timeline_markers (JsonArray *array,
|
|||||||
markers = NULL;
|
markers = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
marker = timeline_marker_new (json_object_get_string_member (object, "name"),
|
if (json_object_has_member (object, "time"))
|
||||||
json_object_get_int_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);
|
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
|
/* Otherwise it's just a simple test if the time is in range of
|
||||||
the previous time and the new time */
|
the previous time and the new time */
|
||||||
return (msecs > data->new_time - data->delta
|
return (msecs > data->new_time - data->delta &&
|
||||||
&& msecs <= data->new_time);
|
msecs <= data->new_time);
|
||||||
}
|
}
|
||||||
else
|
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
|
/* Otherwise it's just a simple test if the time is in range of
|
||||||
the previous time and the new time */
|
the previous time and the new time */
|
||||||
return (msecs >= data->new_time
|
return (msecs >= data->new_time &&
|
||||||
&& msecs < data->new_time + data->delta);
|
msecs < data->new_time + data->delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,14 +915,21 @@ check_if_marker_hit (const gchar *name,
|
|||||||
TimelineMarker *marker,
|
TimelineMarker *marker,
|
||||||
struct CheckIfMarkerHitClosure *data)
|
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);
|
CLUTTER_NOTE (SCHEDULER, "Marker '%s' reached", name);
|
||||||
|
|
||||||
g_signal_emit (data->timeline, timeline_signals[MARKER_REACHED],
|
g_signal_emit (data->timeline, timeline_signals[MARKER_REACHED],
|
||||||
marker->quark,
|
marker->quark,
|
||||||
name,
|
name,
|
||||||
marker->msecs);
|
msecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1723,6 +1763,42 @@ _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:
|
* clutter_timeline_add_marker_at_time:
|
||||||
* @timeline: a #ClutterTimeline
|
* @timeline: a #ClutterTimeline
|
||||||
@ -1730,15 +1806,18 @@ _clutter_timeline_do_tick (ClutterTimeline *timeline,
|
|||||||
* @msecs: position of the marker in milliseconds
|
* @msecs: position of the marker in milliseconds
|
||||||
*
|
*
|
||||||
* Adds a named marker that will be hit when the timeline has been
|
* Adds a named marker that will be hit when the timeline has been
|
||||||
* running for @msecs milliseconds. Markers are unique string
|
* running for @msecs milliseconds.
|
||||||
* identifiers for a given time. Once @timeline reaches
|
*
|
||||||
* @msecs, it will emit a ::marker-reached signal for each marker
|
* Markers are unique string identifiers for a given position on the
|
||||||
* attached to that time.
|
* 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
|
* A marker can be removed with clutter_timeline_remove_marker(). The
|
||||||
* timeline can be advanced to a marker using
|
* timeline can be advanced to a marker using
|
||||||
* clutter_timeline_advance_to_marker().
|
* clutter_timeline_advance_to_marker().
|
||||||
*
|
*
|
||||||
|
* See also: clutter_timeline_add_marker()
|
||||||
|
*
|
||||||
* Since: 0.8
|
* Since: 0.8
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -1752,12 +1831,13 @@ clutter_timeline_add_marker_at_time (ClutterTimeline *timeline,
|
|||||||
g_return_if_fail (marker_name != NULL);
|
g_return_if_fail (marker_name != NULL);
|
||||||
g_return_if_fail (msecs <= clutter_timeline_get_duration (timeline));
|
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);
|
clutter_timeline_add_marker_internal (timeline, marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CollectMarkersClosure
|
struct CollectMarkersClosure
|
||||||
{
|
{
|
||||||
|
guint duration;
|
||||||
guint msecs;
|
guint msecs;
|
||||||
GArray *markers;
|
GArray *markers;
|
||||||
};
|
};
|
||||||
@ -1767,7 +1847,14 @@ collect_markers (const gchar *key,
|
|||||||
TimelineMarker *marker,
|
TimelineMarker *marker,
|
||||||
struct CollectMarkersClosure *data)
|
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);
|
gchar *name_copy = g_strdup (key);
|
||||||
g_array_append_val (data->markers, name_copy);
|
g_array_append_val (data->markers, name_copy);
|
||||||
@ -1827,6 +1914,7 @@ clutter_timeline_list_markers (ClutterTimeline *timeline,
|
|||||||
{
|
{
|
||||||
struct CollectMarkersClosure data;
|
struct CollectMarkersClosure data;
|
||||||
|
|
||||||
|
data.duration = priv->duration;
|
||||||
data.msecs = msecs;
|
data.msecs = msecs;
|
||||||
data.markers = g_array_new (TRUE, FALSE, sizeof (gchar *));
|
data.markers = g_array_new (TRUE, FALSE, sizeof (gchar *));
|
||||||
|
|
||||||
@ -1864,6 +1952,7 @@ clutter_timeline_advance_to_marker (ClutterTimeline *timeline,
|
|||||||
{
|
{
|
||||||
ClutterTimelinePrivate *priv;
|
ClutterTimelinePrivate *priv;
|
||||||
TimelineMarker *marker;
|
TimelineMarker *marker;
|
||||||
|
guint msecs;
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
g_return_if_fail (marker_name != NULL);
|
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);
|
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);
|
g_warning ("No marker named '%s' found.", marker_name);
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,6 +148,10 @@ void clutter_timeline_set_delay
|
|||||||
guint msecs);
|
guint msecs);
|
||||||
guint clutter_timeline_get_delay (ClutterTimeline *timeline);
|
guint clutter_timeline_get_delay (ClutterTimeline *timeline);
|
||||||
guint clutter_timeline_get_delta (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,
|
void clutter_timeline_add_marker_at_time (ClutterTimeline *timeline,
|
||||||
const gchar *marker_name,
|
const gchar *marker_name,
|
||||||
guint msecs);
|
guint msecs);
|
||||||
|
@ -1484,6 +1484,7 @@ clutter_threads_init
|
|||||||
clutter_threads_leave
|
clutter_threads_leave
|
||||||
clutter_threads_remove_repaint_func
|
clutter_threads_remove_repaint_func
|
||||||
clutter_threads_set_lock_functions
|
clutter_threads_set_lock_functions
|
||||||
|
clutter_timeline_add_marker
|
||||||
clutter_timeline_add_marker_at_time
|
clutter_timeline_add_marker_at_time
|
||||||
clutter_timeline_advance
|
clutter_timeline_advance
|
||||||
clutter_timeline_advance_to_marker
|
clutter_timeline_advance_to_marker
|
||||||
|
@ -746,6 +746,7 @@ clutter_timeline_get_progress
|
|||||||
clutter_timeline_is_playing
|
clutter_timeline_is_playing
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
|
clutter_timeline_add_marker
|
||||||
clutter_timeline_add_marker_at_time
|
clutter_timeline_add_marker_at_time
|
||||||
clutter_timeline_has_marker
|
clutter_timeline_has_marker
|
||||||
clutter_timeline_list_markers
|
clutter_timeline_list_markers
|
||||||
|
@ -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, "marker1"));
|
||||||
g_assert (!clutter_timeline_has_marker (timeline, "foo"));
|
g_assert (!clutter_timeline_has_marker (timeline, "foo"));
|
||||||
g_assert (clutter_timeline_has_marker (timeline, "marker2"));
|
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);
|
markers = clutter_timeline_list_markers (timeline, -1, &n_markers);
|
||||||
g_assert_cmpint (n_markers, ==, 3);
|
g_assert_cmpint (n_markers, ==, 4);
|
||||||
g_strfreev (markers);
|
g_strfreev (markers);
|
||||||
|
|
||||||
markers = clutter_timeline_list_markers (timeline, 500, &n_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 (markers != NULL);
|
||||||
g_assert_cmpstr (markers[0], ==, "marker1");
|
g_assert_cmpstr (markers[0], ==, "marker3");
|
||||||
|
g_assert_cmpstr (markers[1], ==, "marker1");
|
||||||
g_strfreev (markers);
|
g_strfreev (markers);
|
||||||
|
|
||||||
g_object_unref (script);
|
g_object_unref (script);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"markers" : [
|
"markers" : [
|
||||||
{ "name" : "marker0", "time" : 250 },
|
{ "name" : "marker0", "time" : 250 },
|
||||||
{ "name" : "marker1", "time" : 500 },
|
{ "name" : "marker1", "time" : 500 },
|
||||||
{ "name" : "marker2", "time" : 750 }
|
{ "name" : "marker2", "time" : 750 },
|
||||||
|
{ "name" : "marker3", "progress" : 0.5 }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user