[clutter] timeline: Add support for step() progress
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter] timeline: Add support for step() progress
- Date: Fri, 20 Jul 2012 02:16:15 +0000 (UTC)
commit 4546f844080672580c469d75168630b737419c17
Author: Emmanuele Bassi <ebassi gnome org>
Date: Thu Jul 19 19:47:48 2012 -0400
timeline: Add support for step() progress
The CSS3 Transitions specification from the W3C defines the possibility
of using a parametrized step() timing function, with the following
prototype:
steps(n_steps, [ start | end ])
where @n_steps represents the number of steps used to divide an interval
between 0 and 1; the 'start' and 'end' tokens describe whether the value
change should happen at the start of the transition, or at the end.
For instance, the "steps(3, start)" timing function has the following
profile:
1 | x
| |
| x---|
| ' |
| x---' |
| ' |
0 |---' |
Whereas the "steps(3, end)" timing function has the following profile:
1 | x---|
| ' |
| x---' |
| ' |
x---' |
| |
0 | |
Since ClutterTimeline uses an enumeration for controlling the progress
mode, we need additional API to define the parameters of the steps()
progress; for this reason, we need a CLUTTER_STEPS enumeration value,
and a method for setting the number of steps and the value transition
policy.
The CSS3 Transitions spec helpfully also defines a step-start and a
step-end shorthands, which expand to step(1, start) and step(1, end)
respectively; we can provide a CLUTTER_STEP_START and CLUTTER_STEP_END
enumeration values for those.
clutter/clutter-easing.c | 27 +++++++++
clutter/clutter-easing.h | 9 +++
clutter/clutter-enums.h | 31 ++++++++++
clutter/clutter-timeline.c | 96 ++++++++++++++++++++++++++++++++
clutter/clutter-timeline.h | 8 +++
clutter/clutter.symbols | 3 +
tests/conform/Makefile.am | 1 +
tests/conform/test-conform-main.c | 2 +
tests/conform/timeline-progress.c | 110 +++++++++++++++++++++++++++++++++++++
9 files changed, 287 insertions(+), 0 deletions(-)
---
diff --git a/clutter/clutter-easing.c b/clutter/clutter-easing.c
index a8cf636..5f3dae2 100644
--- a/clutter/clutter-easing.c
+++ b/clutter/clutter-easing.c
@@ -379,6 +379,29 @@ clutter_ease_in_out_bounce (double t,
return ease_out_bounce_internal (t * 2 - d, d) * 0.5 + 1.0 * 0.5;
}
+static inline double
+ease_steps_end (double p,
+ int n_steps)
+{
+ return floor (p * (double) n_steps) / (double) n_steps;
+}
+
+double
+clutter_ease_steps_start (double t,
+ double d,
+ int n_steps)
+{
+ return 1.0 - ease_steps_end (1.0 - (t / d), n_steps);
+}
+
+double
+clutter_ease_steps_end (double t,
+ double d,
+ int n_steps)
+{
+ return ease_steps_end ((t / d), n_steps);
+}
+
/*< private >
* _clutter_animation_modes:
*
@@ -423,6 +446,10 @@ static const struct {
{ CLUTTER_EASE_OUT_BOUNCE, clutter_ease_out_bounce, "easeOutBounce" },
{ CLUTTER_EASE_IN_OUT_BOUNCE, clutter_ease_in_out_bounce, "easeInOutBounce" },
+ { CLUTTER_STEPS, (ClutterEasingFunc) clutter_ease_steps_end, "steps" },
+ { CLUTTER_STEP_START, (ClutterEasingFunc) clutter_ease_steps_start, "stepStart" },
+ { CLUTTER_STEP_END, (ClutterEasingFunc) clutter_ease_steps_end, "stepEnd" },
+
{ CLUTTER_ANIMATION_LAST, NULL, "sentinel" },
};
diff --git a/clutter/clutter-easing.h b/clutter/clutter-easing.h
index 04f0e28..ab9556b 100644
--- a/clutter/clutter-easing.h
+++ b/clutter/clutter-easing.h
@@ -121,6 +121,15 @@ G_GNUC_INTERNAL
double clutter_ease_in_out_bounce (double t,
double d);
+G_GNUC_INTERNAL
+double clutter_ease_steps_start (double t,
+ double d,
+ int steps);
+G_GNUC_INTERNAL
+double clutter_ease_steps_end (double t,
+ double d,
+ int steps);
+
G_END_DECLS
#endif /* __CLUTTER_EASING_H__ */
diff --git a/clutter/clutter-enums.h b/clutter/clutter-enums.h
index b788a05..2df11a8 100644
--- a/clutter/clutter-enums.h
+++ b/clutter/clutter-enums.h
@@ -160,6 +160,12 @@ typedef enum { /*< prefix=CLUTTER_REQUEST >*/
* tweening, with bounce on end
* @CLUTTER_EASE_IN_OUT_BOUNCE: exponentially decaying parabolic (bounce)
* tweening, with bounce on both ends
+ * @CLUTTER_STEPS: parametrized step function; see clutter_timeline_set_step_progress()
+ * for further details. (Since 1.12)
+ * @CLUTTER_STEP_START: equivalent to %CLUTTER_STEPS with a number of steps
+ * equal to 1, and a step mode of %CLUTTER_STEP_MODE_START. (Since 1.12)
+ * @CLUTTER_STEP_END: equivalent to %CLUTTER_STEPS with a number of steps
+ * equal to 1, and a step mode of %CLUTTER_STEP_MODE_END. (Since: 1.12)
* @CLUTTER_ANIMATION_LAST: last animation mode, used as a guard for
* registered global alpha functions
*
@@ -233,6 +239,11 @@ typedef enum {
CLUTTER_EASE_OUT_BOUNCE,
CLUTTER_EASE_IN_OUT_BOUNCE,
+ /* step functions (see css3-transitions) */
+ CLUTTER_STEPS,
+ CLUTTER_STEP_START, /* steps(1, start) */
+ CLUTTER_STEP_END, /* steps(1, end) */
+
/* guard, before registered alpha functions */
CLUTTER_ANIMATION_LAST
} ClutterAnimationMode;
@@ -1273,6 +1284,26 @@ typedef enum {
CLUTTER_REPEAT_BOTH = CLUTTER_REPEAT_X_AXIS | CLUTTER_REPEAT_Y_AXIS
} ClutterContentRepeat;
+/**
+ * ClutterStepMode:
+ * @CLUTTER_STEP_MODE_START: The change in the value of a
+ * %CLUTTER_STEP progress mode should occur at the start of
+ * the transition
+ * @CLUTTER_STEP_MODE_END: The change in the value of a
+ * %CLUTTER_STEP progress mode should occur at the end of
+ * the transition
+ *
+ * Change the value transition of a step function.
+ *
+ * See clutter_timeline_set_step_progress().
+ *
+ * Since: 1.12
+ */
+typedef enum {
+ CLUTTER_STEP_MODE_START,
+ CLUTTER_STEP_MODE_END
+} ClutterStepMode;
+
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */
diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c
index 64fbd35..cdde665 100644
--- a/clutter/clutter-timeline.c
+++ b/clutter/clutter-timeline.c
@@ -150,6 +150,9 @@ struct _ClutterTimelinePrivate
GDestroyNotify progress_notify;
ClutterAnimationMode progress_mode;
+ gint n_steps;
+ ClutterStepMode step_mode;
+
guint is_playing : 1;
/* If we've just started playing and haven't yet gotten
@@ -812,6 +815,8 @@ clutter_timeline_init (ClutterTimeline *self)
ClutterTimelinePrivate);
priv->progress_mode = CLUTTER_LINEAR;
+ priv->n_steps = 1;
+ priv->step_mode = CLUTTER_STEP_MODE_END;
}
struct CheckIfMarkerHitClosure
@@ -2125,6 +2130,28 @@ clutter_timeline_progress_func (ClutterTimeline *timeline,
{
ClutterTimelinePrivate *priv = timeline->priv;
+ /* parametrized easing functions need to be handled separately */
+ switch (priv->progress_mode)
+ {
+ case CLUTTER_STEPS:
+ if (priv->step_mode == CLUTTER_STEP_MODE_START)
+ return clutter_ease_steps_start (elapsed, duration, priv->n_steps);
+ else if (priv->step_mode == CLUTTER_STEP_MODE_END)
+ return clutter_ease_steps_end (elapsed, duration, priv->n_steps);
+ else
+ g_assert_not_reached ();
+ break;
+
+ case CLUTTER_STEP_START:
+ return clutter_ease_steps_start (elapsed, duration, 1);
+
+ case CLUTTER_STEP_END:
+ return clutter_ease_steps_end (elapsed, duration, 1);
+
+ default:
+ break;
+ }
+
return clutter_easing_for_mode (priv->progress_mode, elapsed, duration);
}
@@ -2243,3 +2270,72 @@ clutter_timeline_get_current_repeat (ClutterTimeline *timeline)
return timeline->priv->current_repeat;
}
+
+/**
+ * clutter_timeline_set_step_progress:
+ * @timeline: a #ClutterTimeline
+ * @n_steps: the number of steps
+ * @step_mode: whether the change should happen at the start
+ * or at the end of the step
+ *
+ * Sets the #ClutterTimeline:progress-mode of the @timeline to %CLUTTER_STEPS
+ * and provides the parameters of the step function.
+ *
+ * Since: 1.12
+ */
+void
+clutter_timeline_set_step_progress (ClutterTimeline *timeline,
+ gint n_steps,
+ ClutterStepMode step_mode)
+{
+ ClutterTimelinePrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
+ g_return_if_fail (n_steps > 0);
+
+ priv = timeline->priv;
+
+ if (priv->progress_mode == CLUTTER_STEPS &&
+ priv->n_steps == n_steps &&
+ priv->step_mode == step_mode)
+ return;
+
+ priv->n_steps = n_steps;
+ priv->step_mode = step_mode;
+ clutter_timeline_set_progress_mode (timeline, CLUTTER_STEPS);
+}
+
+/**
+ * clutter_timeline_get_step_progress:
+ * @timeline: a #ClutterTimeline
+ * @n_steps: (out): return location for the number of steps, or %NULL
+ * @step_mode: (out): return location for the value change policy,
+ * or %NULL
+ *
+ * Retrieves the parameters of the step progress mode used by @timeline.
+ *
+ * Return value: %TRUE if the @timeline is using a step progress
+ * mode, and %FALSE otherwise
+ *
+ * Since: 1.12
+ */
+gboolean
+clutter_timeline_get_step_progress (ClutterTimeline *timeline,
+ gint *n_steps,
+ ClutterStepMode *step_mode)
+{
+ g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE);
+
+ if (timeline->priv->progress_mode != CLUTTER_STEPS ||
+ timeline->priv->progress_mode != CLUTTER_STEP_START ||
+ timeline->priv->progress_mode != CLUTTER_STEP_END)
+ return FALSE;
+
+ if (n_steps != NULL)
+ *n_steps = timeline->priv->n_steps;
+
+ if (step_mode != NULL)
+ *step_mode = timeline->priv->step_mode;
+
+ return TRUE;
+}
diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h
index 4457553..e153613 100644
--- a/clutter/clutter-timeline.h
+++ b/clutter/clutter-timeline.h
@@ -170,6 +170,14 @@ void clutter_timeline_set_progress_mode (Clutter
ClutterAnimationMode mode);
CLUTTER_AVAILABLE_IN_1_10
ClutterAnimationMode clutter_timeline_get_progress_mode (ClutterTimeline *timeline);
+CLUTTER_AVAILABLE_IN_1_12
+void clutter_timeline_set_step_progress (ClutterTimeline *timeline,
+ gint n_steps,
+ ClutterStepMode step_mode);
+CLUTTER_AVAILABLE_IN_1_12
+gboolean clutter_timeline_get_step_progress (ClutterTimeline *timeline,
+ gint *n_steps,
+ ClutterStepMode *step_mode);
CLUTTER_AVAILABLE_IN_1_10
gint64 clutter_timeline_get_duration_hint (ClutterTimeline *timeline);
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index 22a4b8d..66b791c 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -1283,6 +1283,7 @@ clutter_state_set_key
clutter_state_set_state
clutter_state_warp_to_state
clutter_static_color_get_type
+clutter_step_mode_get_type
clutter_swipe_action_get_type
clutter_swipe_action_new
clutter_swipe_direction_get_type
@@ -1463,6 +1464,7 @@ clutter_timeline_get_loop
clutter_timeline_get_progress_mode
clutter_timeline_get_progress
clutter_timeline_get_repeat_count
+clutter_timeline_get_step_progress
clutter_timeline_get_type
clutter_timeline_has_marker
clutter_timeline_is_playing
@@ -1478,6 +1480,7 @@ clutter_timeline_set_loop
clutter_timeline_set_progress_func
clutter_timeline_set_progress_mode
clutter_timeline_set_repeat_count
+clutter_timeline_set_step_progress
clutter_timeline_skip
clutter_timeline_start
clutter_timeline_stop
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
index 51482a4..e06620e 100644
--- a/tests/conform/Makefile.am
+++ b/tests/conform/Makefile.am
@@ -22,6 +22,7 @@ units_sources += \
state.c \
timeline.c \
timeline-interpolate.c \
+ timeline-progress.c \
timeline-rewind.c \
$(NULL)
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index ef3408c..f57a589 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -231,6 +231,8 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/timeline", timeline_markers_from_script);
TEST_CONFORM_SKIP (g_test_slow (), "/timeline", timeline_interpolation);
TEST_CONFORM_SKIP (g_test_slow (), "/timeline", timeline_rewind);
+ TEST_CONFORM_SIMPLE ("/timeline", timeline_progress_mode);
+ TEST_CONFORM_SIMPLE ("/timeline", timeline_progress_step);
TEST_CONFORM_SIMPLE ("/score", score_base);
diff --git a/tests/conform/timeline-progress.c b/tests/conform/timeline-progress.c
new file mode 100644
index 0000000..9c966ca
--- /dev/null
+++ b/tests/conform/timeline-progress.c
@@ -0,0 +1,110 @@
+#include <glib.h>
+#include <clutter/clutter.h>
+#include "test-conform-common.h"
+
+void
+timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
+ gconstpointer dummy G_GNUC_UNUSED)
+{
+ ClutterTimeline *timeline;
+
+ timeline = clutter_timeline_new (1000);
+
+ if (g_test_verbose ())
+ g_print ("mode: step(3, end)\n");
+
+ clutter_timeline_rewind (timeline);
+ clutter_timeline_set_step_progress (timeline, 3, CLUTTER_STEP_MODE_END);
+ g_assert_cmpint (clutter_timeline_get_progress (timeline), ==, 0);
+
+ clutter_timeline_advance (timeline, 1000 / 3 - 1);
+ g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 0);
+
+ clutter_timeline_advance (timeline, 1000 / 3 + 1);
+ g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 333);
+
+ clutter_timeline_advance (timeline, 1000 / 3 * 2 - 1);
+ g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 333);
+
+ clutter_timeline_advance (timeline, 1000 / 3 * 2 + 1);
+ g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 666);
+
+ clutter_timeline_rewind (timeline);
+ clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_START);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 1);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_advance (timeline, 500);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_advance (timeline, 999);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_advance (timeline, 1000);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ if (g_test_verbose ())
+ g_print ("mode: step-start\n");
+
+ clutter_timeline_rewind (timeline);
+ clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_START);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 1);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_advance (timeline, 500);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_advance (timeline, 999);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_advance (timeline, 1000);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ if (g_test_verbose ())
+ g_print ("mode: step-end\n");
+
+ clutter_timeline_rewind (timeline);
+ clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_END);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 1);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 500);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 999);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 1000);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ g_object_unref (timeline);
+}
+
+void
+timeline_progress_mode (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
+ gconstpointer dummy G_GNUC_UNUSED)
+{
+ ClutterTimeline *timeline;
+
+ timeline = clutter_timeline_new (1000);
+
+ g_assert (clutter_timeline_get_progress_mode (timeline) == CLUTTER_LINEAR);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ clutter_timeline_advance (timeline, 500);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.5);
+
+ clutter_timeline_advance (timeline, 1000);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
+
+ clutter_timeline_rewind (timeline);
+ g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
+
+ g_object_unref (timeline);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]