ClutterDropAction

ClutterDropAction — An action for drop targets

Functions

Signals

gboolean can-drop Run Last
void drop Run Last
void drop-cancel Run Last
void over-in Run Last
void over-out Run Last

Types and Values

Object Hierarchy

    GObject
    ╰── GInitiallyUnowned
        ╰── ClutterActorMeta
            ╰── ClutterAction
                ╰── ClutterDropAction

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:

  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

#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);

    }
  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

Functions

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

Types and Values

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.

Members

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

Signal Details

The “can-drop” signal

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

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.

Parameters

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

Flags: Run Last

Since 1.8


The “drop” signal

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

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.

Parameters

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.

 

Flags: Run Last

Since 1.8


The “drop-cancel” signal

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

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.

Parameters

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.

 

Flags: Run Last

Since 1.12


The “over-in” signal

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

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

Parameters

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.

 

Flags: Run Last

Since 1.8


The “over-out” signal

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

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

Parameters

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.

 

Flags: Run Last

Since 1.8