mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 16:10:41 -05:00
Add ClutterDropAction
ClutterDropAction is an Action sub-class that allows writing actors that react to dragged actors being dropped on them. https://bugzilla.gnome.org/show_bug.cgi?id=652842
This commit is contained in:
parent
a6a57d7967
commit
1238e0ddf9
@ -85,6 +85,7 @@ source_h = \
|
||||
$(srcdir)/clutter-desaturate-effect.h \
|
||||
$(srcdir)/clutter-device-manager.h \
|
||||
$(srcdir)/clutter-drag-action.h \
|
||||
$(srcdir)/clutter-drop-action.h \
|
||||
$(srcdir)/clutter-effect.h \
|
||||
$(srcdir)/clutter-event.h \
|
||||
$(srcdir)/clutter-feature.h \
|
||||
@ -169,6 +170,7 @@ source_c = \
|
||||
$(srcdir)/clutter-desaturate-effect.c \
|
||||
$(srcdir)/clutter-device-manager.c \
|
||||
$(srcdir)/clutter-drag-action.c \
|
||||
$(srcdir)/clutter-drop-action.c \
|
||||
$(srcdir)/clutter-effect.c \
|
||||
$(srcdir)/clutter-event.c \
|
||||
$(srcdir)/clutter-feature.c \
|
||||
|
358
clutter/clutter-drop-action.c
Normal file
358
clutter/clutter-drop-action.c
Normal file
@ -0,0 +1,358 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-drop-action.h"
|
||||
|
||||
#include "clutter-actor-meta-private.h"
|
||||
#include "clutter-actor-private.h"
|
||||
#include "clutter-drag-action.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
struct _ClutterDropActionPrivate
|
||||
{
|
||||
ClutterActor *actor;
|
||||
ClutterActor *stage;
|
||||
|
||||
gulong mapped_id;
|
||||
|
||||
guint is_inside : 1;
|
||||
};
|
||||
|
||||
typedef struct _DropTarget {
|
||||
ClutterActor *stage;
|
||||
|
||||
gulong capture_id;
|
||||
|
||||
GHashTable *actions;
|
||||
|
||||
ClutterDropAction *last_action;
|
||||
} DropTarget;
|
||||
|
||||
enum
|
||||
{
|
||||
CAN_DROP,
|
||||
OVER_IN,
|
||||
OVER_OUT,
|
||||
DROP,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint drop_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE (ClutterDropAction, clutter_drop_action, CLUTTER_TYPE_ACTION)
|
||||
|
||||
static void
|
||||
drop_target_free (gpointer _data)
|
||||
{
|
||||
DropTarget *data = _data;
|
||||
|
||||
g_signal_handler_disconnect (data->stage, data->capture_id);
|
||||
g_hash_table_destroy (data->actions);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_stage_capture (ClutterStage *stage,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
DropTarget *data = user_data;
|
||||
gfloat event_x, event_y;
|
||||
ClutterInputDevice *device;
|
||||
ClutterActor *actor, *drag_actor;
|
||||
ClutterDropAction *drop_action;
|
||||
gboolean was_reactive;
|
||||
|
||||
if (!(clutter_event_type (event) == CLUTTER_MOTION ||
|
||||
clutter_event_type (event) == CLUTTER_BUTTON_RELEASE))
|
||||
return FALSE;
|
||||
|
||||
if (!(clutter_event_get_state (event) & CLUTTER_BUTTON1_MASK))
|
||||
return FALSE;
|
||||
|
||||
clutter_event_get_coords (event, &event_x, &event_y);
|
||||
device = clutter_event_get_device (event);
|
||||
|
||||
drag_actor = _clutter_stage_get_drag_actor (stage, device);
|
||||
if (drag_actor == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* get the actor under the cursor, excluding the dragged actor; we
|
||||
* use reactivity because it won't cause any scene invalidation
|
||||
*/
|
||||
was_reactive = clutter_actor_get_reactive (drag_actor);
|
||||
clutter_actor_set_reactive (drag_actor, FALSE);
|
||||
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_REACTIVE,
|
||||
event_x,
|
||||
event_y);
|
||||
if (actor == NULL || actor == CLUTTER_ACTOR (stage))
|
||||
{
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
|
||||
data->last_action = NULL;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
drop_action = g_hash_table_lookup (data->actions, actor);
|
||||
|
||||
if (drop_action == NULL)
|
||||
{
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
|
||||
data->last_action = NULL;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data->last_action != drop_action)
|
||||
{
|
||||
ClutterActorMeta *meta;
|
||||
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
}
|
||||
|
||||
meta = CLUTTER_ACTOR_META (drop_action);
|
||||
|
||||
g_signal_emit (drop_action, drop_signals[OVER_IN], 0,
|
||||
clutter_actor_meta_get_actor (meta));
|
||||
}
|
||||
|
||||
data->last_action = drop_action;
|
||||
}
|
||||
|
||||
out:
|
||||
if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE)
|
||||
{
|
||||
if (data->last_action != NULL)
|
||||
{
|
||||
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
|
||||
gboolean can_drop = FALSE;
|
||||
|
||||
g_signal_emit (data->last_action, drop_signals[CAN_DROP], 0,
|
||||
clutter_actor_meta_get_actor (meta),
|
||||
event_x, event_y,
|
||||
&can_drop);
|
||||
|
||||
if (can_drop)
|
||||
{
|
||||
g_signal_emit (data->last_action, drop_signals[DROP], 0,
|
||||
clutter_actor_meta_get_actor (meta),
|
||||
event_x, event_y);
|
||||
}
|
||||
}
|
||||
|
||||
data->last_action = NULL;
|
||||
}
|
||||
|
||||
if (drag_actor != NULL)
|
||||
clutter_actor_set_reactive (drag_actor, was_reactive);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
drop_action_register (ClutterDropAction *self)
|
||||
{
|
||||
ClutterDropActionPrivate *priv = self->priv;
|
||||
DropTarget *data;
|
||||
|
||||
g_assert (priv->stage != NULL);
|
||||
|
||||
data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets");
|
||||
if (data == NULL)
|
||||
{
|
||||
data = g_new0 (DropTarget, 1);
|
||||
|
||||
data->stage = priv->stage;
|
||||
data->actions = g_hash_table_new (NULL, NULL);
|
||||
data->capture_id = g_signal_connect (priv->stage, "captured-event",
|
||||
G_CALLBACK (on_stage_capture),
|
||||
data);
|
||||
g_object_set_data_full (G_OBJECT (priv->stage), "__clutter_drop_targets",
|
||||
data,
|
||||
drop_target_free);
|
||||
}
|
||||
|
||||
g_hash_table_replace (data->actions, priv->actor, self);
|
||||
}
|
||||
|
||||
static void
|
||||
drop_action_unregister (ClutterDropAction *self)
|
||||
{
|
||||
ClutterDropActionPrivate *priv = self->priv;
|
||||
DropTarget *data;
|
||||
|
||||
data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets");
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (data->actions, priv->actor);
|
||||
if (g_hash_table_size (data->actions) == 0)
|
||||
g_object_set_data (G_OBJECT (data->stage), "__clutter_drop_targets", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_actor_mapped (ClutterActor *actor,
|
||||
GParamSpec *pspec,
|
||||
ClutterDropAction *self)
|
||||
{
|
||||
if (CLUTTER_ACTOR_IS_MAPPED (actor))
|
||||
{
|
||||
if (self->priv->stage == NULL)
|
||||
self->priv->stage = clutter_actor_get_stage (actor);
|
||||
|
||||
drop_action_register (self);
|
||||
}
|
||||
else
|
||||
drop_action_unregister (self);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_drop_action_set_actor (ClutterActorMeta *meta,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
ClutterDropActionPrivate *priv = CLUTTER_DROP_ACTION (meta)->priv;
|
||||
|
||||
if (priv->actor != NULL)
|
||||
{
|
||||
drop_action_unregister (CLUTTER_DROP_ACTION (meta));
|
||||
|
||||
if (priv->mapped_id != 0)
|
||||
g_signal_handler_disconnect (priv->actor, priv->mapped_id);
|
||||
|
||||
priv->stage = NULL;
|
||||
priv->actor = NULL;
|
||||
priv->mapped_id = 0;
|
||||
}
|
||||
|
||||
priv->actor = actor;
|
||||
|
||||
if (priv->actor != NULL)
|
||||
{
|
||||
priv->stage = clutter_actor_get_stage (actor);
|
||||
priv->mapped_id = g_signal_connect (actor, "notify::mapped",
|
||||
G_CALLBACK (on_actor_mapped),
|
||||
meta);
|
||||
|
||||
if (priv->stage != NULL)
|
||||
drop_action_register (CLUTTER_DROP_ACTION (meta));
|
||||
}
|
||||
|
||||
CLUTTER_ACTOR_META_CLASS (clutter_drop_action_parent_class)->set_actor (meta, actor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
signal_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean continue_emission;
|
||||
|
||||
continue_emission = g_value_get_boolean (handler_return);
|
||||
g_value_set_boolean (return_accu, continue_emission);
|
||||
|
||||
return continue_emission;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_drop_action_real_can_drop (ClutterDropAction *action,
|
||||
ClutterActor *actor,
|
||||
gfloat event_x,
|
||||
gfloat event_y)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_drop_action_class_init (ClutterDropActionClass *klass)
|
||||
{
|
||||
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ClutterDropActionPrivate));
|
||||
|
||||
meta_class->set_actor = clutter_drop_action_set_actor;
|
||||
|
||||
klass->can_drop = clutter_drop_action_real_can_drop;
|
||||
|
||||
drop_signals[CAN_DROP] =
|
||||
g_signal_new (I_("can-drop"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, can_drop),
|
||||
signal_accumulator, NULL,
|
||||
_clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT,
|
||||
G_TYPE_BOOLEAN, 3,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_FLOAT,
|
||||
G_TYPE_FLOAT);
|
||||
|
||||
drop_signals[OVER_IN] =
|
||||
g_signal_new (I_("over-in"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, over_in),
|
||||
NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
|
||||
drop_signals[OVER_OUT] =
|
||||
g_signal_new (I_("over-out"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, over_out),
|
||||
NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
|
||||
drop_signals[DROP] =
|
||||
g_signal_new (I_("drop"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterDropActionClass, drop),
|
||||
NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
|
||||
G_TYPE_NONE, 3,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_FLOAT,
|
||||
G_TYPE_FLOAT);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_drop_action_init (ClutterDropAction *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_DROP_ACTION,
|
||||
ClutterDropActionPrivate);
|
||||
}
|
||||
|
||||
ClutterAction *
|
||||
clutter_drop_action_new (void)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_DROP_ACTION, NULL);
|
||||
}
|
85
clutter/clutter-drop-action.h
Normal file
85
clutter/clutter-drop-action.h
Normal file
@ -0,0 +1,85 @@
|
||||
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
|
||||
#error "Only <clutter/clutter.h> can be directly included."
|
||||
#endif
|
||||
|
||||
#ifndef __CLUTTER_DROP_ACTION_H__
|
||||
#define __CLUTTER_DROP_ACTION_H__
|
||||
|
||||
#include <clutter/clutter-action.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_DROP_ACTION (clutter_drop_action_get_type ())
|
||||
#define CLUTTER_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropAction))
|
||||
#define CLUTTER_IS_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DROP_ACTION))
|
||||
#define CLUTTER_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass))
|
||||
#define CLUTTER_IS_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DROP_ACTION))
|
||||
#define CLUTTER_DROP_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass))
|
||||
|
||||
typedef struct _ClutterDropAction ClutterDropAction;
|
||||
typedef struct _ClutterDropActionPrivate ClutterDropActionPrivate;
|
||||
typedef struct _ClutterDropActionClass ClutterDropActionClass;
|
||||
|
||||
/**
|
||||
* ClutterDropAction:
|
||||
*
|
||||
* The <structname>ClutterDropAction</structname> structure contains only
|
||||
* private data and should be accessed using the provided API.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
struct _ClutterDropAction
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterAction parent_instance;
|
||||
|
||||
ClutterDropActionPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* ClutterDropActionClass:
|
||||
*
|
||||
* The <structname>ClutterDropActionClass</structname> structure contains
|
||||
* only private data.
|
||||
*
|
||||
* Since: 1.8
|
||||
*/
|
||||
struct _ClutterDropActionClass
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActionClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
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);
|
||||
|
||||
/*< private >*/
|
||||
void (*_clutter_drop_action1) (void);
|
||||
void (*_clutter_drop_action2) (void);
|
||||
void (*_clutter_drop_action3) (void);
|
||||
void (*_clutter_drop_action4) (void);
|
||||
void (*_clutter_drop_action5) (void);
|
||||
void (*_clutter_drop_action6) (void);
|
||||
void (*_clutter_drop_action7) (void);
|
||||
void (*_clutter_drop_action8) (void);
|
||||
};
|
||||
|
||||
GType clutter_drop_action_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterAction * clutter_drop_action_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_DROP_ACTION_H__ */
|
@ -2,6 +2,7 @@ BOOLEAN:BOXED
|
||||
BOOLEAN:OBJECT,ENUM
|
||||
BOOLEAN:STRING,UINT,FLAGS
|
||||
BOOLEAN:OBJECT
|
||||
BOOLEAN:OBJECT,FLOAT,FLOAT
|
||||
BOXED:UINT,UINT
|
||||
DOUBLE:VOID
|
||||
UINT:VOID
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "clutter-desaturate-effect.h"
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-drag-action.h"
|
||||
#include "clutter-drop-action.h"
|
||||
#include "clutter-effect.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-feature.h"
|
||||
|
@ -57,7 +57,8 @@ UNIT_TESTS = \
|
||||
test-table-layout.c \
|
||||
test-path-constraint.c \
|
||||
test-snap-constraint.c \
|
||||
test-state-script.c
|
||||
test-state-script.c \
|
||||
test-drop.c
|
||||
|
||||
if X11_TESTS
|
||||
UNIT_TESTS += test-pixmap.c test-devices.c
|
||||
|
245
tests/interactive/test-drop.c
Normal file
245
tests/interactive/test-drop.c
Normal file
@ -0,0 +1,245 @@
|
||||
#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_animate (actor, CLUTTER_LINEAR, 150, "opacity", 255, NULL);
|
||||
|
||||
if (!drop_successful)
|
||||
{
|
||||
gfloat x_pos, y_pos;
|
||||
|
||||
clutter_actor_animate (clutter_actor_get_parent (actor),
|
||||
CLUTTER_LINEAR, 150,
|
||||
"opacity", 255,
|
||||
NULL);
|
||||
|
||||
clutter_actor_get_transformed_position (actor, &x_pos, &y_pos);
|
||||
clutter_actor_animate (handle, CLUTTER_EASE_OUT_BOUNCE, 250,
|
||||
"x", x_pos,
|
||||
"y", y_pos,
|
||||
"opacity", 0,
|
||||
"signal-swapped::completed",
|
||||
G_CALLBACK (clutter_actor_destroy),
|
||||
handle,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_actor_animate (handle, CLUTTER_LINEAR, 250,
|
||||
"opacity", 0,
|
||||
"signal-swapped::completed",
|
||||
G_CALLBACK (clutter_actor_destroy),
|
||||
handle,
|
||||
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_rectangle_new_with_color (CLUTTER_COLOR_DarkSkyBlue);
|
||||
clutter_actor_set_size (handle, 128, 128);
|
||||
clutter_actor_set_position (handle, event_x - x_pos, event_y - y_pos);
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (stage), handle);
|
||||
|
||||
clutter_drag_action_set_drag_handle (action, handle);
|
||||
|
||||
clutter_actor_animate (actor, CLUTTER_LINEAR, 150, "opacity", 128, NULL);\
|
||||
|
||||
drop_successful = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_drag_object (ClutterActor *target)
|
||||
{
|
||||
ClutterActor *parent;
|
||||
|
||||
if (drag == NULL)
|
||||
{
|
||||
ClutterAction *action;
|
||||
|
||||
drag = clutter_rectangle_new_with_color (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_animate (target, CLUTTER_LINEAR, 150,
|
||||
"opacity", 255,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_ref (drag);
|
||||
if (parent != NULL && parent != stage)
|
||||
{
|
||||
clutter_container_remove_actor (CLUTTER_CONTAINER (parent), drag);
|
||||
clutter_actor_animate (parent, CLUTTER_LINEAR, 150,
|
||||
"opacity", 64,
|
||||
NULL);
|
||||
}
|
||||
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (target), drag);
|
||||
clutter_actor_animate (target, CLUTTER_LINEAR, 150,
|
||||
"opacity", 255,
|
||||
NULL);
|
||||
|
||||
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_animate (target, CLUTTER_LINEAR, 250,
|
||||
"opacity", final_opacity,
|
||||
NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_drop_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_box_new (clutter_fixed_layout_new ());
|
||||
clutter_box_set_color (CLUTTER_BOX (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_rectangle_new_with_color (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_box_new (clutter_fixed_layout_new ());
|
||||
clutter_box_set_color (CLUTTER_BOX (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_container_add (CLUTTER_CONTAINER (stage), target1, dummy, target2, NULL);
|
||||
|
||||
add_drag_object (target1);
|
||||
|
||||
clutter_actor_show (stage);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user