[clutter] gesture-action: Let subclasses override the GestureTriggerEdge handling



commit abcf1d589f29ba7914d5648bb9814ad26c13cd83
Author: Emanuele Aina <emanuele aina collabora com>
Date:   Mon Oct 15 23:37:38 2012 +0200

    gesture-action: Let subclasses override the GestureTriggerEdge handling
    
    Let gesture subclasses override how the drag threshold should
    be handled:
    
    â CLUTTER_GESTURE_TRIGGER_NONE tells GestureAction that the gesture
      must begin immediately and there's no drag limit that will cause
      its cancellation;
    â CLUTTER_GESTURE_TRIGGER_AFTER is the default GestureAction behaviour,
      where it needs to wait until the drag threshold has been exceeded
      before considering the gesture valid;
    â CLUTTER_GESTURE_TRIGGER_BEFORE will make GestureAction cancel
      the gesture once the drag exceed the configured threshold.
    
    For example, ZoomAction and RotateAction could set
    CLUTTER_GESTURE_TRIGGER_NONE since the use of two fingers makes the
    begin of the action more self-evident, while an hypothetical Tap
    gesture may use CLUTTER_GESTURE_TRIGGER_BEFORE to cancel the tap if
    the pointer moves too much.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=685028

 clutter/Makefile.am                      |    1 +
 clutter/clutter-gesture-action-private.h |   59 +++++++++++++
 clutter/clutter-gesture-action.c         |  141 ++++++++++++++++++++----------
 3 files changed, 153 insertions(+), 48 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 100c1f5..70a4792 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -226,6 +226,7 @@ source_h_priv = \
 	$(srcdir)/clutter-event-translator.h		\
 	$(srcdir)/clutter-event-private.h		\
 	$(srcdir)/clutter-flatten-effect.h		\
+	$(srcdir)/clutter-gesture-action-private.h	\
 	$(srcdir)/clutter-id-pool.h 			\
 	$(srcdir)/clutter-master-clock.h		\
 	$(srcdir)/clutter-model-private.h		\
diff --git a/clutter/clutter-gesture-action-private.h b/clutter/clutter-gesture-action-private.h
new file mode 100644
index 0000000..d3eb865
--- /dev/null
+++ b/clutter/clutter-gesture-action-private.h
@@ -0,0 +1,59 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2012  Collabora Ltd..
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLUTTER_GESTURE_ACTION_PRIVATE_H__
+#define __CLUTTER_GESTURE_ACTION_PRIVATE_H__
+
+#include <clutter/clutter-gesture-action.h>
+
+G_BEGIN_DECLS
+
+/*< private >
+ * ClutterGestureTriggerEdge:
+ * @CLUTTER_GESTURE_TRIGGER_NONE: Tell #ClutterGestureAction that
+ * the gesture must begin immediately and there's no drag limit that
+ * will cause its cancellation;
+ * @CLUTTER_GESTURE_TRIGGER_AFTER: Tell #ClutterGestureAction that
+ * it needs to wait until the drag threshold has been exceeded before
+ * considering that the gesture has begun;
+ * @CLUTTER_GESTURE_TRIGGER_BEFORE: Tell #ClutterGestureAction that
+ * the gesture must begin immegiately and that it must be cancelled
+ * once the drag exceed the configured threshold.
+ *
+ * Enum passed to the _clutter_gesture_action_set_threshold_trigger_edge()
+ * function.
+ *
+ * Since: 1.14
+ */
+typedef enum
+{
+  CLUTTER_GESTURE_TRIGGER_EDGE_NONE  = 0,
+  CLUTTER_GESTURE_TRIGGER_EDGE_AFTER,
+  CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE
+} ClutterGestureTriggerEdge;
+
+
+void    _clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction     *action,
+                                                            ClutterGestureTriggerEdge edge);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_GESTURE_ACTION_PRIVATE_H__ */
diff --git a/clutter/clutter-gesture-action.c b/clutter/clutter-gesture-action.c
index 4c9460b..310bf9a 100644
--- a/clutter/clutter-gesture-action.c
+++ b/clutter/clutter-gesture-action.c
@@ -87,7 +87,7 @@
 #include "config.h"
 #endif
 
