Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-swipe-action.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2010  Intel Corporation.
7  * Copyright (C) 2011  Robert Bosch Car Multimedia GmbH.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21  *
22  * Author:
23  *   Tomeu Vizoso <tomeu.vizoso@collabora.co.uk>
24  *
25  * Based on ClutterDragAction, written by:
26  *   Emmanuele Bassi <ebassi@linux.intel.com>
27  */
28
29 /**
30  * SECTION:clutter-swipe-action
31  * @Title: ClutterSwipeAction
32  * @Short_Description: Action for swipe gestures
33  *
34  * #ClutterSwipeAction is a sub-class of #ClutterGestureAction that implements
35  * the logic for recognizing swipe gestures.
36  *
37  * Since: 1.8
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include "clutter-swipe-action.h"
45
46 #include "clutter-debug.h"
47 #include "clutter-enum-types.h"
48 #include "clutter-marshal.h"
49 #include "clutter-private.h"
50
51 struct _ClutterSwipeActionPrivate
52 {
53   ClutterSwipeDirection h_direction;
54   ClutterSwipeDirection v_direction;
55
56   int threshold;
57 };
58
59 enum
60 {
61   SWEPT,
62
63   LAST_SIGNAL
64 };
65
66 static guint swipe_signals[LAST_SIGNAL] = { 0, };
67
68 G_DEFINE_TYPE (ClutterSwipeAction, clutter_swipe_action,
69                CLUTTER_TYPE_GESTURE_ACTION);
70
71 static gboolean
72 gesture_begin (ClutterGestureAction  *action,
73                ClutterActor          *actor)
74 {
75   ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv;
76   ClutterSettings *settings = clutter_settings_get_default ();
77
78   /* reset the state at the beginning of a new gesture */
79   priv->h_direction = 0;
80   priv->v_direction = 0;
81
82   g_object_get (settings, "dnd-drag-threshold", &priv->threshold, NULL);
83
84   return TRUE;
85 }
86
87 static gboolean
88 gesture_progress (ClutterGestureAction *action,
89                   ClutterActor         *actor)
90 {
91   ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv;
92   gfloat press_x, press_y;
93   gfloat motion_x, motion_y;
94   gfloat delta_x, delta_y;
95   ClutterSwipeDirection h_direction = 0, v_direction = 0;
96
97   clutter_gesture_action_get_press_coords (action,
98                                            0,
99                                            &press_x,
100                                            &press_y);
101
102   clutter_gesture_action_get_motion_coords (action,
103                                             0,
104                                             &motion_x,
105                                             &motion_y);
106
107   delta_x = press_x - motion_x;
108   delta_y = press_y - motion_y;
109
110   if (delta_x >= priv->threshold)
111     h_direction = CLUTTER_SWIPE_DIRECTION_RIGHT;
112   else if (delta_x < -priv->threshold)
113     h_direction = CLUTTER_SWIPE_DIRECTION_LEFT;
114
115   if (delta_y >= priv->threshold)
116     v_direction = CLUTTER_SWIPE_DIRECTION_DOWN;
117   else if (delta_y < -priv->threshold)
118     v_direction = CLUTTER_SWIPE_DIRECTION_UP;
119
120   /* cancel gesture on direction reversal */
121   if (priv->h_direction == 0)
122     priv->h_direction = h_direction;
123
124   if (priv->v_direction == 0)
125     priv->v_direction = v_direction;
126
127   if (priv->h_direction != h_direction)
128     return FALSE;
129
130   if (priv->v_direction != v_direction)
131     return FALSE;
132
133   return TRUE;
134 }
135
136 static void
137 gesture_end (ClutterGestureAction *action,
138              ClutterActor         *actor)
139 {
140   ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv;
141   gfloat press_x, press_y;
142   gfloat release_x, release_y;
143   ClutterSwipeDirection direction = 0;
144
145   clutter_gesture_action_get_press_coords (action,
146                                            0,
147                                            &press_x, &press_y);
148
149   clutter_gesture_action_get_release_coords (action,
150                                              0,
151                                              &release_x, &release_y);
152
153   if (release_x - press_x > priv->threshold)
154     direction |= CLUTTER_SWIPE_DIRECTION_RIGHT;
155   else if (press_x - release_x > priv->threshold)
156     direction |= CLUTTER_SWIPE_DIRECTION_LEFT;
157
158   if (release_y - press_y > priv->threshold)
159     direction |= CLUTTER_SWIPE_DIRECTION_DOWN;
160   else if (press_y - release_y > priv->threshold)
161     direction |= CLUTTER_SWIPE_DIRECTION_UP;
162
163   g_signal_emit (action, swipe_signals[SWEPT], 0, actor, direction);
164 }
165
166 static void
167 clutter_swipe_action_class_init (ClutterSwipeActionClass *klass)
168 {
169   ClutterGestureActionClass *gesture_class =
170       CLUTTER_GESTURE_ACTION_CLASS (klass);
171
172   g_type_class_add_private (klass, sizeof (ClutterSwipeActionPrivate));
173
174   gesture_class->gesture_begin = gesture_begin;
175   gesture_class->gesture_progress = gesture_progress;
176   gesture_class->gesture_end = gesture_end;
177
178   /**
179    * ClutterSwipeAction::swept:
180    * @action: the #ClutterSwipeAction that emitted the signal
181    * @actor: the #ClutterActor attached to the @action
182    * @direction: the main direction of the swipe gesture
183    *
184    * The ::swept signal is emitted when a swipe gesture is recognized on the
185    * attached actor.
186    *
187    * Since: 1.8
188    */
189   swipe_signals[SWEPT] =
190     g_signal_new (I_("swept"),
191                   G_TYPE_FROM_CLASS (klass),
192                   G_SIGNAL_RUN_LAST,
193                   G_STRUCT_OFFSET (ClutterSwipeActionClass, swept),
194                   NULL, NULL,
195                   _clutter_marshal_VOID__OBJECT_FLAGS,
196                   G_TYPE_NONE, 2,
197                   CLUTTER_TYPE_ACTOR,
198                   CLUTTER_TYPE_SWIPE_DIRECTION);
199 }
200
201 static void
202 clutter_swipe_action_init (ClutterSwipeAction *self)
203 {
204   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_SWIPE_ACTION,
205                                             ClutterSwipeActionPrivate);
206 }
207
208 /**
209  * clutter_swipe_action_new:
210  *
211  * Creates a new #ClutterSwipeAction instance
212  *
213  * Return value: the newly created #ClutterSwipeAction
214  *
215  * Since: 1.8
216  */
217 ClutterAction *
218 clutter_swipe_action_new (void)
219 {
220   return g_object_new (CLUTTER_TYPE_SWIPE_ACTION, NULL);
221 }