1 #include <stdlib.h>
2 #include <clutter/clutter.h>
3 
4 #define TARGET_SIZE     200
5 #define HANDLE_SIZE     128
6 
7 static ClutterActor *stage   = NULL;
8 static ClutterActor *target1 = NULL;
9 static ClutterActor *target2 = NULL;
10 static ClutterActor *drag    = NULL;
11 
12 static gboolean drop_successful = FALSE;
13 
14 static void add_drag_object (ClutterActor *target);
15 
16 static void
on_drag_end(ClutterDragAction * action,ClutterActor * actor,gfloat event_x,gfloat event_y,ClutterModifierType modifiers)17 on_drag_end (ClutterDragAction   *action,
18              ClutterActor        *actor,
19              gfloat               event_x,
20              gfloat               event_y,
21              ClutterModifierType  modifiers)
22 {
23   ClutterActor *handle = clutter_drag_action_get_drag_handle (action);
24 
25   g_print ("Drag ended at: %.0f, %.0f\n",
26            event_x, event_y);
27 
28   clutter_actor_save_easing_state (actor);
29   clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR);
30   clutter_actor_set_opacity (actor, 255);
31   clutter_actor_restore_easing_state (actor);
32 
33   clutter_actor_save_easing_state (handle);
34 
35   if (!drop_successful)
36     {
37       ClutterActor *parent = clutter_actor_get_parent (actor);
38       gfloat x_pos, y_pos;
39 
40       clutter_actor_save_easing_state (parent);
41       clutter_actor_set_easing_mode (parent, CLUTTER_LINEAR);
42       clutter_actor_set_opacity (parent, 255);
43       clutter_actor_restore_easing_state (parent);
44 
45       clutter_actor_get_transformed_position (actor, &x_pos, &y_pos);
46 
47       clutter_actor_set_easing_mode (handle, CLUTTER_EASE_OUT_BOUNCE);
48       clutter_actor_set_position (handle, x_pos, y_pos);
49       clutter_actor_set_opacity (handle, 0);
50 
51     }
52   else
53     {
54       clutter_actor_set_easing_mode (handle, CLUTTER_LINEAR);
55       clutter_actor_set_opacity (handle, 0);
56     }
57 
58   clutter_actor_restore_easing_state (handle);
59 
60   g_signal_connect (handle, "transitions-completed",
61                     G_CALLBACK (clutter_actor_destroy),
62                     NULL);
63 }
64 
65 static void
on_drag_begin(ClutterDragAction * action,ClutterActor * actor,gfloat event_x,gfloat event_y,ClutterModifierType modifiers)66 on_drag_begin (ClutterDragAction   *action,
67                ClutterActor        *actor,
68                gfloat               event_x,
69                gfloat               event_y,
70                ClutterModifierType  modifiers)
71 {
72   ClutterActor *handle;
73   gfloat x_pos, y_pos;
74 
75   clutter_actor_get_position (actor, &x_pos, &y_pos);
76 
77   handle = clutter_actor_new ();
78   clutter_actor_set_background_color (handle, CLUTTER_COLOR_DarkSkyBlue);
79   clutter_actor_set_size (handle, 128, 128);
80   clutter_actor_set_position (handle, event_x - x_pos, event_y - y_pos);
81   clutter_actor_add_child (stage, handle);
82 
83   clutter_drag_action_set_drag_handle (action, handle);
84 
85   clutter_actor_save_easing_state (actor);
86   clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR);
87   clutter_actor_set_opacity (actor, 128);
88   clutter_actor_restore_easing_state (actor);
89 
90   drop_successful = FALSE;
91 }
92 
93 static void
add_drag_object(ClutterActor * target)94 add_drag_object (ClutterActor *target)
95 {
96   ClutterActor *parent;
97 
98   if (drag == NULL)
99     {
100       ClutterAction *action;
101 
102       drag = clutter_actor_new ();
103       clutter_actor_set_background_color (drag, CLUTTER_COLOR_LightSkyBlue);
104       clutter_actor_set_size (drag, HANDLE_SIZE, HANDLE_SIZE);
105       clutter_actor_set_position (drag,
106                                   (TARGET_SIZE - HANDLE_SIZE) / 2.0,
107                                   (TARGET_SIZE - HANDLE_SIZE) / 2.0);
108       clutter_actor_set_reactive (drag, TRUE);
109 
110       action = clutter_drag_action_new ();
111       g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL);
112       g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL);
113 
114       clutter_actor_add_action (drag, action);
115     }
116 
117   parent = clutter_actor_get_parent (drag);
118   if (parent == target)
119     {
120       clutter_actor_save_easing_state (target);
121       clutter_actor_set_easing_mode (target, CLUTTER_LINEAR);
122       clutter_actor_set_opacity (target, 255);
123       clutter_actor_restore_easing_state (target);
124       return;
125     }
126 
127   g_object_ref (drag);
128   if (parent != NULL && parent != stage)
129     {
130       clutter_actor_remove_child (parent, drag);
131 
132       clutter_actor_save_easing_state (parent);
133       clutter_actor_set_easing_mode (parent, CLUTTER_LINEAR);
134       clutter_actor_set_opacity (parent, 64);
135       clutter_actor_restore_easing_state (parent);
136     }
137 
138   clutter_actor_add_child (target, drag);
139 
140   clutter_actor_save_easing_state (target);
141   clutter_actor_set_easing_mode (target, CLUTTER_LINEAR);
142   clutter_actor_set_opacity (target, 255);
143   clutter_actor_restore_easing_state (target);
144 
145   g_object_unref (drag);
146 }
147 
148 static void
on_target_over(ClutterDropAction * action,ClutterActor * actor,gpointer _data)149 on_target_over (ClutterDropAction *action,
150                 ClutterActor      *actor,
151                 gpointer           _data)
152 {
153   gboolean is_over = GPOINTER_TO_UINT (_data);
154   guint8 final_opacity = is_over ? 128 : 64;
155   ClutterActor *target;
156 
157   target = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
158 
159   clutter_actor_save_easing_state (target);
160   clutter_actor_set_easing_mode (target, CLUTTER_LINEAR);
161   clutter_actor_set_opacity (target, final_opacity);
162   clutter_actor_restore_easing_state (target);
163 }
164 
165 static void
on_target_drop(ClutterDropAction * action,ClutterActor * actor,gfloat event_x,gfloat event_y)166 on_target_drop (ClutterDropAction *action,
167                 ClutterActor      *actor,
168                 gfloat             event_x,
169                 gfloat             event_y)
170 {
171   gfloat actor_x, actor_y;
172 
173   actor_x = actor_y = 0.0f;
174 
175   clutter_actor_transform_stage_point (actor, event_x, event_y,
176                                        &actor_x,
177                                        &actor_y);
178 
179   g_print ("Dropped at %.0f, %.0f (screen: %.0f, %.0f)\n",
180            actor_x, actor_y,
181            event_x, event_y);
182 
183   drop_successful = TRUE;
184   add_drag_object (actor);
185 }
186 
187 int
main(int argc,char * argv[])188 main (int argc, char *argv[])
189 {
190   ClutterActor *dummy;
191 
192   if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
193     return EXIT_FAILURE;
194 
195   stage = clutter_stage_new ();
196   clutter_stage_set_title (CLUTTER_STAGE (stage), "Drop Action");
197   g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
198 
199   target1 = clutter_actor_new ();
200   clutter_actor_set_background_color (target1, CLUTTER_COLOR_LightScarletRed);
201   clutter_actor_set_size (target1, TARGET_SIZE, TARGET_SIZE);
202   clutter_actor_set_opacity (target1, 64);
203   clutter_actor_add_constraint (target1, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
204   clutter_actor_set_x (target1, 10);
205   clutter_actor_set_reactive (target1, TRUE);
206 
207   clutter_actor_add_action_with_name (target1, "drop", clutter_drop_action_new ());
208   g_signal_connect (clutter_actor_get_action (target1, "drop"),
209                     "over-in",
210                     G_CALLBACK (on_target_over),
211                     GUINT_TO_POINTER (TRUE));
212   g_signal_connect (clutter_actor_get_action (target1, "drop"),
213                     "over-out",
214                     G_CALLBACK (on_target_over),
215                     GUINT_TO_POINTER (FALSE));
216   g_signal_connect (clutter_actor_get_action (target1, "drop"),
217                     "drop",
218                     G_CALLBACK (on_target_drop),
219                     NULL);
220 
221   dummy = clutter_actor_new ();
222   clutter_actor_set_background_color (dummy, CLUTTER_COLOR_DarkOrange);
223   clutter_actor_set_size (dummy,
224                           640 - (2 * 10) - (2 * (TARGET_SIZE + 10)),
225                           TARGET_SIZE);
226   clutter_actor_add_constraint (dummy, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
227   clutter_actor_add_constraint (dummy, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
228   clutter_actor_set_reactive (dummy, TRUE);
229 
230   target2 = clutter_actor_new ();
231   clutter_actor_set_background_color (target2, CLUTTER_COLOR_LightChameleon);
232   clutter_actor_set_size (target2, TARGET_SIZE, TARGET_SIZE);
233   clutter_actor_set_opacity (target2, 64);
234   clutter_actor_add_constraint (target2, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
235   clutter_actor_set_x (target2, 640 - TARGET_SIZE - 10);
236   clutter_actor_set_reactive (target2, TRUE);
237 
238   clutter_actor_add_action_with_name (target2, "drop", clutter_drop_action_new ());
239   g_signal_connect (clutter_actor_get_action (target2, "drop"),
240                     "over-in",
241                     G_CALLBACK (on_target_over),
242                     GUINT_TO_POINTER (TRUE));
243   g_signal_connect (clutter_actor_get_action (target2, "drop"),
244                     "over-out",
245                     G_CALLBACK (on_target_over),
246                     GUINT_TO_POINTER (FALSE));
247   g_signal_connect (clutter_actor_get_action (target2, "drop"),
248                     "drop",
249                     G_CALLBACK (on_target_drop),
250                     NULL);
251 
252   clutter_actor_add_child (stage, target1);
253   clutter_actor_add_child (stage, dummy);
254   clutter_actor_add_child (stage, target2);
255 
256   add_drag_object (target1);
257 
258   clutter_actor_show (stage);
259 
260   clutter_main ();
261 
262   return EXIT_SUCCESS;
263 }
264