ClutterDropAction

ClutterDropAction — An action for drop targets

Synopsis

struct              ClutterDropAction;
struct              ClutterDropActionClass;
ClutterAction *     clutter_drop_action_new             (void);

Object Hierarchy

  GObject
   +----GInitiallyUnowned
         +----ClutterActorMeta
               +----ClutterAction
                     +----ClutterDropAction

Signals

  "can-drop"                                       : Run Last
  "drop"                                           : Run Last
  "drop-cancel"                                    : Run Last
  "over-in"                                        : Run Last
  "over-out"                                       : Run Last

Description

ClutterDropAction is a ClutterAction that allows a ClutterActor implementation to control what happens when an actor dragged using a ClutterDragAction crosses the target area or when a dragged actor is released (or "dropped") on the target area.

A trivial use of ClutterDropAction consists in connecting to the "drop" signal and handling the drop from there, for instance:

1
2
3
4
ClutterAction *action = clutter_drop_action ();

g_signal_connect (action, "drop", G_CALLBACK (on_drop), NULL);
clutter_actor_add_action (an_actor, action);

The "can-drop" can be used to control whether the "drop" signal is going to be emitted; returning FALSE from a handler connected to the "can-drop" signal will cause the "drop" signal to be skipped when the input device button is released.

Example 6. Drop targets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#include <stdlib.h>
#include <clutter/clutter.h>

#define TARGET_SIZE     200
#define HANDLE_SIZE     128

static ClutterActor *stage   = NULL;
static ClutterActor *target1 = NULL;
static ClutterActor *target2 = NULL;
static ClutterActor *drag    = NULL;

static gboolean drop_successful = FALSE;

static void add_drag_object (ClutterActor *target);

static void
on_drag_end (ClutterDragAction   *action,
             ClutterActor        *actor,
             gfloat               event_x,
             gfloat               event_y,
             ClutterModifierType  modifiers)
{
  ClutterActor *handle = clutter_drag_action_get_drag_handle (action);

  g_print ("Drag ended at: %.0f, %.0f\n",
           event_x, event_y);

  clutter_actor_save_easing_state (actor);
  clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR);
  clutter_actor_set_opacity (actor, 255);
  clutter_actor_restore_easing_state (actor);

  clutter_actor_save_easing_state (handle);

  if (!drop_successful)
    {
      ClutterActor *parent = clutter_actor_get_parent (actor);
      gfloat x_pos, y_pos;

      clutter_actor_save_easing_state (parent);
      clutter_actor_set_easing_mode (parent, CLUTTER_LINEAR);
      clutter_actor_set_opacity (parent, 255);
      clutter_actor_restore_easing_state (parent);

      clutter_actor_get_transformed_position (actor, &x_pos, &y_pos);

      clutter_actor_set_easing_mode (handle, CLUTTER_EASE_OUT_BOUNCE);
      clutter_actor_set_position (handle, x_pos, y_pos);
      clutter_actor_set_opacity (handle, 0);
      clutter_actor_restore_easing_state (handle);

    }
  else
    {
      clutter_actor_set_easing_mode (handle, CLUTTER_LINEAR);
      clutter_actor_set_opacity (handle, 0);
    }

  clutter_actor_restore_easing_state (handle);

  g_signal_connect (handle, "transitions-completed",
                    G_CALLBACK (clutter_actor_destroy),
                    NULL);
}

static void
on_drag_begin (ClutterDragAction   *action,
               ClutterActor        *actor,
               gfloat               event_x,
               gfloat               event_y,
               ClutterModifierType  modifiers)
{
  ClutterActor *handle;
  gfloat x_pos, y_pos;

  clutter_actor_get_position (actor, &x_pos, &y_pos);

  handle = clutter_actor_new ();
  clutter_actor_set_background_color (handle, CLUTTER_COLOR_DarkSkyBlue);
  clutter_actor_set_size (handle, 128, 128);
  clutter_actor_set_position (handle, event_x - x_pos, event_y - y_pos);
  clutter_actor_add_child (stage, handle);

  clutter_drag_action_set_drag_handle (action, handle);

  clutter_actor_save_easing_state (actor);
  clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR);
  clutter_actor_set_opacity (actor, 128);
  clutter_actor_restore_easing_state (actor);

  drop_successful = FALSE;
}

