1 #include <stdlib.h>
2 #include <gmodule.h>
3 #include <clutter/clutter.h>
4
5 /* all the easing modes provided by Clutter */
6 static const struct {
7 const gchar *name;
8 ClutterAnimationMode mode;
9 } easing_modes[] = {
10 { "linear", CLUTTER_LINEAR },
11 { "easeInQuad", CLUTTER_EASE_IN_QUAD },
12 { "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
13 { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
14 { "easeInCubic", CLUTTER_EASE_IN_CUBIC },
15 { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
16 { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
17 { "easeInQuart", CLUTTER_EASE_IN_QUART },
18 { "easeOutQuart", CLUTTER_EASE_OUT_QUART },
19 { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
20 { "easeInQuint", CLUTTER_EASE_IN_QUINT },
21 { "easeOutQuint", CLUTTER_EASE_OUT_QUINT },
22 { "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT },
23 { "easeInSine", CLUTTER_EASE_IN_SINE },
24 { "easeOutSine", CLUTTER_EASE_OUT_SINE },
25 { "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE },
26 { "easeInExpo", CLUTTER_EASE_IN_EXPO },
27 { "easeOutExpo", CLUTTER_EASE_OUT_EXPO },
28 { "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO },
29 { "easeInCirc", CLUTTER_EASE_IN_CIRC },
30 { "easeOutCirc", CLUTTER_EASE_OUT_CIRC },
31 { "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC },
32 { "easeInElastic", CLUTTER_EASE_IN_ELASTIC },
33 { "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC },
34 { "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC },
35 { "easeInBack", CLUTTER_EASE_IN_BACK },
36 { "easeOutBack", CLUTTER_EASE_OUT_BACK },
37 { "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK },
38 { "easeInBounce", CLUTTER_EASE_IN_BOUNCE },
39 { "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE },
40 { "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE },
41 };
42
43 #define HELP_TEXT "Easing mode: %s (%d of %d)\n" \
44 "Left click to tween\n" \
45 "Right click to change the easing mode"
46
47 static const gint n_easing_modes = G_N_ELEMENTS (easing_modes);
48 static gint current_mode = 0;
49
50 static gint duration = 1;
51 static gboolean recenter = FALSE;
52
53 static ClutterActor *main_stage = NULL;
54 static ClutterActor *easing_mode_label = NULL;
55
56 static ClutterAnimation *last_animation = NULL;
57
58 /* recenter_bouncer:
59 *
60 * repositions (through an animation) the bouncer at the center of the stage
61 */
62 static void
recenter_bouncer(ClutterAnimation * animation,ClutterActor * rectangle)63 recenter_bouncer (ClutterAnimation *animation,
64 ClutterActor *rectangle)
65 {
66 gfloat base_x, base_y;
67 gint cur_mode;
68
69 base_x = clutter_actor_get_width (main_stage) / 2;
70 base_y = clutter_actor_get_height (main_stage) / 2;
71
72 cur_mode = easing_modes[current_mode].mode;
73
74 clutter_actor_animate (rectangle, cur_mode, 250,
75 "x", base_x,
76 "y", base_y,
77 NULL);
78 }
79
80 static gboolean
on_button_press(ClutterActor * actor,ClutterButtonEvent * event,ClutterActor * rectangle)81 on_button_press (ClutterActor *actor,
82 ClutterButtonEvent *event,
83 ClutterActor *rectangle)
84 {
85 if (event->button == CLUTTER_BUTTON_SECONDARY)
86 {
87 gchar *text;
88
89 /* cycle through the various easing modes */
90 current_mode = (current_mode + 1 < n_easing_modes)
91 ? current_mode + 1
92 : 0;
93
94 /* update the text of the label */
95 text = g_strdup_printf (HELP_TEXT,
96 easing_modes[current_mode].name,
97 current_mode + 1,
98 n_easing_modes);
99
100 clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text);
101 g_free (text);
102 }
103 else if (event->button == CLUTTER_BUTTON_PRIMARY)
104 {
105 ClutterAnimation *animation;
106 ClutterAnimationMode cur_mode;
107
108 cur_mode = easing_modes[current_mode].mode;
109
110 /* tween the actor using the current easing mode */
111 animation =
112 clutter_actor_animate (rectangle, cur_mode, duration * 1000,
113 "x", event->x,
114 "y", event->y,
115 NULL);
116
117 /* if we were asked to, recenter the bouncer at the end of the
118 * animation. we keep track of the animation to avoid connecting
119 * the signal handler to the same Animation twice.
120 */
121 if (recenter && last_animation != animation)
122 g_signal_connect_after (animation, "completed",
123 G_CALLBACK (recenter_bouncer),
124 rectangle);
125
126 last_animation = animation;
127 }
128
129 return TRUE;
130 }
131
132 static gboolean
draw_bouncer(ClutterCairoTexture * texture,cairo_t * cr)133 draw_bouncer (ClutterCairoTexture *texture,
134 cairo_t *cr)
135 {
136 const ClutterColor *bouncer_color;
137 cairo_pattern_t *pattern;
138 guint width, height;
139 float radius;
140
141 clutter_cairo_texture_get_surface_size (texture, &width, &height);
142
143 radius = MAX (width, height);
144
145 clutter_cairo_texture_clear (texture);
146
147 cairo_arc (cr, radius / 2, radius / 2, radius / 2, 0.0, 2.0 * G_PI);
148
149 bouncer_color = CLUTTER_COLOR_DarkScarletRed;
150
151 pattern = cairo_pattern_create_radial (radius / 2, radius / 2, 0,
152 radius, radius, radius);
153 cairo_pattern_add_color_stop_rgba (pattern,
154 0,
155 bouncer_color->red / 255.0,
156 bouncer_color->green / 255.0,
157 bouncer_color->blue / 255.0,
158 bouncer_color->alpha / 255.0);
159 cairo_pattern_add_color_stop_rgba (pattern,
160 0.85,
161 bouncer_color->red / 255.0,
162 bouncer_color->green / 255.0,
163 bouncer_color->blue / 255.0,
164 0.25);
165
166 cairo_set_source (cr, pattern);
167 cairo_fill_preserve (cr);
168
169 cairo_pattern_destroy (pattern);
170
171 return TRUE;
172 }
173
174 static ClutterActor *
make_bouncer(gfloat width,gfloat height)175 make_bouncer (gfloat width,
176 gfloat height)
177 {
178 ClutterActor *retval;
179
180 retval = clutter_cairo_texture_new (width, height);
181 g_signal_connect (retval, "draw", G_CALLBACK (draw_bouncer), NULL);
182
183 clutter_actor_set_name (retval, "bouncer");
184 clutter_actor_set_size (retval, width, height);
185 clutter_actor_set_anchor_point (retval, width / 2, height / 2);
186 clutter_actor_set_reactive (retval, TRUE);
187
188 /* make sure we draw the bouncer immediately */
189 clutter_cairo_texture_invalidate (CLUTTER_CAIRO_TEXTURE (retval));
190
191 return retval;
192 }
193
194 static GOptionEntry test_easing_entries[] = {
195 {
196 "re-center", 'r',
197 0,
198 G_OPTION_ARG_NONE, &recenter,
199 "Re-center the actor when the animation ends",
200 NULL
201 },
202 {
203 "duration", 'd',
204 0,
205 G_OPTION_ARG_INT, &duration,
206 "Duration of the animation",
207 "SECONDS"
208 },
209
210 { NULL }
211 };
212
213 G_MODULE_EXPORT int
test_easing_main(int argc,char * argv[])214 test_easing_main (int argc, char *argv[])
215 {
216 ClutterActor *stage, *rect, *label;
217 gchar *text;
218 gfloat stage_width, stage_height;
219 GError *error = NULL;
220
221 if (clutter_init_with_args (&argc, &argv,
222 NULL,
223 test_easing_entries,
224 NULL,
225 &error) != CLUTTER_INIT_SUCCESS)
226 return 1;
227
228 stage = clutter_stage_new ();
229 clutter_stage_set_title (CLUTTER_STAGE (stage), "Easing Modes");
230 clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue);
231 g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
232 main_stage = stage;
233
234 clutter_actor_get_size (stage, &stage_width, &stage_height);
235
236 /* create the actor that we want to tween */
237 rect = make_bouncer (50, 50);
238 clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
239 clutter_actor_set_position (rect, stage_width / 2, stage_height / 2);
240
241 text = g_strdup_printf (HELP_TEXT,
242 easing_modes[current_mode].name,
243 current_mode + 1,
244 n_easing_modes);
245
246 label = clutter_text_new ();
247 clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
248 clutter_text_set_text (CLUTTER_TEXT (label), text);
249 clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.95));
250 clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.95));
251 easing_mode_label = label;
252
253 g_free (text);
254
255 g_signal_connect (stage,
256 "button-press-event", G_CALLBACK (on_button_press),
257 rect);
258
259 clutter_actor_show (stage);
260
261 clutter_main ();
262
263 return EXIT_SUCCESS;
264 }
265
266 G_MODULE_EXPORT const char *
test_easing_describe(void)267 test_easing_describe (void)
268 {
269 return "Visualize all easing modes provided by Clutter";
270 }
271