-#include "clutter-gesture-action.h"
+#include "clutter-gesture-action-private.h"
 
 #include "clutter-debug.h"
 #include "clutter-enum-types.h"
@@ -122,6 +122,8 @@ struct _ClutterGestureActionPrivate
   guint actor_capture_id;
   gulong stage_capture_id;
 
+  ClutterGestureTriggerEdge edge;
+
   guint in_gesture : 1;
 };
 
@@ -209,6 +211,15 @@ gesture_unregister_point (ClutterGestureAction *action, gint position)
   g_array_remove_index (priv->points, position);
 }
 
+static gint
+gesture_get_threshold (ClutterGestureAction *action)
+{
+  gint threshold;
+  ClutterSettings *settings = clutter_settings_get_default ();
+  g_object_get (settings, "dnd-drag-threshold", &threshold, NULL);
+  return threshold;
+}
+
 static void
 cancel_gesture (ClutterGestureAction *action)
 {
@@ -228,13 +239,45 @@ cancel_gesture (ClutterGestureAction *action)
 }
 
 static gboolean
+begin_gesture (ClutterGestureAction *action,
+               ClutterActor         *actor)
+{
+  ClutterGestureActionPrivate *priv = action->priv;
+  gboolean return_value;
+
+  priv->in_gesture = TRUE;
+
+  if (!CLUTTER_GESTURE_ACTION_GET_CLASS (action)->gesture_prepare (action, actor))
+    {
+      cancel_gesture (action);
+      return FALSE;
+    }
+
+  /* clutter_gesture_action_cancel() may have been called during
+   * gesture_prepare(), check that the gesture is still active. */
+  if (!priv->in_gesture)
+    return FALSE;
+
+  g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor,
+                 &return_value);
+
+  if (!return_value)
+    {
+      cancel_gesture (action);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
 stage_captured_event_cb (ClutterActor       *stage,
                          ClutterEvent       *event,
                          ClutterGestureAction *action)
 {
   ClutterGestureActionPrivate *priv = action->priv;
   ClutterActor *actor;
-  gint position;
+  gint position, drag_threshold;
   gboolean return_value;
   GesturePoint *point;
   gfloat motion_x, motion_y;
@@ -272,40 +315,18 @@ stage_captured_event_cb (ClutterActor       *stage,
       if (priv->points->len < priv->requested_nb_points)
         return CLUTTER_EVENT_PROPAGATE;
 
+      drag_threshold = gesture_get_threshold (action);
+
       if (!priv->in_gesture)
         {
-          gint drag_threshold;
-          ClutterSettings *settings = clutter_settings_get_default ();
-
-          g_object_get (settings,
-                        "dnd-drag-threshold", &drag_threshold,
-                        NULL);
-
-          if ((ABS (point->press_y - motion_y) >= drag_threshold) ||
-              (ABS (point->press_x - motion_x) >= drag_threshold))
-            {
-              priv->in_gesture = TRUE;
-
-              if (!CLUTTER_GESTURE_ACTION_GET_CLASS (action)->gesture_prepare (action, actor))
-                {
-                  cancel_gesture (action);
-                  return CLUTTER_EVENT_PROPAGATE;
-                }
-
-              /* clutter_gesture_action_cancel() may have been called during
-               * gesture_prepare(), check that the gesture is still active. */
-              if (!priv->in_gesture)
-                return CLUTTER_EVENT_PROPAGATE;
+          /* Wait until the drag threshold has been exceeded
+           * before starting _TRIGGER_EDGE_AFTER gestures. */
+          if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER &&
+              (fabsf (point->press_y - motion_y) < drag_threshold) &&
+              (fabsf (point->press_x - motion_x) < drag_threshold))
+            return CLUTTER_EVENT_PROPAGATE;
 
-              g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor,
-                             &return_value);
-              if (!return_value)
-                {
-                  cancel_gesture (action);
-                  return CLUTTER_EVENT_PROPAGATE;
-                }
-            }
-          else
+          if (!begin_gesture(action, actor))
             return CLUTTER_EVENT_PROPAGATE;
         }
 
@@ -325,6 +346,16 @@ stage_captured_event_cb (ClutterActor       *stage,
           cancel_gesture (action);
           return CLUTTER_EVENT_PROPAGATE;
         }
+
+      /* Check if a _TRIGGER_EDGE_BEFORE gesture needs to be cancelled because
+       * the drag threshold has been exceeded. */
+      if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE &&
+          ((fabsf (point->press_y - motion_y) > drag_threshold) ||
+           (fabsf (point->press_x - motion_x) > drag_threshold)))
+        {
+          cancel_gesture (action);
+          return CLUTTER_EVENT_PROPAGATE;
+        }
       break;
 
     case CLUTTER_BUTTON_RELEASE:
@@ -400,6 +431,11 @@ actor_captured_event_cb (ClutterActor *actor,
                               G_CALLBACK (stage_captured_event_cb),
                               action);
 
+  /* Start the gesture immediately if the gesture has no
+   * _TRIGGER_EDGE_AFTER drag threshold. */
+  if (priv->edge != CLUTTER_GESTURE_TRIGGER_EDGE_AFTER)
+    begin_gesture (action, actor);
+
   return CLUTTER_EVENT_PROPAGATE;
 }
 
@@ -448,6 +484,26 @@ default_event_handler (ClutterGestureAction *action,
   return TRUE;
 }
 
+
+/*< private >
+ * _clutter_gesture_action_set_threshold_trigger_edge:
+ * @action: a #ClutterGestureAction
+ * @edge: the %ClutterGestureTriggerEdge
+ *
+ * Sets the edge trigger for the gesture drag threshold, if any.
+ *
+ * This function can be called by #ClutterGestureAction subclasses that needs
+ * to change the %CLUTTER_GESTURE_TRIGGER_EDGE_AFTER default.
+ *
+ * Since: 1.14
+ */
+void
+_clutter_gesture_action_set_threshold_trigger_edge  (ClutterGestureAction     *action,
+                                                     ClutterGestureTriggerEdge edge)
+{
+  action->priv->edge = edge;
+}
+
 static void
 clutter_gesture_action_class_init (ClutterGestureActionClass *klass)
 {
@@ -562,6 +618,7 @@ clutter_gesture_action_init (ClutterGestureAction *self)
 
   self->priv->points = g_array_sized_new (FALSE, TRUE, sizeof (GesturePoint), 3);
   self->priv->requested_nb_points = 1;
+  self->priv->edge = CLUTTER_GESTURE_TRIGGER_EDGE_AFTER;
 }
 
 /**
@@ -812,18 +869,15 @@ clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action,
       if (priv->points->len < priv->requested_nb_points)
         cancel_gesture (action);
     }
-  else
+  else if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER)
     {
       if (priv->points->len >= priv->requested_nb_points)
         {
           ClutterActor *actor =
             clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
-          ClutterSettings *settings = clutter_settings_get_default ();
           gint i, drag_threshold;
 
-          g_object_get (settings,
-                        "dnd-drag-threshold", &drag_threshold,
-                        NULL);
+          drag_threshold = gesture_get_threshold (action);
 
           for (i = 0; i < priv->points->len; i++)
             {
@@ -832,16 +886,7 @@ clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action,
               if ((ABS (point->press_y - point->last_motion_y) >= drag_threshold) ||
                   (ABS (point->press_x - point->last_motion_x) >= drag_threshold))
                 {
-                  gboolean return_value;
-
-                  priv->in_gesture = TRUE;
-
-                  g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor,
-                                 &return_value);
-
-                  if (!return_value)
-                    cancel_gesture (action);
-
+                  begin_gesture (action, actor);
                   break;
                 }
             }



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