1 #include <stdlib.h>
2 #include <clutter/clutter.h>
3
4 static gboolean
on_enter(ClutterActor * actor,ClutterEvent * event)5 on_enter (ClutterActor *actor,
6 ClutterEvent *event)
7 {
8 ClutterTransition *t;
9
10 t = clutter_actor_get_transition (actor, "curl");
11 if (t == NULL)
12 {
13 t = clutter_property_transition_new ("@effects.curl.period");
14 clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250);
15 clutter_actor_add_transition (actor, "curl", t);
16 g_object_unref (t);
17 }
18
19 clutter_transition_set_from (t, G_TYPE_DOUBLE, 0.0);
20 clutter_transition_set_to (t, G_TYPE_DOUBLE, 0.25);
21 clutter_timeline_rewind (CLUTTER_TIMELINE (t));
22 clutter_timeline_start (CLUTTER_TIMELINE (t));
23
24 return CLUTTER_EVENT_STOP;
25 }
26
27 static gboolean
on_leave(ClutterActor * actor,ClutterEvent * event)28 on_leave (ClutterActor *actor,
29 ClutterEvent *event)
30 {
31 ClutterTransition *t;
32
33 t = clutter_actor_get_transition (actor, "curl");
34 if (t == NULL)
35 {
36 t = clutter_property_transition_new ("@effects.curl.period");
37 clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250);
38 clutter_actor_add_transition (actor, "curl", t);
39 g_object_unref (t);
40 }
41
42 clutter_transition_set_from (t, G_TYPE_DOUBLE, 0.25);
43 clutter_transition_set_to (t, G_TYPE_DOUBLE, 0.0);
44 clutter_timeline_rewind (CLUTTER_TIMELINE (t));
45 clutter_timeline_start (CLUTTER_TIMELINE (t));
46
47 return CLUTTER_EVENT_STOP;
48 }
49
50 static void
on_drag_begin(ClutterDragAction * action,ClutterActor * actor,gfloat event_x,gfloat event_y,ClutterModifierType modifiers)51 on_drag_begin (ClutterDragAction *action,
52 ClutterActor *actor,
53 gfloat event_x,
54 gfloat event_y,
55 ClutterModifierType modifiers)
56 {
57 gboolean is_copy = (modifiers & CLUTTER_SHIFT_MASK) ? TRUE : FALSE;
58 ClutterActor *drag_handle = NULL;
59 ClutterTransition *t;
60
61 if (is_copy)
62 {
63 ClutterActor *stage = clutter_actor_get_stage (actor);
64
65 drag_handle = clutter_actor_new ();
66 clutter_actor_set_size (drag_handle, 48, 48);
67
68 clutter_actor_set_background_color (drag_handle, CLUTTER_COLOR_DarkSkyBlue);
69
70 clutter_actor_add_child (stage, drag_handle);
71 clutter_actor_set_position (drag_handle, event_x, event_y);
72 }
73 else
74 drag_handle = actor;
75
76 clutter_drag_action_set_drag_handle (action, drag_handle);
77
78 /* fully desaturate the actor */
79 t = clutter_actor_get_transition (actor, "disable");
80 if (t == NULL)
81 {
82 t = clutter_property_transition_new ("@effects.disable.factor");
83 clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250);
84 clutter_actor_add_transition (actor, "disable", t);
85 g_object_unref (t);
86 }
87
88 clutter_transition_set_from (t, G_TYPE_DOUBLE, 0.0);
89 clutter_transition_set_to (t, G_TYPE_DOUBLE, 1.0);
90 clutter_timeline_rewind (CLUTTER_TIMELINE (t));
91 clutter_timeline_start (CLUTTER_TIMELINE (t));
92 }
93
94 static void
on_drag_end(ClutterDragAction * action,ClutterActor * actor,gfloat event_x,gfloat event_y,ClutterModifierType modifiers)95 on_drag_end (ClutterDragAction *action,
96 ClutterActor *actor,
97 gfloat event_x,
98 gfloat event_y,
99 ClutterModifierType modifiers)
100 {
101 ClutterActor *drag_handle;
102 ClutterTransition *t;
103
104 drag_handle = clutter_drag_action_get_drag_handle (action);
105 if (actor != drag_handle)
106 {
107 gfloat real_x, real_y;
108 ClutterActor *parent;
109
110 /* if we are dragging a copy we can destroy the copy now
111 * and animate the real actor to the drop coordinates,
112 * transformed in the parent's coordinate space
113 */
114 clutter_actor_save_easing_state (drag_handle);
115 clutter_actor_set_easing_mode (drag_handle, CLUTTER_LINEAR);
116 clutter_actor_set_opacity (drag_handle, 0);
117 clutter_actor_restore_easing_state (drag_handle);
118 g_signal_connect (drag_handle, "transitions-completed",
119 G_CALLBACK (clutter_actor_destroy),
120 NULL);
121
122 parent = clutter_actor_get_parent (actor);
123 clutter_actor_transform_stage_point (parent, event_x, event_y,
124 &real_x,
125 &real_y);
126
127 clutter_actor_save_easing_state (actor);
128 clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
129 clutter_actor_set_position (actor, real_x, real_y);
130 clutter_actor_restore_easing_state (actor);
131 }
132
133 t = clutter_actor_get_transition (actor, "disable");
134 if (t == NULL)
135 {
136 t = clutter_property_transition_new ("@effects.disable.factor");
137 clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250);
138 clutter_actor_add_transition (actor, "disable", t);
139 g_object_unref (t);
140 }
141
142 clutter_transition_set_from (t, G_TYPE_DOUBLE, 1.0);
143 clutter_transition_set_to (t, G_TYPE_DOUBLE, 0.0);
144 clutter_timeline_rewind (CLUTTER_TIMELINE (t));
145 clutter_timeline_start (CLUTTER_TIMELINE (t));
146 }
147
148 static ClutterDragAxis
get_drag_axis(const gchar * str)149 get_drag_axis (const gchar *str)
150 {
151 if (str == NULL || *str == '\0')
152 return CLUTTER_DRAG_AXIS_NONE;
153
154 if (*str == 'x' || *str == 'X')
155 return CLUTTER_DRAG_X_AXIS;
156
157 if (*str == 'y' || *str == 'Y')
158 return CLUTTER_DRAG_Y_AXIS;
159
160 g_warn_if_reached ();
161
162 return CLUTTER_DRAG_AXIS_NONE;
163 }
164
165 static gchar *drag_axis = NULL;
166 static gint x_drag_threshold = 0;
167 static gint y_drag_threshold = 0;
168
169 static GOptionEntry entries[] = {
170 {
171 "x-threshold", 'x',
172 0,
173 G_OPTION_ARG_INT,
174 &x_drag_threshold,
175 "Set the horizontal drag threshold", "PIXELS"
176 },
177 {
178 "y-threshold", 'y',
179 0,
180 G_OPTION_ARG_INT,
181 &y_drag_threshold,
182 "Set the vertical drag threshold", "PIXELS"
183 },
184 {
185 "axis", 'a',
186 0,
187 G_OPTION_ARG_STRING,
188 &drag_axis,
189 "Set the drag axis", "AXIS"
190 },
191
192 { NULL }
193 };
194
195 int
main(int argc,char * argv[])196 main (int argc, char *argv[])
197 {
198 ClutterActor *stage, *handle;
199 ClutterAction *action;
200 GError *error;
201
202 error = NULL;
203 if (clutter_init_with_args (&argc, &argv,
204 "test-drag",
205 entries,
206 NULL,
207 &error) != CLUTTER_INIT_SUCCESS)
208 {
209 g_print ("Unable to run drag-action: %s\n", error->message);
210 g_error_free (error);
211
212 return EXIT_FAILURE;
213 }
214
215 stage = clutter_stage_new ();
216 clutter_stage_set_title (CLUTTER_STAGE (stage), "Drag Test");
217 clutter_actor_set_size (stage, 800, 600);
218 g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
219
220 handle = clutter_actor_new ();
221 clutter_actor_set_background_color (handle, CLUTTER_COLOR_SkyBlue);
222 clutter_actor_set_size (handle, 128, 128);
223 clutter_actor_set_position (handle, (800 - 128) / 2, (600 - 128) / 2);
224 clutter_actor_set_reactive (handle, TRUE);
225 clutter_actor_add_child (stage, handle);
226 g_signal_connect (handle, "enter-event", G_CALLBACK (on_enter), NULL);
227 g_signal_connect (handle, "leave-event", G_CALLBACK (on_leave), NULL);
228
229 action = clutter_drag_action_new ();
230 clutter_drag_action_set_drag_threshold (CLUTTER_DRAG_ACTION (action),
231 x_drag_threshold,
232 y_drag_threshold);
233 clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action),
234 get_drag_axis (drag_axis));
235
236 g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL);
237 g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL);
238
239 clutter_actor_add_action (handle, action);
240
241 clutter_actor_add_effect_with_name (handle, "disable", clutter_desaturate_effect_new (0.0));
242 clutter_actor_add_effect_with_name (handle, "curl", clutter_page_turn_effect_new (0.0, 45.0, 12.0));
243
244 clutter_actor_show (stage);
245
246 clutter_main ();
247
248 return EXIT_SUCCESS;
249 }
250