cookbook: Refactored reusable animation example

Extracted the animation into its own JSON definition,
then create a new script and get the animation each
time a rectangle is clicked.

Removes the need to reparent onto the background and
copy property values to the rectangle after the animation,
and generally much cleaner.
This commit is contained in:
Elliot Smith 2010-09-01 10:21:23 +01:00
parent acc28cf60c
commit d4190cbf8c
4 changed files with 158 additions and 190 deletions

View File

@ -0,0 +1,63 @@
[
{
"type" : "ClutterGroup",
"id" : "rig"
},
{
"type" : "ClutterAnimator",
"id" : "bounce",
"timeline" : {
"type" : "ClutterTimeline",
"id" : "bounce_timeline",
"duration" : 2500
},
"properties" : [
{
"object" : "rig",
"name" : "x",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutCubic", 100.0 ],
[ 0.6, "easeOutCubic", 150.0 ],
[ 0.8, "linear", 350.0 ],
[ 1.0, "linear", 500.0 ]
]
},
{
"object" : "rig",
"name" : "y",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutCubic", 200.0 ],
[ 0.6, "easeOutBounce", 200.0 ],
[ 0.8, "linear", 200.0 ],
[ 1.0, "linear", 0.0 ]
]
},
{
"object" : "rig",
"name" : "scale-x",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutElastic", 2.0 ],
[ 0.6, "easeOutBounce", 4.0 ],
[ 0.8, "linear", 4.0 ],
[ 1.0, "linear", 1.0 ]
]
},
{
"object" : "rig",
"name" : "scale-y",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutElastic", 2.0 ],
[ 0.6, "easeOutBounce", 4.0 ],
[ 0.8, "linear", 4.0 ],
[ 1.0, "linear", 1.0 ]
]
}
]
}
]

View File

@ -0,0 +1,53 @@
[
{
"type" : "ClutterStage",
"id" : "stage",
"width" : 550,
"height" : 400,
"color" : "#333355ff",
"signals" : [
{ "name" : "destroy", "handler" : "clutter_main_quit" }
],
"children" : [
{
"type" : "ClutterRectangle",
"id" : "rect1",
"color" : "red",
"width" : 50,
"height" : 50,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "foo_button_pressed_cb" }
]
},
{
"type" : "ClutterRectangle",
"id" : "rect2",
"color" : "blue",
"width" : 50,
"height" : 50,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "foo_button_pressed_cb" }
]
},
{
"type" : "ClutterRectangle",
"id" : "rect3",
"color" : "green",
"width" : 50,
"height" : 50,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "foo_button_pressed_cb" }
]
}
]
}
]

View File

