[clutter] Add ClutterDropAction



commit 1238e0ddf92c7fc7a3ec49dcbeeb934a696b9800
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Fri Jun 17 16:54:31 2011 +0100

    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

 clutter/Makefile.am           |    2 +
 clutter/clutter-drop-action.c |  358 +++++++++++++++++++++++++++++++++++++++++
 clutter/clutter-drop-action.h |   85 ++++++++++
 clutter/clutter-marshal.list  |    1 +
 clutter/clutter.h             |    1 +
 tests/interactive/Makefile.am |    3 +-
 tests/interactive/test-drop.c |  245 ++++++++++++++++++++++++++++
 7 files changed, 694 insertions(+), 1 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 071b786..2f158a8 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -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 		\
diff --git a/clutter/clutter-drop-action.c b/clutter/clutter-drop-action.c
new file mode 100644
index 0000000..1052dc7
--- /dev/null
+++ b/clutter/clutter-drop-action.c
@@ -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);
+}
diff --git a/clutter/clutter-drop-action.h b/clutter/clutter-drop-action.h
new file mode 100644
index 0000000..290c90e
--- /dev/null
+++ b/clutter/clutter-drop-action.h
@@ -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__ */
diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list
index 9d433c6..d189a82 100644
--- a/clutter/clutter-marshal.list
+++ b/clutter/clutter-marshal.list
@@ -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
diff --git a/clutter/clutter.h b/clutter/clutter.h
index d64a9b7..8753466 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -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"
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index 7ed17e5..7935397 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -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
diff --git a/tests/interactive/test-drop.c b/tests/interactive/test-drop.c
new file mode 100644
index 0000000..2b511d4
--- /dev/null
+++ b/tests/interactive/test-drop.c
@@ -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;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]