static void
add_drag_object (ClutterActor *target)
{
  ClutterActor *parent;

  if (drag == NULL)
    {
      ClutterAction *action;

      drag = clutter_actor_new ();
      clutter_actor_set_background_color (drag, CLUTTER_COLOR_LightSkyBlue);
      clutter_actor_set_size (drag, HANDLE_SIZE, HANDLE_SIZE);
      clutter_actor_set_position (drag,
                                  (TARGET_SIZE - HANDLE_SIZE) / 2.0,
                                  (TARGET_SIZE - HANDLE_SIZE) / 2.0);
      clutter_actor_set_reactive (drag, TRUE);

      action = clutter_drag_action_new ();
      g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL);
      g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL);

      clutter_actor_add_action (drag, action);
    }

  parent = clutter_actor_get_parent (drag);
  if (parent == target)
    {
      clutter_actor_save_easing_state (target);
      clutter_actor_set_easing_mode (target, CLUTTER_LINEAR);
      clutter_actor_set_opacity (target, 255);
      clutter_actor_restore_easing_state (target);
      return;
    }

  g_object_ref (drag);
  if (parent != NULL && parent != stage)
    {
      clutter_actor_remove_child (parent, drag);

      clutter_actor_save_easing_state (parent);
      clutter_actor_set_easing_mode (parent, CLUTTER_LINEAR);
      clutter_actor_set_opacity (parent, 64);
      clutter_actor_restore_easing_state (parent);
    }

  clutter_actor_add_child (target, drag);

  clutter_actor_save_easing_state (target);
  clutter_actor_set_easing_mode (target, CLUTTER_LINEAR);
  clutter_actor_set_opacity (target, 255);
  clutter_actor_restore_easing_state (target);

  g_object_unref (drag);
}

static void
on_target_over (ClutterDropAction *action,
                ClutterActor      *actor,
                gpointer           _data)
{
  gboolean is_over = GPOINTER_TO_UINT (_data);
  guint8 final_opacity = is_over ? 128 : 64;
  ClutterActor *target;

  target = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));

  clutter_actor_save_easing_state (target);
  clutter_actor_set_easing_mode (target, CLUTTER_LINEAR);
  clutter_actor_set_opacity (target, final_opacity);
  clutter_actor_restore_easing_state (target);
}

static void
on_target_drop (ClutterDropAction *action,
                ClutterActor      *actor,
                gfloat             event_x,
                gfloat             event_y)
{
  gfloat actor_x, actor_y;

  actor_x = actor_y = 0.0f;

  clutter_actor_transform_stage_point (actor, event_x, event_y,
                                       &actor_x,
                                       &actor_y);

  g_print ("Dropped at %.0f, %.0f (screen: %.0f, %.0f)\n",
           actor_x, actor_y,
           event_x, event_y);

  drop_successful = TRUE;
  add_drag_object (actor);
}