@ -1,12 +1,38 @@
#include <stdlib.h> #include <stdlib.h>
#include <clutter/clutter.h> #include <clutter/clutter.h>
#define UI_FILE "animations-reuse-ui.json"
#define ANIMATION_FILE "animations-reuse-animation.json"
static gboolean
_load_script (ClutterScript *script,
gchar *filename)
{
GError *error = NULL;
clutter_script_load_from_file (script, filename, &error);
if (error != NULL)
{
g_critical ("Error loading ClutterScript file %s\n%s", filename, error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
return TRUE;
}
gboolean gboolean
foo_button_pressed_cb (ClutterActor *actor, foo_button_pressed_cb (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer user_data) gpointer user_data)
{ {
ClutterScript *script = CLUTTER_SCRIPT (user_data); ClutterScript *ui = CLUTTER_SCRIPT (user_data);
ClutterStage *stage = CLUTTER_STAGE (clutter_script_get_object (ui, "stage"));
ClutterScript *script = clutter_script_new ();
_load_script (script, ANIMATION_FILE);
ClutterAnimator *bounce; ClutterAnimator *bounce;
ClutterActor *rig; ClutterActor *rig;
@ -18,13 +44,22 @@ foo_button_pressed_cb (ClutterActor *actor,
"bounce", &bounce, "bounce", &bounce,
NULL); NULL);
/* don't allow animation to be reused until it is complete */ /* remove the button press handler */
if (clutter_timeline_is_playing (bounce_timeline)) g_signal_handlers_disconnect_matched (actor,
return TRUE; G_SIGNAL_MATCH_FUNC,
0,
0,
NULL,
foo_button_pressed_cb,
NULL);
clutter_actor_set_position (rig, 0, 0); /* add a handler to clean up when the animation completes */
g_signal_connect_swapped (bounce_timeline,
"completed",
G_CALLBACK (g_object_unref),
script);
clutter_actor_set_scale (rig, 1.0, 1.0); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rig);
clutter_actor_reparent (actor, rig); clutter_actor_reparent (actor, rig);
@ -33,72 +68,13 @@ foo_button_pressed_cb (ClutterActor *actor,
return TRUE; return TRUE;
} }
/* set the actor's position to the rig's position
* but parented to the background;
* remove the click handler so the rectangle can't be animated again
*/
static void
_move_to_background_cb (ClutterActor *actor,
gpointer user_data)
{
ClutterActor *background = CLUTTER_ACTOR (user_data);
gfloat x, y;
clutter_actor_get_position (clutter_actor_get_parent (actor), &x, &y);
gdouble scale_x, scale_y;
clutter_actor_get_scale (clutter_actor_get_parent (actor), &scale_x, &scale_y);
clutter_actor_reparent (actor, background);
clutter_actor_set_position (actor, x, y);
clutter_actor_set_scale (actor, scale_x, scale_y);
g_signal_handlers_disconnect_matched (actor,
G_SIGNAL_MATCH_FUNC,
0,
0,
NULL,
foo_button_pressed_cb,
NULL);
}
void
foo_rig_animation_complete_cb (ClutterTimeline *timeline,
gpointer user_data)
{
ClutterScript *script = CLUTTER_SCRIPT (user_data);
ClutterContainer *rig;
ClutterActor *background;
clutter_script_get_objects (script,
"rig", &rig,
"background", &background,
NULL);
clutter_container_foreach (rig,
CLUTTER_CALLBACK (_move_to_background_cb),
background);
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
clutter_init (&argc, &argv); clutter_init (&argc, &argv);
gchar *filename = "animations-reuse.json";
GError *error = NULL;
ClutterScript *script = clutter_script_new (); ClutterScript *script = clutter_script_new ();
clutter_script_load_from_file (script, filename, &error); _load_script (script, UI_FILE);
if (error != NULL)
{
g_critical ("Error loading ClutterScript file %s\n%s", filename, error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
clutter_script_connect_signals (script, script); clutter_script_connect_signals (script, script);

View File

@ -1,124 +0,0 @@
[
{
"type" : "ClutterStage",
"id" : "stage",
"width" : 550,
"height" : 400,
"color" : "#333355ff",
"signals" : [
{ "name" : "destroy", "handler" : "clutter_main_quit" }
],
"children" : [
{
"type" : "ClutterRectangle",
"id" : "rect1",
"color" : "red",
"width" : 50,
"height" : 50,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "foo_button_pressed_cb" }
]
},
{
"type" : "ClutterRectangle",
"id" : "rect2",
"color" : "blue",
"width" : 50,
"height" : 50,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "foo_button_pressed_cb" }
]
},
{
"type" : "ClutterRectangle",
"id" : "rect3",
"color" : "green",
"width" : 50,
"height" : 50,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "foo_button_pressed_cb" }
]
},
{
"type" : "ClutterGroup",
"id" : "background"
},
{
"type" : "ClutterGroup",
"id" : "rig"
}
]
},
{
"type" : "ClutterAnimator",
"id" : "bounce",
"timeline" : {
"type" : "ClutterTimeline",
"id" : "bounce_timeline",
"duration" : 3000,
"signals" : [
{ "name" : "completed", "handler" : "foo_rig_animation_complete_cb" }
]
},
"properties" : [
{
"object" : "rig",
"name" : "x",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutCubic", 100.0 ],
[ 0.6, "easeOutCubic", 150.0 ],
[ 0.8, "linear", 350.0 ],
[ 1.0, "linear", 500.0 ]
]
},
{
"object" : "rig",
"name" : "y",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutCubic", 200.0 ],
[ 0.6, "easeOutBounce", 200.0 ],
[ 0.8, "linear", 200.0 ],
[ 1.0, "linear", 0.0 ]
]
},
{
"object" : "rig",
"name" : "scale-x",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutElastic", 2.0 ],
[ 0.6, "easeOutBounce", 4.0 ],
[ 0.8, "linear", 4.0 ],
[ 1.0, "linear", 1.0 ]
]
},
{
"object" : "rig",
"name" : "scale-y",
"ease-in" : true,
"keys" : [
[ 0.2, "easeOutElastic", 2.0 ],
[ 0.6, "easeOutBounce", 4.0 ],
[ 0.8, "linear", 4.0 ],
[ 1.0, "linear", 1.0 ]
]
}
]
}
]