mutter/doc/cookbook/animations.xml
2010-07-12 16:59:38 +01:00

186 lines
5.6 KiB
XML

<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<chapter id="animations">
<title>Animations</title>
<epigraph>
<attribution>the author of the epigraph</attribution>
<para>a short epigraph</para>
</epigraph>
<section id="animations-introduction">
<title>Introduction</title>
<para>introduction</para>
</section>
<section id="animations-inversion">
<title>Inverting Animations</title>
<section>
<title>Problem</title>
<para>You want to have an animation exactly mirroring another one
that you just played.</para>
</section>
<section>
<title>Solution</title>
<para>Reverse the direction of the <type>ClutterTimeline</type>
associated with the animation.</para>
<para>For example, here's how to invert an implicit
animation which moves an actor along the <varname>x</varname>
axis. The direction of the animation is inverted when the
movement along the <varname>x</varname> axis is completed; it is
also inverted if the mouse button is pressed on the actor.</para>
<para>First, set up the animation:</para>
<informalexample>
<programlisting>
<![CDATA[
ClutterAnimation *animation;
/*
* animate actor to x = 300.0;
* the implicit animation functions return a ClutterAnimation
* which we can use to invert the timeline
*/
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_OUT_CUBIC,
2000,
"x", 300.0,
NULL);
/* callback for when the animation completes */
g_signal_connect (animation,
"completed",
G_CALLBACK (_animation_done_cb),
NULL);
/*
* callback for when the mouse button is pressed on the actor;
* note the animation is passed as user data, so we can
* get at the timeline
*/
g_signal_connect (actor,
"button-press-event",
G_CALLBACK (_on_click_cb),
animation);
]]>
</programlisting>
</informalexample>
<para>Next, add a function for inverting the timeline:</para>
<informalexample>
<programlisting>
<![CDATA[
static void
_invert_timeline (ClutterTimeline *timeline)
{
ClutterTimelineDirection direction = clutter_timeline_get_direction (timeline);
if (direction == CLUTTER_TIMELINE_FORWARD)
direction = CLUTTER_TIMELINE_BACKWARD;
else
direction = CLUTTER_TIMELINE_FORWARD;
clutter_timeline_set_direction (timeline, direction);
}
]]>
</programlisting>
</informalexample>
<para>Then add a function which calls <function>_invert_timeline</function>
when the animation completes. More importantly, the callback should
stop emission of the "completed" signal by the animation. This
prevents the <type>ClutterAnimation</type> underlying the implicit
animation from being unreferenced; which in turn allows it to be
inverted:</para>
<informalexample>
<programlisting>
<![CDATA[
static void
_animation_done_cb (ClutterAnimation *animation,
gpointer user_data)
{
/* stop the completed signal before the ClutterAnimation is unreferenced */
g_signal_stop_emission_by_name (animation, "completed");
/* invert the timeline associated with the animation */
ClutterTimeline *timeline = clutter_animation_get_timeline (animation);
_invert_timeline (timeline);
}
]]>
</programlisting>
</informalexample>
<para>Finally, the click callback function uses the same
<function>_invert_timeline</function> function if the animation
is playing; but if the animation is stopped, it will
start it instead:</para>
<informalexample>
<programlisting>
<![CDATA[
static void
_on_click_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterAnimation *animation = (ClutterAnimation *)user_data;
ClutterTimeline *timeline = clutter_animation_get_timeline (animation);
if (clutter_timeline_is_playing (timeline))
{
_invert_timeline (timeline);
}
else
{
clutter_timeline_start (timeline);
}
}
]]>
</programlisting>
</informalexample>
</section>
<section>
<title>Discussion</title>
<para>If you are using <type>ClutterAnimator</type> rather than
implicit animations, <function>clutter_animator_get_timeline()</function>
enables you to get the underlying timeline; you could then use
the techniques shown above to invert it.</para>
<para><type>ClutterState</type> enables a different approach
to "inverting" an animation: rather than having a single animation
which you invert, you would define two or more
<emphasis>keys</emphasis> for an actor (or set of actors) and
transition between them.</para>
<para>For the example above, you would define two keys:
one for the actor's initial position; and a second for the actor
at <code>x = 300.0</code>. You would also define the
transition between them: 2000 milliseconds with a
<constant>CLUTTER_EASE_IN_OUT_CUBIC</constant> easing mode.</para>
<para>With the states defined, you would then use
<function>clutter_state_set_state()</function> inside callbacks to
animate the actor between the two <varname>x</varname> positions.
Behind the scenes, <type>ClutterState</type> would handle the
animations and timelines for you.</para>
</section>
</section>
</chapter>