int
main (int argc, char *argv[])
{
  ClutterActor *dummy;

  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return EXIT_FAILURE;

  stage = clutter_stage_new ();
  clutter_stage_set_title (CLUTTER_STAGE (stage), "Drop Action");
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  target1 = clutter_actor_new ();
  clutter_actor_set_background_color (target1, CLUTTER_COLOR_LightScarletRed);
  clutter_actor_set_size (target1, TARGET_SIZE, TARGET_SIZE);
  clutter_actor_set_opacity (target1, 64);
  clutter_actor_add_constraint (target1, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
  clutter_actor_set_x (target1, 10);
  clutter_actor_set_reactive (target1, TRUE);

  clutter_actor_add_action_with_name (target1, "drop", clutter_drop_action_new ());
  g_signal_connect (clutter_actor_get_action (target1, "drop"),
                    "over-in",
                    G_CALLBACK (on_target_over),
                    GUINT_TO_POINTER (TRUE));
  g_signal_connect (clutter_actor_get_action (target1, "drop"),
                    "over-out",
                    G_CALLBACK (on_target_over),
                    GUINT_TO_POINTER (FALSE));
  g_signal_connect (clutter_actor_get_action (target1, "drop"),
                    "drop",
                    G_CALLBACK (on_target_drop),
                    NULL);

  dummy = clutter_actor_new ();
  clutter_actor_set_background_color (dummy, CLUTTER_COLOR_DarkOrange);
  clutter_actor_set_size (dummy,
                          640 - (2 * 10) - (2 * (TARGET_SIZE + 10)),
                          TARGET_SIZE);
  clutter_actor_add_constraint (dummy, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
  clutter_actor_add_constraint (dummy, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
  clutter_actor_set_reactive (dummy, TRUE);

  target2 = clutter_actor_new ();
  clutter_actor_set_background_color (target2, CLUTTER_COLOR_LightChameleon);
  clutter_actor_set_size (target2, TARGET_SIZE, TARGET_SIZE);
  clutter_actor_set_opacity (target2, 64);
  clutter_actor_add_constraint (target2, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
  clutter_actor_set_x (target2, 640 - TARGET_SIZE - 10);
  clutter_actor_set_reactive (target2, TRUE);

  clutter_actor_add_action_with_name (target2, "drop", clutter_drop_action_new ());
  g_signal_connect (clutter_actor_get_action (target2, "drop"),
                    "over-in",
                    G_CALLBACK (on_target_over),
                    GUINT_TO_POINTER (TRUE));
  g_signal_connect (clutter_actor_get_action (target2, "drop"),
                    "over-out",
                    G_CALLBACK (on_target_over),
                    GUINT_TO_POINTER (FALSE));
  g_signal_connect (clutter_actor_get_action (target2, "drop"),
                    "drop",
                    G_CALLBACK (on_target_drop),
                    NULL);

  clutter_actor_add_child (stage, target1);
  clutter_actor_add_child (stage, dummy);
  clutter_actor_add_child (stage, target2);

  add_drag_object (target1);

  clutter_actor_show (stage);

  clutter_main ();

  return EXIT_SUCCESS;
}


It's important to note that ClutterDropAction will only work with actors dragged using ClutterDragAction.

ClutterDropAction is available since Clutter 1.8

Details

struct ClutterDropAction

struct ClutterDropAction;

The ClutterDropAction structure contains only private data and should be accessed using the provided API.

Since 1.8


struct ClutterDropActionClass

struct ClutterDropActionClass {
  gboolean (* can_drop) (ClutterDropAction *action,
                         ClutterActor      *actor,
                         gfloat             event_x,
                         gfloat             event_y);

  void     (* over_in)  (ClutterDropAction *action,
                         ClutterActor      *actor);
  void     (* over_out) (ClutterDropAction *action,
                         ClutterActor      *actor);

  void     (* drop)     (ClutterDropAction *action,
                         ClutterActor      *actor,
                         gfloat             event_x,
                         gfloat             event_y);
};

The ClutterDropActionClass structure contains only private data.

can_drop ()

class handler for the "can-drop" signal

over_in ()

class handler for the "over-in" signal

over_out ()

class handler for the "over-out" signal

drop ()

class handler for the "drop" signal

Since 1.8


clutter_drop_action_new ()

ClutterAction *     clutter_drop_action_new             (void);

Creates a new ClutterDropAction.

Use clutter_actor_add_action() to add the action to a ClutterActor.

Returns :

the newly created ClutterDropAction

Since 1.8

Signal Details

The "can-drop" signal

gboolean            user_function                      (ClutterDropAction *action,
                                                        ClutterActor      *actor,
                                                        gfloat             event_x,
                                                        gfloat             event_y,
                                                        gpointer           user_data)      : Run Last

The ::can-drop signal is emitted when the dragged actor is dropped on actor. The return value of the ::can-drop signal will determine whether or not the "drop" signal is going to be emitted on action.

The default implementation of ClutterDropAction returns TRUE for this signal.

action :

the ClutterDropAction that emitted the signal

actor :

the ClutterActor attached to the action

event_x :

the X coordinate (in stage space) of the drop event

event_y :

the Y coordinate (in stage space) of the drop event

user_data :

user data set when the signal handler was connected.

Returns :

TRUE if the drop is accepted, and FALSE otherwise

Since 1.8


The "drop" signal

void                user_function                      (ClutterDropAction *action,
                                                        ClutterActor      *actor,
                                                        gfloat             event_x,
                                                        gfloat             event_y,
                                                        gpointer           user_data)      : Run Last

The ::drop signal is emitted when the dragged actor is dropped on actor. This signal is only emitted if at least an handler of "can-drop" returns TRUE.

action :

the ClutterDropAction that emitted the signal

actor :

the ClutterActor attached to the action

event_x :

the X coordinate (in stage space) of the drop event

event_y :

the Y coordinate (in stage space) of the drop event

user_data :

user data set when the signal handler was connected.

Since 1.8


The "drop-cancel" signal

void                user_function                      (ClutterDropAction *action,
                                                        ClutterActor      *actor,
                                                        gfloat             event_x,
                                                        gfloat             event_y,
                                                        gpointer           user_data)      : Run Last

The ::drop-cancel signal is emitted when the drop is refused by an emission of the "can-drop" signal.

After the ::drop-cancel signal is fired the active drag is terminated.

action :

the ClutterDropAction that emitted the signal

actor :

the ClutterActor attached to the action

event_x :

the X coordinate (in stage space) of the drop event

event_y :

the Y coordinate (in stage space) of the drop event

user_data :

user data set when the signal handler was connected.

Since 1.12


The "over-in" signal

void                user_function                      (ClutterDropAction *action,
                                                        ClutterActor      *actor,
                                                        gpointer           user_data)      : Run Last

The ::over-in signal is emitted when the dragged actor crosses into actor.

action :

the ClutterDropAction that emitted the signal

actor :

the ClutterActor attached to the action

user_data :

user data set when the signal handler was connected.

Since 1.8


The "over-out" signal

void                user_function                      (ClutterDropAction *action,
                                                        ClutterActor      *actor,
                                                        gpointer           user_data)      : Run Last

The ::over-out signal is emitted when the dragged actor crosses outside actor.

action :

the ClutterDropAction that emitted the signal

actor :

the ClutterActor attached to the action

user_data :

user data set when the signal handler was connected.

Since 1.8