2 # include "elementary_config.h"
5 #include <Elementary.h>
8 EAPI Eo_Op ELM_OBJ_GESTURE_LAYER_BASE_ID = EO_NOOP;
10 #define MY_CLASS ELM_OBJ_GESTURE_LAYER_CLASS
12 #define MY_CLASS_NAME "elm_gesture_layer"
15 #define ELM_MOUSE_DEVICE 0
16 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
17 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
18 #define ELM_GESTURE_MOMENTUM_DELAY 25
19 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
20 #define ELM_GESTURE_MULTI_TIMEOUT 50
21 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
23 /* Some Trigo values */
24 #define RAD_90DEG M_PI_2
25 #define RAD_180DEG M_PI
26 #define RAD_270DEG (M_PI_2 * 3)
27 #define RAD_360DEG (M_PI * 2)
29 #define RAD2DEG(x) ((x) * 57.295779513)
30 #define DEG2RAD(x) ((x) / 57.295779513)
33 _glayer_buf_dup(void *buf, size_t size)
43 #define COPY_EVENT_INFO(EV) _glayer_buf_dup(EV, sizeof(*EV))
45 #define SET_TEST_BIT(P) \
47 P->test = P->fn[ELM_GESTURE_STATE_START].cb || \
48 P->fn[ELM_GESTURE_STATE_MOVE].cb || \
49 P->fn[ELM_GESTURE_STATE_END].cb || \
50 P->fn[ELM_GESTURE_STATE_ABORT].cb; \
53 #define IS_TESTED_GESTURE(gesture) \
54 ((gesture) ? (gesture)->test : EINA_FALSE)
56 #define IS_TESTED(T) \
57 ((sd->gesture[T]) ? sd->gesture[T]->test : EINA_FALSE)
59 #define ELM_GESTURE_LAYER_DATA_GET(o, sd) \
60 Elm_Gesture_Layer_Smart_Data * sd = eo_data_scope_get(o, MY_CLASS)
62 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN(o, ptr) \
63 ELM_GESTURE_LAYER_DATA_GET(o, ptr); \
66 CRITICAL("No widget data for object %p (%s)", \
67 o, evas_object_type_get(o)); \
71 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
72 ELM_GESTURE_LAYER_DATA_GET(o, ptr); \
75 CRITICAL("No widget data for object %p (%s)", \
76 o, evas_object_type_get(o)); \
80 #define ELM_GESTURE_LAYER_CHECK(obj) \
81 if (!obj || !eo_isa(obj, MY_CLASS)) \
87 * @struct _Pointer_Event
88 * Struct holds pointer-event info
89 * This is a generic pointer event structure
91 * @ingroup Elm_Gesture_Layer
96 unsigned int timestamp;
98 Evas_Callback_Type event_type;
104 * @typedef Pointer_Event
105 * Type for generic pointer event structure
107 * @ingroup Elm_Gesture_Layer
109 typedef struct _Pointer_Event Pointer_Event;
115 * Struct holds callback information.
117 * @ingroup Elm_Gesture_Layer
121 void *user_data; /**< Holds user data to CB (like sd) */
122 Elm_Gesture_Event_Cb cb;
129 * type for callback information
131 * @ingroup Elm_Gesture_Layer
133 typedef struct _Func_Data Func_Data;
138 * @struct _Gesture_Info
139 * Struct holds gesture info
141 * @ingroup Elm_Gesture_Layer
146 void *data; /**< Holds gesture intemidiate processing data */
147 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
148 Elm_Gesture_Type g_type; /**< gesture type */
149 Elm_Gesture_State state; /**< gesture state */
150 void *info; /**< Data for the state callback */
151 Eina_Bool test; /**< if true this gesture should be tested on input */
157 * @typedef Gesture_Info
158 * Type for _Gesture_Info
160 * @ingroup Elm_Gesture_Layer
162 typedef struct _Gesture_Info Gesture_Info;
166 void (*test)(Evas_Object *obj, Pointer_Event *pe,
167 void *event_info, Evas_Callback_Type event_type,
168 Elm_Gesture_Type g_type);
169 void (*reset)(Gesture_Info *gesture);
170 void (*cont_reset)(Gesture_Info *gesture); /* Can be NULL. */
173 /* functions referred by _glayer_tests_array */
174 static void _tap_gesture_test(Evas_Object *obj,
177 Evas_Callback_Type event_type,
178 Elm_Gesture_Type g_type);
179 static void _tap_gestures_test_reset(Gesture_Info *gesture);
180 static void _n_long_tap_test(Evas_Object *obj,
183 Evas_Callback_Type event_type,
184 Elm_Gesture_Type g_type);
185 static void _n_long_tap_test_reset(Gesture_Info *gesture);
186 static void _momentum_test(Evas_Object *obj,
189 Evas_Callback_Type event_type,
190 Elm_Gesture_Type g_type);
191 static void _momentum_test_reset(Gesture_Info *gesture);
192 static void _n_line_test(Evas_Object *obj,
195 Evas_Callback_Type event_type,
196 Elm_Gesture_Type g_type);
197 static void _line_test_reset(Gesture_Info *gesture);
198 static void _zoom_test(Evas_Object *obj,
201 Evas_Callback_Type event_type,
202 Elm_Gesture_Type g_type);
203 static void _zoom_test_reset(Gesture_Info *gesture);
204 static void _rotate_test(Evas_Object *obj,
207 Evas_Callback_Type event_type,
208 Elm_Gesture_Type g_type);
209 static void _rotate_test_reset(Gesture_Info *gesture);
211 static void _event_process(void *data,
214 Evas_Callback_Type event_type);
216 static void _callbacks_unregister(Evas_Object *obj);
218 /* Should be the same order as _Elm_Gesture_Type */
219 static Tests_Array_Funcs _glayer_tests_array[] = {
220 { NULL, NULL, NULL }, /** Because someone made an awful mistake. */
221 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
222 /* ELM_GESTURE_N_TAPS */
223 { _n_long_tap_test, _n_long_tap_test_reset, NULL },
224 /* ELM_GESTURE_N_LONG_TAPS */
225 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
226 /* ELM_GESTURE_N_DOUBLE_TAPS */
227 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
228 /* ELM_GESTURE_N_TRIPLE_TAPS */
229 { _momentum_test, _momentum_test_reset, _momentum_test_reset },
230 /* ELM_GESTURE_MOMENTUM */
231 { _n_line_test, _line_test_reset, _line_test_reset },
232 /* ELM_GESTURE_N_LINES */
233 { _n_line_test, _line_test_reset, _line_test_reset },
234 /* ELM_GESTURE_N_FLICKS */
235 { _zoom_test, _zoom_test_reset, _zoom_test_reset },
236 /* ELM_GESTURE_ZOOM */
237 { _rotate_test, _rotate_test_reset, _rotate_test_reset },
238 /* ELM_GESTURE_ROTATE */
245 * @struct _Event_History
246 * Struct holds event history.
247 * These events are repeated if no gesture found.
249 * @ingroup Elm_Gesture_Layer
251 struct _Event_History
255 Evas_Callback_Type event_type;
261 * @typedef Event_History
262 * Type for _Event_History
264 * @ingroup Elm_Gesture_Layer
266 typedef struct _Event_History Event_History;
268 /* All *Type structs hold result for the user in 'info' field
269 * The rest is gesture processing intermediate data.
270 * NOTE: info field must be FIRST in the struct.
271 * This is used when reporting ABORT in _event_history_clear() */
274 Elm_Gesture_Taps_Info info;
277 unsigned int n_taps_needed;
281 typedef struct _Taps_Type Taps_Type;
283 struct _Long_Tap_Type
285 Elm_Gesture_Taps_Info info;
288 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
291 typedef struct _Long_Tap_Type Long_Tap_Type;
293 struct _Momentum_Type /* Fields used by _line_test() */
295 Elm_Gesture_Momentum_Info info;
296 Evas_Coord_Point line_st;
297 Evas_Coord_Point line_end;
298 unsigned int t_st_x; /* Time start on X */
299 unsigned int t_st_y; /* Time start on Y */
300 unsigned int t_end; /* Time end */
301 unsigned int t_up; /* Recent up event time */
304 typedef struct _Momentum_Type Momentum_Type;
308 Evas_Coord_Point line_st;
309 Evas_Coord_Point line_end;
310 Evas_Coord line_length;
311 unsigned int t_st; /* Time start */
312 unsigned int t_end; /* Time end */
314 double line_angle; /* Current angle of line */
316 typedef struct _Line_Data Line_Data;
318 struct _Line_Type /* Fields used by _line_test() */
320 Elm_Gesture_Line_Info info;
321 Eina_List *list; /* List of Line_Data */
323 typedef struct _Line_Type Line_Type;
325 struct _Zoom_Type /* Fields used by _zoom_test() */
327 Elm_Gesture_Zoom_Info info;
328 Pointer_Event zoom_st;
329 Pointer_Event zoom_mv;
330 Pointer_Event zoom_st1;
331 Pointer_Event zoom_mv1;
332 Evas_Event_Mouse_Wheel *zoom_wheel;
333 Evas_Coord zoom_base; /* Holds gap between fingers on
335 Evas_Coord zoom_distance_tolerance;
336 unsigned int m_st_tm; /* momentum start time */
337 unsigned int m_prev_tm; /* momentum prev time */
338 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
339 double m_base; /* zoom value when momentum starts */
342 typedef struct _Zoom_Type Zoom_Type;
344 struct _Rotate_Type /* Fields used by _rotation_test() */
346 Elm_Gesture_Rotate_Info info;
347 Pointer_Event rotate_st;
348 Pointer_Event rotate_mv;
349 Pointer_Event rotate_st1;
350 Pointer_Event rotate_mv1;
351 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
352 double prev_momentum; /* Snapshot of momentum 0.01
354 double accum_momentum;
355 double rotate_angular_tolerance;
358 typedef struct _Rotate_Type Rotate_Type;
360 typedef struct _Elm_Gesture_Layer_Smart_Data Elm_Gesture_Layer_Smart_Data;
361 struct _Elm_Gesture_Layer_Smart_Data
363 Evas_Object *target; /* Target Widget */
364 Event_History *event_history_list;
367 Evas_Coord zoom_distance_tolerance;
368 Evas_Coord line_distance_tolerance;
369 double line_angular_tolerance;
370 double zoom_wheel_factor; /* mouse wheel zoom steps */
371 double zoom_finger_factor; /* used for zoom factor */
372 double rotate_angular_tolerance;
373 unsigned int flick_time_limit_ms;
374 double long_tap_start_timeout;
375 Eina_Bool glayer_continues_enable;
376 double double_tap_timeout;
381 Gesture_Info *gesture[ELM_GESTURE_LAST];
382 Eina_List *pending; /* List of devices need to refeed
384 Eina_List *touched; /* Information of touched devices */
387 Ecore_Timer *gest_taps_timeout; /* When this expires, dbl
388 * click/taps ABORTed */
390 Eina_Bool repeat_events : 1;
393 /* START - Functions to manage touched-device list */
396 * This function is used to find if device is touched
398 * @ingroup Elm_Gesture_Layer
401 _device_compare(const void *data1,
404 /* Compare the two device numbers */
405 return ((Pointer_Event *)data1)->device - ((Pointer_Event *)data2)->device;
411 * Remove Pointer Event from touched device list
412 * @param list Pointer to touched device list.
413 * @param Pointer_Event Pointer to PE.
415 * @ingroup Elm_Gesture_Layer
418 _touched_device_remove(Eina_List *list,
421 Eina_List *lst = NULL;
422 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
425 lst = eina_list_remove(list, p);
436 * Recoed Pointer Event in touched device list
437 * Note: This fuction allocates memory for PE event
438 * This memory is released in _touched_device_remove()
439 * @param list Pointer to touched device list.
440 * @param Pointer_Event Pointer to PE.
442 * @ingroup Elm_Gesture_Layer
445 _touched_device_add(Eina_List *list,
448 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
450 if (p) /* We like to track device touch-position, overwrite info */
452 memcpy(p, pe, sizeof(Pointer_Event));
456 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
457 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN)) /* Add touched
461 p = malloc(sizeof(Pointer_Event));
462 /* Freed in _touched_device_remove() */
463 memcpy(p, pe, sizeof(Pointer_Event));
464 return eina_list_append(list, p);
470 /* END - Functions to manage touched-device list */
476 * @param event_info pointer to event.
478 * @ingroup Elm_Gesture_Layer
480 static Evas_Event_Flags
481 _event_flag_get(void *event_info,
482 Evas_Callback_Type event_type)
486 case EVAS_CALLBACK_MOUSE_IN:
487 return ((Evas_Event_Mouse_In *)event_info)->event_flags;
489 case EVAS_CALLBACK_MOUSE_OUT:
490 return ((Evas_Event_Mouse_Out *)event_info)->event_flags;
492 case EVAS_CALLBACK_MOUSE_DOWN:
493 return ((Evas_Event_Mouse_Down *)event_info)->event_flags;
495 case EVAS_CALLBACK_MOUSE_MOVE:
496 return ((Evas_Event_Mouse_Move *)event_info)->event_flags;
498 case EVAS_CALLBACK_MOUSE_UP:
499 return ((Evas_Event_Mouse_Up *)event_info)->event_flags;
501 case EVAS_CALLBACK_MOUSE_WHEEL:
502 return ((Evas_Event_Mouse_Wheel *)event_info)->event_flags;
504 case EVAS_CALLBACK_MULTI_DOWN:
505 return ((Evas_Event_Multi_Down *)event_info)->event_flags;
507 case EVAS_CALLBACK_MULTI_MOVE:
508 return ((Evas_Event_Multi_Move *)event_info)->event_flags;
510 case EVAS_CALLBACK_MULTI_UP:
511 return ((Evas_Event_Multi_Up *)event_info)->event_flags;
513 case EVAS_CALLBACK_KEY_DOWN:
514 return ((Evas_Event_Key_Down *)event_info)->event_flags;
516 case EVAS_CALLBACK_KEY_UP:
517 return ((Evas_Event_Key_Up *)event_info)->event_flags;
520 return EVAS_EVENT_FLAG_NONE;
527 * Sets event flag to value returned from user callback
528 * @param sd Widget Data
529 * @param event_info pointer to event.
530 * @param event_type what type was ev (mouse down, etc...)
531 * @param ev_flags event flags
533 * @ingroup Elm_Gesture_Layer
536 _event_consume(Elm_Gesture_Layer_Smart_Data *sd,
538 Evas_Callback_Type event_type,
539 Evas_Event_Flags ev_flags)
541 /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
542 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
543 /* should not refeed this event. */
545 return; /* This happens when restarting gestures */
547 if (!sd->repeat_events) ev_flags |= EVAS_EVENT_FLAG_ON_HOLD;
553 case EVAS_CALLBACK_MOUSE_DOWN:
554 ((Evas_Event_Mouse_Down *)event_info)->event_flags |= ev_flags;
557 case EVAS_CALLBACK_MOUSE_MOVE:
558 ((Evas_Event_Mouse_Move *)event_info)->event_flags |= ev_flags;
561 case EVAS_CALLBACK_MOUSE_UP:
562 ((Evas_Event_Mouse_Up *)event_info)->event_flags |= ev_flags;
565 case EVAS_CALLBACK_MOUSE_WHEEL:
566 ((Evas_Event_Mouse_Wheel *)event_info)->event_flags |= ev_flags;
569 case EVAS_CALLBACK_MULTI_DOWN:
570 ((Evas_Event_Multi_Down *)event_info)->event_flags |= ev_flags;
573 case EVAS_CALLBACK_MULTI_MOVE:
574 ((Evas_Event_Multi_Move *)event_info)->event_flags |= ev_flags;
577 case EVAS_CALLBACK_MULTI_UP:
578 ((Evas_Event_Multi_Up *)event_info)->event_flags |= ev_flags;
581 case EVAS_CALLBACK_KEY_DOWN:
582 ((Evas_Event_Key_Down *)event_info)->event_flags |= ev_flags;
585 case EVAS_CALLBACK_KEY_UP:
586 ((Evas_Event_Key_Up *)event_info)->event_flags |= ev_flags;
598 * Report current state of a gesture by calling user callback.
599 * @param gesture what gesture state we report.
600 * @param info inforamtion for user callback
602 * @ingroup Elm_Gesture_Layer
604 static Evas_Event_Flags
605 _state_report(Gesture_Info *gesture,
608 /* We report current state (START, MOVE, END, ABORT), once */
609 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
610 (gesture->fn[gesture->state].cb)) /* Fill state-info struct and
614 return gesture->fn[gesture->state].cb(
615 gesture->fn[gesture->state].user_data, info);
618 return EVAS_EVENT_FLAG_NONE;
624 * Update state for a given gesture.
625 * We may update gesture state to:
626 * - @c UNDEFINED - current input did not start gesure yet.
627 * - @c START - gesture started according to input.
628 * - @c MOVE - gusture in progress.
629 * - @c END - gesture completed according to input.
630 * - @c ABORT - input does not matches gesure.
631 * note that we may move from UNDEFINED to ABORT
632 * because we may detect that gesture will not START
633 * with a given input.
635 * @param g given gesture to change state.
636 * @param s gesure new state.
637 * @param info buffer to be sent to user callback on report_state.
638 * @param force makes report_state to report the new-state even
639 * if its same as current state. Works for MOVE - gesture in progress.
641 * @ingroup Elm_Gesture_Layer
643 static Evas_Event_Flags
644 _state_set(Gesture_Info *g,
649 Elm_Gesture_State old_state;
651 if ((g->state == s) && (!force))
652 return EVAS_EVENT_FLAG_NONE;
654 old_state = g->state;
657 g->info = info; /* Information for user callback */
658 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
659 (g->state == ELM_GESTURE_STATE_END))
660 g->test = EINA_FALSE;
662 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
663 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
664 (s == ELM_GESTURE_STATE_ABORT))))
665 return _state_report(g, g->info);
667 return EVAS_EVENT_FLAG_NONE;
673 * This resets all gesture states and sets test-bit.
674 * this is used for restarting gestures to listen to input.
675 * happens after we complete a gesture or no gesture was detected.
676 * @param sd Widget data of the gesture-layer object.
678 * @ingroup Elm_Gesture_Layer
681 _states_reset(Elm_Gesture_Layer_Smart_Data *sd)
686 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
691 _state_set(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
700 * This function is used to save input events in an abstract struct
701 * to be used later by getsure-testing functions.
703 * @param data The gesture-layer object.
704 * @param event_info Pointer to recent input event.
705 * @param event_type Recent input event type.
706 * @param pe The abstract data-struct (output).
708 * @ingroup Elm_Gesture_Layer
711 _pointer_event_make(void *data __UNUSED__,
713 Evas_Callback_Type event_type,
716 memset(pe, '\0', sizeof(*pe));
719 case EVAS_CALLBACK_MOUSE_DOWN:
720 pe->x = ((Evas_Event_Mouse_Down *)event_info)->canvas.x;
721 pe->y = ((Evas_Event_Mouse_Down *)event_info)->canvas.y;
722 pe->timestamp = ((Evas_Event_Mouse_Down *)event_info)->timestamp;
723 pe->device = ELM_MOUSE_DEVICE;
726 case EVAS_CALLBACK_MOUSE_UP:
727 pe->x = ((Evas_Event_Mouse_Up *)event_info)->canvas.x;
728 pe->y = ((Evas_Event_Mouse_Up *)event_info)->canvas.y;
729 pe->timestamp = ((Evas_Event_Mouse_Up *)event_info)->timestamp;
730 pe->device = ELM_MOUSE_DEVICE;
733 case EVAS_CALLBACK_MOUSE_MOVE:
734 pe->x = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.x;
735 pe->y = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.y;
736 pe->timestamp = ((Evas_Event_Mouse_Move *)event_info)->timestamp;
737 pe->device = ELM_MOUSE_DEVICE;
740 case EVAS_CALLBACK_MULTI_DOWN:
741 pe->x = ((Evas_Event_Multi_Down *)event_info)->canvas.x;
742 pe->y = ((Evas_Event_Multi_Down *)event_info)->canvas.y;
743 pe->timestamp = ((Evas_Event_Multi_Down *)event_info)->timestamp;
744 pe->device = ((Evas_Event_Multi_Down *)event_info)->device;
747 case EVAS_CALLBACK_MULTI_UP:
748 pe->x = ((Evas_Event_Multi_Up *)event_info)->canvas.x;
749 pe->y = ((Evas_Event_Multi_Up *)event_info)->canvas.y;
750 pe->timestamp = ((Evas_Event_Multi_Up *)event_info)->timestamp;
751 pe->device = ((Evas_Event_Multi_Up *)event_info)->device;
754 case EVAS_CALLBACK_MULTI_MOVE:
755 pe->x = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.x;
756 pe->y = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.y;
757 pe->timestamp = ((Evas_Event_Multi_Move *)event_info)->timestamp;
758 pe->device = ((Evas_Event_Multi_Move *)event_info)->device;
765 pe->event_type = event_type;
772 * This function copies input events.
773 * We copy event info before adding it to history.
774 * The memory is freed when we clear history.
776 * @param event the event to copy
777 * @param event_type event type to copy
779 * @ingroup Elm_Gesture_Layer
782 _event_info_copy(void *event,
783 Evas_Callback_Type event_type)
787 case EVAS_CALLBACK_MOUSE_DOWN:
788 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *)event);
791 case EVAS_CALLBACK_MOUSE_MOVE:
792 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *)event);
795 case EVAS_CALLBACK_MOUSE_UP:
796 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *)event);
799 case EVAS_CALLBACK_MOUSE_WHEEL:
800 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *)event);
803 case EVAS_CALLBACK_MULTI_DOWN:
804 return COPY_EVENT_INFO((Evas_Event_Multi_Down *)event);
807 case EVAS_CALLBACK_MULTI_MOVE:
808 return COPY_EVENT_INFO((Evas_Event_Multi_Move *)event);
811 case EVAS_CALLBACK_MULTI_UP:
812 return COPY_EVENT_INFO((Evas_Event_Multi_Up *)event);
815 case EVAS_CALLBACK_KEY_DOWN:
816 return COPY_EVENT_INFO((Evas_Event_Key_Down *)event);
819 case EVAS_CALLBACK_KEY_UP:
820 return COPY_EVENT_INFO((Evas_Event_Key_Up *)event);
829 _event_history_add(Evas_Object *obj,
831 Evas_Callback_Type event_type)
835 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
837 ev = malloc(sizeof(Event_History));
838 ev->event = _event_info_copy(event, event_type); /* Freed on
839 * _event_history_clear */
840 ev->event_type = event_type;
841 sd->event_history_list = (Event_History *)eina_inlist_append(
842 EINA_INLIST_GET(sd->event_history_list), EINA_INLIST_GET(ev));
848 * For all _mouse_* / multi_* functions wethen send this event to
849 * _event_process function.
851 * @param data The gesture-layer object.
852 * @param event_info Pointer to recent input event.
854 * @ingroup Elm_Gesture_Layer
857 _mouse_down_cb(void *data,
859 Evas_Object *obj __UNUSED__,
862 if (((Evas_Event_Mouse_Down *)event_info)->button != 1)
863 return; /* We only process left-click at the moment */
865 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
869 _mouse_move_cb(void *data,
871 Evas_Object *obj __UNUSED__,
874 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
878 _key_down_cb(void *data,
880 Evas_Object *obj __UNUSED__,
883 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
887 _key_up_cb(void *data,
889 Evas_Object *obj __UNUSED__,
892 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
896 _mouse_up_cb(void *data,
898 Evas_Object *obj __UNUSED__,
901 if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
902 return; /* We only process left-click at the moment */
904 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
908 _mouse_wheel_cb(void *data,
910 Evas_Object *obj __UNUSED__,
913 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
917 _multi_down_cb(void *data,
919 Evas_Object *obj __UNUSED__,
922 /* Skip the mouse duplicates. */
923 if (((Evas_Event_Multi_Down *) event_info)->device == 0) return;
925 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
929 _multi_move_cb(void *data,
931 Evas_Object *obj __UNUSED__,
934 /* Skip the mouse duplicates. */
935 if (((Evas_Event_Multi_Move *) event_info)->device == 0) return;
937 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
941 _multi_up_cb(void *data,
943 Evas_Object *obj __UNUSED__,
946 /* Skip the mouse duplicates. */
947 if (((Evas_Event_Multi_Up *) event_info)->device == 0) return;
949 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
953 _target_del_cb(void *data,
955 Evas_Object *obj __UNUSED__,
956 void *event_info __UNUSED__)
958 _callbacks_unregister(data);
964 * We register callbacks when gesture layer is attached to an object
965 * or when its enabled after disable.
967 * @param obj The gesture-layer object.
969 * @ingroup Elm_Gesture_Layer
972 _callbacks_register(Evas_Object *obj)
974 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
976 if (!sd->target) return;
978 evas_object_event_callback_add
979 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
980 evas_object_event_callback_add
981 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
982 evas_object_event_callback_add
983 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
985 evas_object_event_callback_add
986 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
988 evas_object_event_callback_add
989 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
990 evas_object_event_callback_add
991 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
992 evas_object_event_callback_add
993 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
995 evas_object_event_callback_add
996 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
997 evas_object_event_callback_add
998 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1000 evas_object_event_callback_add
1001 (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1007 * We unregister callbacks when gesture layer is disabled.
1009 * @param obj The gesture-layer object.
1011 * @ingroup Elm_Gesture_Layer
1014 _callbacks_unregister(Evas_Object *obj)
1016 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1018 if (!sd->target) return;
1020 evas_object_event_callback_del_full
1021 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
1022 evas_object_event_callback_del_full
1023 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
1024 evas_object_event_callback_del_full
1025 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
1027 evas_object_event_callback_del_full
1028 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
1030 evas_object_event_callback_del_full
1031 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
1033 evas_object_event_callback_del_full
1034 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
1036 evas_object_event_callback_del_full
1037 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1039 evas_object_event_callback_del_full
1040 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1041 evas_object_event_callback_del_full
1042 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1044 evas_object_event_callback_del_full
1045 (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1050 * This function is used to find if device number
1051 * is found in a list of devices.
1052 * The list contains devices for refeeding *UP event
1054 * @ingroup Elm_Gesture_Layer
1057 _device_in_pending_cmp(const void *data1,
1060 /* Compare the two device numbers */
1061 return ((intptr_t)data1) - ((intptr_t)data2);
1067 * This functions returns pending-device node
1068 * @ingroup Elm_Gesture_Layer
1071 _device_is_pending(Eina_List *list,
1073 Evas_Callback_Type event_type)
1075 int device = ELM_MOUSE_DEVICE;
1079 case EVAS_CALLBACK_MOUSE_UP:
1082 case EVAS_CALLBACK_MULTI_UP:
1083 device = ((Evas_Event_Multi_Up *)event)->device;
1090 return eina_list_search_unsorted_list
1091 (list, _device_in_pending_cmp, (void *)(intptr_t)device);
1097 * This functions adds device to refeed-pending device list
1098 * @ingroup Elm_Gesture_Layer
1101 _pending_device_add(Eina_List *list,
1103 Evas_Callback_Type event_type)
1105 int device = ELM_MOUSE_DEVICE;
1109 case EVAS_CALLBACK_MOUSE_DOWN:
1112 case EVAS_CALLBACK_MULTI_DOWN:
1113 device = ((Evas_Event_Multi_Down *)event)->device;
1120 if (!eina_list_search_unsorted_list
1121 (list, _device_in_pending_cmp, (void *)(intptr_t)device))
1123 return eina_list_append(list, (void *)(intptr_t)device);
1132 * This function reports ABORT to all none-detected gestures
1133 * Then resets test bits for all desired gesures
1134 * and clears input-events history.
1135 * note: if no gesture was detected, events from history list
1136 * are streamed to the widget because it's unused by layer.
1137 * user may cancel refeed of events by setting repeat events.
1139 * @param obj The gesture-layer object.
1141 * @ingroup Elm_Gesture_Layer
1144 _event_history_clear(Evas_Object *obj)
1148 Evas *e = evas_object_evas_get(obj);
1149 Eina_Bool gesture_found = EINA_FALSE;
1151 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1153 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1158 if (p->state == ELM_GESTURE_STATE_END)
1160 gesture_found = EINA_TRUE;
1163 { /* Report ABORT to all gestures that still not finished */
1164 _state_set(p, ELM_GESTURE_STATE_ABORT, sd->gesture[i]->info,
1170 _states_reset(sd); /* we are ready to start testing for gestures again */
1172 /* Clear all gestures intermediate data */
1174 /* FIXME: +1 because of the mistake in the enum. */
1175 Gesture_Info **gitr = sd->gesture + 1;
1176 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1177 for (; fitr->reset; fitr++, gitr++)
1179 if (IS_TESTED_GESTURE(*gitr))
1184 /* Disable gesture layer so refeeded events won't be consumed by it */
1185 _callbacks_unregister(obj);
1186 while (sd->event_history_list)
1189 t = sd->event_history_list;
1190 Eina_List *pending = _device_is_pending
1191 (sd->pending, sd->event_history_list->event,
1192 sd->event_history_list->event_type);
1194 /* Refeed events if no gesture matched input */
1195 if (pending || ((!gesture_found) && (!sd->repeat_events)))
1197 evas_event_refeed_event(e, sd->event_history_list->event,
1198 sd->event_history_list->event_type);
1202 sd->pending = eina_list_remove_list(sd->pending, pending);
1206 sd->pending = _pending_device_add
1207 (sd->pending, sd->event_history_list->event,
1208 sd->event_history_list->event_type);
1212 free(sd->event_history_list->event);
1213 sd->event_history_list = (Event_History *)eina_inlist_remove(
1214 EINA_INLIST_GET(sd->event_history_list),
1215 EINA_INLIST_GET(sd->event_history_list));
1218 _callbacks_register(obj);
1225 * if gesture was NOT detected AND we only have gestures in ABORT state
1226 * we clear history immediately to be ready for input.
1228 * @param obj The gesture-layer object.
1229 * @return TRUE on event history_clear
1231 * @ingroup Elm_Gesture_Layer
1234 _clear_if_finished(Evas_Object *obj)
1237 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
1239 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1241 /* Clear history if all we have aborted gestures */
1242 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1243 { /* If no gesture started and all we have aborted gestures, reset all */
1244 Gesture_Info *p = sd->gesture[i];
1246 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
1248 if ((p->state == ELM_GESTURE_STATE_START) ||
1249 (p->state == ELM_GESTURE_STATE_MOVE))
1250 reset_s = EINA_FALSE;
1252 all_undefined = EINA_FALSE;
1256 if (reset_s && (!all_undefined))
1257 return _event_history_clear(obj);
1265 * This function restartes line, flick, zoom and rotate gestures
1266 * when gesture-layer continues-gestures enabled.
1267 * Example of continues-gesture:
1268 * When doing a line, user stops moving finger but keeps fingers on touch.
1269 * This will cause line-end, then as user continues moving his finger
1270 * it re-starts line gesture.
1271 * When continue mode is disabled, user has to lift finger from touch
1272 * to end a gesture. Them touch-again to start a new one.
1274 * @param data The gesture-layer object.
1275 * @param sd gesture layer widget data.
1276 * @param states_reset flag that marks gestures were reset in history clear.
1278 * @ingroup Elm_Gesture_Layer
1281 _continues_gestures_restart(void *data,
1282 Eina_Bool states_reset)
1284 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1286 /* Test all the gestures */
1288 /* FIXME: +1 because of the mistake in the enum. */
1289 Gesture_Info **gitr = sd->gesture + 1;
1290 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1291 for (; fitr->test; fitr++, gitr++)
1293 Gesture_Info *g = *gitr;
1294 Eina_Bool tmp = (g) ?
1295 ((states_reset) || ((g->state != ELM_GESTURE_STATE_START)
1296 && (g->state != ELM_GESTURE_STATE_MOVE)))
1298 if (tmp && fitr->cont_reset)
1300 fitr->cont_reset(g);
1301 _state_set(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
1311 * This function the core-function where input handling is done.
1312 * Here we get user input and stream it to gesture testing.
1313 * We notify user about any gestures with new state:
1315 * START - gesture started.
1316 * MOVE - gesture is ongoing.
1317 * END - gesture was completed.
1318 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
1320 * We also check if a gesture was detected, then reset event history
1321 * If no gestures were found we reset gesture test flag
1322 * after streaming event-history to widget.
1323 * (stream to the widget all events not consumed as a gesture)
1325 * @param data The gesture-layer object.
1326 * @param event_info Pointer to recent input event.
1327 * @param event_type Recent input event type.
1329 * @ingroup Elm_Gesture_Layer
1332 _event_process(void *data,
1333 Evas_Object *obj __UNUSED__,
1335 Evas_Callback_Type event_type)
1338 Pointer_Event *pe = NULL;
1340 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1342 /* Start testing candidate gesture from here */
1343 if (_pointer_event_make(data, event_info, event_type, &_pe))
1346 /* Test all the gestures */
1348 /* FIXME: +1 because of the mistake in the enum. */
1349 Gesture_Info **gitr = sd->gesture + 1;
1350 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1351 for (; fitr->test; fitr++, gitr++)
1353 if (IS_TESTED_GESTURE(*gitr))
1354 fitr->test(data, pe, event_info, event_type, (*gitr)->g_type);
1358 if (_event_flag_get(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
1359 _event_history_add(data, event_info, event_type);
1361 /* we maintain list of touched devices */
1362 /* We also use move to track current device x.y pos */
1363 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1364 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1365 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1366 (event_type == EVAS_CALLBACK_MULTI_MOVE))
1368 sd->touched = _touched_device_add(sd->touched, pe);
1370 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
1371 (event_type == EVAS_CALLBACK_MULTI_UP))
1373 sd->touched = _touched_device_remove(sd->touched, pe);
1376 /* Report current states and clear history if needed */
1377 Eina_Bool states_reset = _clear_if_finished(data);
1378 if (sd->glayer_continues_enable)
1379 _continues_gestures_restart(data, states_reset);
1383 _inside(Evas_Coord xx1,
1388 int w = elm_config_finger_size_get() >> 1; /* Finger size devided by 2 */
1390 if (xx1 < (xx2 - w))
1393 if (xx1 > (xx2 + w))
1396 if (yy1 < (yy2 - w))
1399 if (yy1 > (yy2 + w))
1405 /* All *test_reset() funcs are called to clear
1406 * gesture intermediate data.
1407 * This happens when we need to reset our tests.
1408 * for example when gesture is detected or all ABORTed. */
1410 _tap_gestures_test_reset(Gesture_Info *gesture)
1415 EINA_SAFETY_ON_NULL_RETURN(gesture);
1416 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1418 ELM_SAFE_FREE(sd->gest_taps_timeout, ecore_timer_del);
1423 EINA_LIST_FREE(((Taps_Type *)gesture->data)->l, data)
1424 EINA_LIST_FREE(data, pe)
1427 memset(gesture->data, 0, sizeof(Taps_Type));
1430 /* All *test_reset() funcs are called to clear
1431 * gesture intermediate data.
1432 * This happens when we need to reset our tests.
1433 * for example when gesture is detected or all ABORTed. */
1435 _n_long_tap_test_reset(Gesture_Info *gesture)
1440 EINA_SAFETY_ON_NULL_RETURN(gesture);
1441 if (!gesture->data) return;
1445 EINA_LIST_FREE(st->touched, p)
1449 ELM_SAFE_FREE(st->timeout, ecore_timer_del);
1450 memset(gesture->data, 0, sizeof(Long_Tap_Type));
1454 _momentum_test_reset(Gesture_Info *gesture)
1456 EINA_SAFETY_ON_NULL_RETURN(gesture);
1457 if (!gesture->data) return;
1459 memset(gesture->data, 0, sizeof(Momentum_Type));
1463 _line_data_reset(Line_Data *st)
1468 memset(st, 0, sizeof(Line_Data));
1469 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1473 _line_test_reset(Gesture_Info *gesture)
1478 EINA_SAFETY_ON_NULL_RETURN(gesture);
1479 if (!gesture->data) return;
1483 EINA_LIST_FREE(st->list, t_line)
1489 _zoom_test_reset(Gesture_Info *gesture)
1492 Evas_Modifier_Mask mask;
1494 EINA_SAFETY_ON_NULL_RETURN(gesture);
1495 if (!gesture->data) return;
1496 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1499 mask = evas_key_modifier_mask_get(
1500 evas_object_evas_get(sd->target), "Control");
1501 evas_object_key_ungrab(sd->target, "Control_L", mask, 0);
1502 evas_object_key_ungrab(sd->target, "Control_R", mask, 0);
1504 memset(st, 0, sizeof(Zoom_Type));
1505 st->zoom_distance_tolerance = sd->zoom_distance_tolerance;
1506 st->info.zoom = 1.0;
1510 _rotate_test_reset(Gesture_Info *gesture)
1514 EINA_SAFETY_ON_NULL_RETURN(gesture);
1515 if (!gesture->data) return;
1517 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1520 memset(st, 0, sizeof(Rotate_Type));
1521 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1522 st->rotate_angular_tolerance = sd->rotate_angular_tolerance;
1526 _match_fingers_compare(const void *data1,
1529 /* Compare coords of first item in list to cur coords */
1530 const Pointer_Event *pe1 = eina_list_data_get(data1);
1531 const Pointer_Event *pe2 = data2;
1533 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1535 else if (pe1->x < pe2->x)
1539 if (pe1->x == pe2->x)
1540 return pe1->y - pe2->y;
1547 _pe_device_compare(const void *data1,
1550 /* Compare device of first item in list to our pe device */
1551 const Pointer_Event *pe1 = eina_list_data_get(data1);
1552 const Pointer_Event *pe2 = data2;
1554 /* Only match if last was a down event */
1555 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1556 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1559 if (pe1->device == pe2->device)
1561 else if (pe1->device < pe2->device)
1568 _pointer_event_record(Taps_Type *st,
1571 Elm_Gesture_Layer_Smart_Data *sd,
1573 Evas_Callback_Type event_type)
1575 /* Keep copy of pe and record it in list */
1576 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1578 memcpy(p, pe, sizeof(Pointer_Event));
1579 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1585 /* This will also update middle-point to report to user later */
1586 st->info.x = st->sum_x / st->n_taps;
1587 st->info.y = st->sum_y / st->n_taps;
1588 st->info.timestamp = pe->timestamp;
1592 pe_list = eina_list_append(pe_list, p);
1593 st->l = eina_list_append(st->l, pe_list);
1596 pe_list = eina_list_append(pe_list, p);
1604 * This function checks if the tap gesture is done.
1606 * @param data gesture info pointer
1607 * @return EINA_TRUE if it is done.
1609 * @ingroup Elm_Gesture_Layer
1612 _tap_gesture_check_finish(Gesture_Info *gesture)
1614 /* Here we check if taps-gesture was completed successfuly */
1615 /* Count how many taps were recieved on each device then */
1616 /* determine if it matches n_taps_needed defined on START */
1617 Taps_Type *st = gesture->data;
1621 if (!st->l) return EINA_FALSE;
1622 EINA_LIST_FOREACH(st->l, l, pe_list)
1624 /* No match taps number on device, ABORT */
1625 if (eina_list_count(pe_list) != st->n_taps_needed)
1637 * This function sets state a tap-gesture to END or ABORT
1639 * @param data gesture info pointer
1641 * @ingroup Elm_Gesture_Layer
1644 _tap_gesture_finish(void *data)
1646 /* This function will test each tap gesture when timer expires */
1647 Elm_Gesture_State s = ELM_GESTURE_STATE_ABORT;
1648 Gesture_Info *gesture = data;
1649 Taps_Type *st = gesture->data;
1651 if (_tap_gesture_check_finish(gesture))
1653 s = ELM_GESTURE_STATE_END;
1656 st->info.n = eina_list_count(st->l);
1657 _state_set(gesture, s, gesture->info, EINA_FALSE);
1658 _tap_gestures_test_reset(gesture);
1664 * when this timer expires we finish tap gestures.
1666 * @param data The gesture-layer object.
1667 * @return cancles callback for this timer.
1669 * @ingroup Elm_Gesture_Layer
1672 _multi_tap_timeout(void *data)
1674 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1676 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1677 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TAPS]);
1679 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1680 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1682 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1683 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1685 _clear_if_finished(data);
1686 sd->gest_taps_timeout = NULL;
1688 return ECORE_CALLBACK_CANCEL;
1694 * when this timer expires we START long tap gesture
1696 * @param data The gesture-layer object.
1697 * @return cancles callback for this timer.
1699 * @ingroup Elm_Gesture_Layer
1702 _long_tap_timeout(void *data)
1704 Gesture_Info *gesture = data;
1706 _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1707 gesture->data, EINA_TRUE);
1709 return ECORE_CALLBACK_RENEW;
1715 * This function checks the state of a tap gesture.
1717 * @param sd Gesture Layer Widget Data.
1718 * @param pe The recent input event as stored in pe struct.
1719 * @param event_info Original input event pointer.
1720 * @param event_type Type of original input event.
1721 * @param gesture what gesture is tested
1722 * @param how many taps for this gesture (1, 2 or 3)
1724 * @ingroup Elm_Gesture_Layer
1727 _tap_gesture_test(Evas_Object *obj,
1730 Evas_Callback_Type event_type,
1731 Elm_Gesture_Type g_type)
1735 Gesture_Info *gesture;
1736 Eina_List *pe_list = NULL;
1737 Pointer_Event *pe_down = NULL;
1738 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1740 /* Here we fill Tap struct */
1741 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1746 gesture = sd->gesture[g_type];
1747 if (!gesture) return;
1751 case ELM_GESTURE_N_TAPS:
1755 case ELM_GESTURE_N_DOUBLE_TAPS:
1759 case ELM_GESTURE_N_TRIPLE_TAPS:
1769 if (!st) /* Allocated once on first time */
1771 st = calloc(1, sizeof(Taps_Type));
1773 _tap_gestures_test_reset(gesture);
1776 switch (pe->event_type)
1778 case EVAS_CALLBACK_MULTI_DOWN:
1779 case EVAS_CALLBACK_MOUSE_DOWN:
1780 /* Check if got tap on same cord was tapped before */
1781 pe_list = eina_list_search_unsorted(st->l, _match_fingers_compare, pe);
1784 /* This device was touched in other cord before completion */
1785 eina_list_search_unsorted(st->l, _pe_device_compare, pe))
1787 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1788 &st->info, EINA_FALSE);
1789 _event_consume(sd, event_info, event_type, ev_flag);
1794 pe_list = _pointer_event_record
1795 (st, pe_list, pe, sd, event_info, event_type);
1796 if (!sd->gest_taps_timeout)
1798 if (sd->double_tap_timeout > 0.0)
1800 sd->gest_taps_timeout =
1801 ecore_timer_add(sd->double_tap_timeout,
1802 _multi_tap_timeout, gesture->obj);
1806 ecore_timer_reset(sd->gest_taps_timeout);
1808 /* This is the first mouse down we got */
1809 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1811 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
1812 &st->info, EINA_FALSE);
1813 _event_consume(sd, event_info, event_type, ev_flag);
1815 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1819 else if (eina_list_count(pe_list) > st->n_taps_needed)
1820 /* If we arleady got too many touches for this gesture. */
1821 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1822 &st->info, EINA_FALSE);
1826 case EVAS_CALLBACK_MULTI_UP:
1827 case EVAS_CALLBACK_MOUSE_UP:
1828 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1829 if (!pe_list) return;
1831 pe_list = _pointer_event_record
1832 (st, pe_list, pe, sd, event_info, event_type);
1834 if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1835 !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1836 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1837 ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1838 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1840 if (_tap_gesture_check_finish(gesture))
1842 _tap_gesture_finish(gesture);
1849 case EVAS_CALLBACK_MULTI_MOVE:
1850 case EVAS_CALLBACK_MOUSE_MOVE:
1851 /* Get first event in first list, this has to be a Mouse Down event */
1852 /* and verify that user didn't move out of this area before next tap */
1853 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1856 pe_down = eina_list_data_get(pe_list);
1857 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1859 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1860 &st->info, EINA_FALSE);
1861 _event_consume(sd, event_info, event_type, ev_flag);
1874 * This function computes center-point for long-tap gesture
1876 * @param st Long Tap gesture info pointer
1877 * @param pe The recent input event as stored in pe struct.
1879 * @ingroup Elm_Gesture_Layer
1882 _compute_taps_center(Long_Tap_Type *st,
1889 Evas_Coord x = 0, y = 0;
1891 if (!eina_list_count(st->touched))
1894 EINA_LIST_FOREACH(st->touched, l, p)
1895 { /* Accumulate all then take avarage */
1896 if (p->device == pe->device) /* This will take care of values
1897 * coming from MOVE event */
1909 *x_out = x / eina_list_count(st->touched);
1910 *y_out = y / eina_list_count(st->touched);
1916 * This function checks N long-tap gesture.
1918 * @param obj The gesture-layer object.
1919 * @param pe The recent input event as stored in pe struct.
1920 * @param event_info Original input event pointer.
1921 * @param event_type Type of original input event.
1922 * @param g_type what Gesture we are testing.
1923 * @param taps How many click/taps we test for.
1925 * @ingroup Elm_Gesture_Layer
1928 _n_long_tap_test(Evas_Object *obj,
1931 Evas_Callback_Type event_type,
1932 Elm_Gesture_Type g_type)
1934 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1935 Gesture_Info *gesture;
1938 /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1939 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1941 if (!pe) /* this happens when unhandled event arrived */
1942 return; /* see _make_pointer_event function */
1944 gesture = sd->gesture[g_type];
1945 if (!gesture) return;
1948 if (!st) /* Allocated once on first time */
1950 st = calloc(1, sizeof(Long_Tap_Type));
1952 _n_long_tap_test_reset(gesture);
1955 switch (pe->event_type)
1957 case EVAS_CALLBACK_MULTI_DOWN:
1958 case EVAS_CALLBACK_MOUSE_DOWN:
1959 st->touched = _touched_device_add(st->touched, pe);
1960 st->info.n = eina_list_count(st->touched);
1962 _event_consume(sd, event_info, event_type, ev_flag);
1963 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1964 st->center_x = st->info.x; /* Update coords for */
1965 st->center_y = st->info.y; /* reporting START */
1967 /* This is the first mouse down we got */
1968 if (eina_list_count(st->touched) == 1)
1970 _state_set(gesture, ELM_GESTURE_STATE_START,
1971 gesture->data, EINA_FALSE);
1972 st->info.timestamp = pe->timestamp;
1974 /* To test long tap */
1975 /* When this timer expires, gesture STARTED */
1976 if ((!st->timeout) && (sd->long_tap_start_timeout > 0.0))
1977 st->timeout = ecore_timer_add(sd->long_tap_start_timeout,
1978 _long_tap_timeout, gesture);
1983 ecore_timer_reset(st->timeout);
1988 case EVAS_CALLBACK_MULTI_UP:
1989 case EVAS_CALLBACK_MOUSE_UP:
1990 st->touched = _touched_device_remove(st->touched, pe);
1991 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1994 if (gesture->state == ELM_GESTURE_STATE_MOVE)
1995 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
1996 &st->info, EINA_FALSE);
1998 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1999 &st->info, EINA_FALSE);
2001 ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2002 _event_consume(sd, event_info, event_type, ev_flag);
2007 case EVAS_CALLBACK_MULTI_MOVE:
2008 case EVAS_CALLBACK_MOUSE_MOVE:
2010 ((gesture->state == ELM_GESTURE_STATE_START) ||
2011 /* Report MOVE only if STARTED */
2012 (gesture->state == ELM_GESTURE_STATE_MOVE)))
2017 _compute_taps_center(st, &x, &y, pe);
2018 /* ABORT if user moved fingers out of tap area */
2019 if (!_inside(x, y, st->center_x, st->center_y))
2021 ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2023 /* Report MOVE if gesture started */
2024 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2025 &st->info, EINA_FALSE);
2028 _event_consume(sd, event_info, event_type, ev_flag);
2040 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
2041 * This momentum value will be sent to widget when gesture is completed.
2043 * @param momentum pointer to buffer where we record momentum value.
2044 * @param x1 x coord where user started gesture.
2045 * @param y1 y coord where user started gesture.
2046 * @param x2 x coord where user completed gesture.
2047 * @param y2 y coord where user completed gesture.
2048 * @param t1x timestamp for X, when user started gesture.
2049 * @param t1y timestamp for Y, when user started gesture.
2050 * @param t2 timestamp when user completed gesture.
2052 * @ingroup Elm_Gesture_Layer
2055 _momentum_set(Elm_Gesture_Momentum_Info *momentum,
2064 Evas_Coord velx = 0, vely = 0, vel;
2065 Evas_Coord dx = xx2 - xx1;
2066 Evas_Coord dy = yy2 - yy1;
2071 velx = (dx * 1000) / dtx;
2074 vely = (dy * 1000) / dty;
2076 vel = sqrt((velx * velx) + (vely * vely));
2078 if ((_elm_config->thumbscroll_friction > 0.0) &&
2079 (vel > _elm_config->thumbscroll_momentum_threshold)) /* report
2082 momentum->mx = velx;
2083 momentum->my = vely;
2095 * This function is used for computing rotation angle (DEG).
2097 * @param x1 first finger x location.
2098 * @param y1 first finger y location.
2099 * @param x2 second finger x location.
2100 * @param y2 second finger y location.
2102 * @return angle of the line between (x1,y1), (x2,y2) in Deg.
2103 * Angles now are given in DEG, not RAD.
2104 * ZERO angle at 12-oclock, growing clockwise.
2106 * @ingroup Elm_Gesture_Layer
2109 _angle_get(Evas_Coord xx1,
2114 double a, xx, yy, rt = (-1);
2116 xx = fabs(xx2 - xx1);
2117 yy = fabs(yy2 - yy1);
2119 if (((int)xx) && ((int)yy))
2121 rt = a = RAD2DEG(atan(yy / xx));
2124 if (yy1 < yy2) rt = 360 - a;
2129 if (yy1 < yy2) rt = 180 + a;
2134 if (rt < 0) /* Do this only if rt is not set */
2136 if (((int)xx)) /* Horizontal line */
2138 if (xx2 < xx1) rt = 180;
2142 { /* Vertical line */
2143 if (yy2 < yy1) rt = 90;
2148 /* Now we want to change from:
2150 * original circle 180 0 We want: 270 90
2154 if (rt >= 360) rt -= 360;
2162 * This function is used for computing the magnitude and direction
2163 * of vector between two points.
2165 * @param x1 first finger x location.
2166 * @param y1 first finger y location.
2167 * @param x2 second finger x location.
2168 * @param y2 second finger y location.
2169 * @param l length computed (output)
2170 * @param a angle computed (output)
2172 * @ingroup Elm_Gesture_Layer
2175 _vector_get(Evas_Coord xx1,
2186 *l = (Evas_Coord)sqrt((xx * xx) + (yy * yy));
2187 *a = _angle_get(xx1, yy1, xx2, yy2);
2191 _direction_get(Evas_Coord xx1,
2194 if (xx2 < xx1) return -1;
2195 if (xx2 > xx1) return 1;
2203 * This function tests momentum gesture.
2204 * @param obj The gesture-layer object.
2205 * @param pe The recent input event as stored in pe struct.
2206 * @param event_info recent input event.
2207 * @param event_type recent event type.
2208 * @param g_type what Gesture we are testing.
2210 * @ingroup Elm_Gesture_Layer
2213 _momentum_test(Evas_Object *obj,
2216 Evas_Callback_Type event_type,
2217 Elm_Gesture_Type g_type)
2222 Gesture_Info *gesture;
2223 Pointer_Event pe_local;
2224 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2225 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
2226 unsigned int cnt = 1; /* We start counter counting current pe event */
2228 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2230 gesture = sd->gesture[g_type];
2231 if (!gesture) return;
2233 /* When continues enable = TRUE a gesture may START on MOVE event */
2234 /* We don't allow this to happen with the if-statement below. */
2235 /* When continues enable = FALSE a gesture may START on DOWN only */
2236 /* Therefor it would NOT start on MOVE event. */
2237 /* NOTE that touched list is updated AFTER this function returns */
2238 /* so (count == 0) when we get here on first touch on surface. */
2239 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2240 return; /* Got move on mouse-over move */
2243 if (!st) /* Allocated once on first time */
2245 st = calloc(1, sizeof(Momentum_Type));
2247 _momentum_test_reset(gesture);
2253 /* First make avarage of all touched devices to determine center point */
2254 pe_local = *pe; /* Copy pe event info to local */
2255 EINA_LIST_FOREACH(sd->touched, l, p)
2256 if (p->device != pe_local.device)
2263 /* Compute avarage to get center point */
2267 /* If user added finger - reset gesture */
2268 if ((st->info.n) && (st->info.n < cnt))
2269 state_to_report = ELM_GESTURE_STATE_ABORT;
2271 if (st->info.n < cnt)
2276 case EVAS_CALLBACK_MOUSE_DOWN:
2277 case EVAS_CALLBACK_MULTI_DOWN:
2278 case EVAS_CALLBACK_MOUSE_MOVE:
2279 case EVAS_CALLBACK_MULTI_MOVE:
2282 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2283 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2284 (sd->glayer_continues_enable)) /* start also on MOVE */
2285 { /* We start on MOVE when cont-enabled only */
2286 st->line_st.x = st->line_end.x = pe_local.x;
2287 st->line_st.y = st->line_end.y = pe_local.y;
2288 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
2289 st->xdir = st->ydir = 0;
2290 st->info.x2 = st->info.x1 = pe_local.x;
2291 st->info.y2 = st->info.y1 = pe_local.y;
2292 st->info.tx = st->info.ty = pe_local.timestamp;
2293 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
2294 &st->info, EINA_FALSE);
2295 _event_consume(sd, event_info, event_type, ev_flag);
2303 Eina_Bool force = EINA_TRUE; /* for move state */
2305 /* ABORT if got DOWN or MOVE event after UP+timeout */
2306 if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
2308 state_to_report = ELM_GESTURE_STATE_ABORT;
2312 /* We report state but don't compute momentum now */
2313 ev_flag = _state_set(gesture, state_to_report, &st->info,
2315 _event_consume(sd, event_info, event_type, ev_flag);
2316 return; /* Stop computing when user remove finger */
2319 /* Too long of a wait, reset all values */
2320 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2322 st->line_st.x = pe_local.x;
2323 st->line_st.y = pe_local.y;
2324 st->t_st_y = st->t_st_x = pe_local.timestamp;
2325 st->info.tx = st->t_st_x;
2326 st->info.ty = st->t_st_y;
2327 st->xdir = st->ydir = 0;
2333 xdir = _direction_get(st->line_end.x, pe_local.x);
2334 ydir = _direction_get(st->line_end.y, pe_local.y);
2335 if (xdir && (xdir != st->xdir))
2337 st->line_st.x = st->line_end.x;
2338 st->info.tx = st->t_st_x = st->t_end;
2342 if (ydir && (ydir != st->ydir))
2344 st->line_st.y = st->line_end.y;
2345 st->info.ty = st->t_st_y = st->t_end;
2350 st->info.x2 = st->line_end.x = pe_local.x;
2351 st->info.y2 = st->line_end.y = pe_local.y;
2352 st->t_end = pe_local.timestamp;
2353 _momentum_set(&st->info, st->line_st.x, st->line_st.y,
2354 pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2355 pe_local.timestamp);
2357 ev_flag = _state_set(gesture, state_to_report, &st->info,
2359 _event_consume(sd, event_info, event_type, ev_flag);
2362 case EVAS_CALLBACK_MOUSE_UP:
2363 case EVAS_CALLBACK_MULTI_UP:
2364 st->t_up = pe_local.timestamp; /* Record recent up event time */
2365 if ((cnt > 1) || /* Ignore if more fingers touch surface */
2366 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2369 /* Too long of a wait, reset all values */
2370 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2372 st->line_st.x = pe_local.x;
2373 st->line_st.y = pe_local.y;
2374 st->t_st_y = st->t_st_x = pe_local.timestamp;
2375 st->xdir = st->ydir = 0;
2378 st->info.x2 = pe_local.x;
2379 st->info.y2 = pe_local.y;
2380 st->line_end.x = pe_local.x;
2381 st->line_end.y = pe_local.y;
2382 st->t_end = pe_local.timestamp;
2384 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2385 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2386 state_to_report = ELM_GESTURE_STATE_END;
2388 state_to_report = ELM_GESTURE_STATE_ABORT;
2390 ev_flag = _state_set(gesture, state_to_report, &st->info,
2392 _event_consume(sd, event_info, event_type, ev_flag);
2401 _line_device_compare(const void *data1,
2404 /* Compare device component of line struct */
2405 const Line_Data *ln1 = data1;
2406 const int *device = data2;
2408 if (ln1->t_st) /* Compare only with lines that started */
2409 return ln1->device - (*device);
2417 * This function construct line struct from input.
2418 * @param info pointer to store line momentum.
2419 * @param st line info to store input data.
2420 * @param pe The recent input event as stored in pe struct.
2422 * @ingroup Elm_Gesture_Layer
2425 _single_line_process(Elm_Gesture_Line_Info *info,
2428 Evas_Callback_Type event_type)
2430 /* Record events and set momentum for line pointed by st */
2436 case EVAS_CALLBACK_MOUSE_DOWN:
2437 case EVAS_CALLBACK_MOUSE_MOVE:
2438 case EVAS_CALLBACK_MULTI_DOWN:
2439 case EVAS_CALLBACK_MULTI_MOVE:
2440 if (!st->t_st) /* This happens only when line starts */
2442 st->line_st.x = pe->x;
2443 st->line_st.y = pe->y;
2444 st->t_st = pe->timestamp;
2445 st->device = pe->device;
2446 info->momentum.x1 = pe->x;
2447 info->momentum.y1 = pe->y;
2448 info->momentum.tx = pe->timestamp;
2449 info->momentum.ty = pe->timestamp;
2456 case EVAS_CALLBACK_MOUSE_UP:
2457 case EVAS_CALLBACK_MULTI_UP:
2458 /* IGNORE if line info was cleared, like long press, move */
2462 st->line_end.x = pe->x;
2463 st->line_end.y = pe->y;
2464 st->t_end = pe->timestamp;
2473 _line_data_reset(st);
2477 info->momentum.x2 = pe->x;
2478 info->momentum.y2 = pe->y;
2479 _momentum_set(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2480 st->t_st, st->t_st, pe->timestamp);
2488 * This function test for (n) line gesture.
2489 * @param obj The gesture-layer object.
2490 * @param pe The recent input event as stored in pe struct.
2491 * @param event_info Original input event pointer.
2492 * @param event_type Type of original input event.
2493 * @param g_type what Gesture we are testing.
2495 * @ingroup Elm_Gesture_Layer
2498 _n_line_test(Evas_Object *obj,
2501 Evas_Callback_Type event_type,
2502 Elm_Gesture_Type g_type)
2507 Gesture_Info *gesture;
2508 Line_Data *line = NULL;
2513 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2515 gesture = sd->gesture[g_type];
2516 if (!gesture ) return;
2518 /* When continues enable = TRUE a gesture may START on MOVE event */
2519 /* We don't allow this to happen with the if-statement below. */
2520 /* When continues enable = FALSE a gesture may START on DOWN only */
2521 /* Therefor it would NOT start on MOVE event. */
2522 /* NOTE that touched list is updated AFTER this function returns */
2523 /* so (count == 0) when we get here on first touch on surface. */
2524 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2525 return; /* Got move on mouse-over move */
2530 st = calloc(1, sizeof(Line_Type));
2535 cnt = eina_list_count(list);
2537 if (cnt) /* list is not empty, locate this device on list */
2539 line = (Line_Data *)eina_list_search_unsorted
2540 (st->list, _line_device_compare, &pe->device);
2543 if (!line) /* List is empty or device not found, new line-struct on
2546 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2547 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2548 ((sd->glayer_continues_enable) && /* START on MOVE also */
2549 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2550 /* Allocate new item on START only */
2551 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2553 line = calloc(1, sizeof(Line_Data));
2554 _line_data_reset(line);
2555 list = eina_list_append(list, line);
2560 if (!line) /* This may happen on MOVE that comes before DOWN */
2561 return; /* No line-struct to work with, can't continue testing */
2563 /* update st with input */
2564 if (_single_line_process(&st->info, line, pe, event_type))
2565 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2567 /* Get direction and magnitude of the line */
2569 _vector_get(line->line_st.x, line->line_st.y, pe->x, pe->y,
2570 &line->line_length, &angle);
2572 /* These are used later to compare lines length */
2573 Evas_Coord shortest_line_len = line->line_length;
2574 Evas_Coord longest_line_len = line->line_length;
2575 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2577 /* Now update line-state */
2578 if (line->t_st) /* Analyze line only if line started */
2580 if (line->line_angle >= 0.0) /* if line direction was set, we
2581 * test if broke tolerance */
2583 double a = fabs(angle - line->line_angle);
2584 /* Distance from line */
2585 double d = (tan(DEG2RAD(a))) * line->line_length;
2586 /* Broke tolerance: abort line and start a new one */
2587 if ((d > sd->line_distance_tolerance) ||
2588 (a > sd->line_angular_tolerance))
2590 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2591 &st->info, EINA_FALSE);
2592 _event_consume(sd, event_info, event_type, ev_flag);
2596 /* We may finish line if momentum is zero */
2597 if (sd->glayer_continues_enable)
2599 /* This is for continues-gesture */
2600 /* Finish line on zero momentum for continues gesture */
2601 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2603 line->line_end.x = pe->x;
2604 line->line_end.y = pe->y;
2605 line->t_end = pe->timestamp;
2610 { /* Record the line angle as it broke minimum length for line */
2611 if (line->line_length >= sd->line_min_length)
2612 st->info.angle = line->line_angle = angle;
2617 if (line->line_angle < 0.0) /* it's not a line, too short
2618 * more close to a tap */
2620 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2621 &st->info, EINA_FALSE);
2622 _event_consume(sd, event_info, event_type, ev_flag);
2628 /* Count how many lines already started / ended */
2631 unsigned int tm_start = pe->timestamp;
2632 unsigned int tm_end = pe->timestamp;
2635 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2636 Eina_Bool lines_parallel = EINA_TRUE;
2637 EINA_LIST_FOREACH(list, l, t_line)
2640 base_angle = t_line->line_angle;
2643 if (t_line->line_angle >= 0) /* Compare angle only with
2644 * lines with direction
2647 if (fabs(base_angle - t_line->line_angle) >
2648 sd->line_angular_tolerance)
2649 lines_parallel = EINA_FALSE;
2653 if (t_line->line_length) /* update only if this line is used */
2655 if (shortest_line_len > t_line->line_length)
2656 shortest_line_len = t_line->line_length;
2658 if (longest_line_len < t_line->line_length)
2659 longest_line_len = t_line->line_length;
2665 if (t_line->t_st < tm_start)
2666 tm_start = t_line->t_st;
2672 if (t_line->t_end < tm_end)
2673 tm_end = t_line->t_end;
2677 st->info.momentum.n = started;
2680 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2681 /* user lift one finger then starts again without line-end - ABORT */
2682 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2684 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2686 _event_consume(sd, event_info, event_type, ev_flag);
2690 if (!lines_parallel) /* Lines are NOT at same direction, abort this
2693 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2695 _event_consume(sd, event_info, event_type, ev_flag);
2699 /* We report ABORT if lines length are NOT matching when fingers are up */
2700 if ((longest_line_len - shortest_line_len) >
2701 (elm_config_finger_size_get() * 2))
2703 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2705 _event_consume(sd, event_info, event_type, ev_flag);
2709 /* We consider FLICK as a fast line.ABORT if take too long to finish */
2710 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) >
2711 sd->flick_time_limit_ms))
2713 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2715 _event_consume(sd, event_info, event_type, ev_flag);
2721 case EVAS_CALLBACK_MOUSE_UP:
2722 case EVAS_CALLBACK_MULTI_UP:
2723 if ((started) && (started == ended))
2725 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2726 &st->info, EINA_FALSE);
2727 _event_consume(sd, event_info, event_type, ev_flag);
2732 case EVAS_CALLBACK_MOUSE_DOWN:
2733 case EVAS_CALLBACK_MULTI_DOWN:
2734 case EVAS_CALLBACK_MOUSE_MOVE:
2735 case EVAS_CALLBACK_MULTI_MOVE:
2738 /* For continues gesture */
2739 if (sd->glayer_continues_enable && (started == ended))
2741 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2742 &st->info, EINA_FALSE);
2743 _event_consume(sd, event_info, event_type, ev_flag);
2746 { /* When continues, may START on MOVE event too */
2747 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2749 /* This happens when: on n > 1 lines then one finger up */
2750 /* caused abort, then put finger down. */
2751 /* This will stop line from starting again. */
2752 /* Number of lines, MUST match touched-device in list */
2753 if ((!sd->glayer_continues_enable) &&
2754 (eina_list_count(st->list) <
2755 eina_list_count(sd->touched)))
2756 s = ELM_GESTURE_STATE_ABORT;
2758 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2759 s = ELM_GESTURE_STATE_START;
2761 ev_flag = _state_set(gesture, s, &st->info, EINA_TRUE);
2762 _event_consume(sd, event_info, event_type, ev_flag);
2768 return; /* Unhandeld event type */
2775 * This function is used to check if rotation gesture started.
2776 * @param st Contains current rotation values from user input.
2777 * @return TRUE/FALSE if we need to set rotation START.
2779 * @ingroup Elm_Gesture_Layer
2782 _on_rotation_broke_tolerance(Rotate_Type *st)
2784 if (st->info.base_angle < 0)
2785 return EINA_FALSE; /* Angle has to be computed first */
2787 if (st->rotate_angular_tolerance < 0)
2790 double low = st->info.base_angle - st->rotate_angular_tolerance;
2791 double high = st->info.base_angle + st->rotate_angular_tolerance;
2792 double t = st->info.angle;
2816 if ((t < low) || (t > high)) /* This marks that roation action has
2819 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2820 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2830 * This function is used for computing the gap between fingers.
2831 * It returns the length and center point between fingers.
2833 * @param x1 first finger x location.
2834 * @param y1 first finger y location.
2835 * @param x2 second finger x location.
2836 * @param y2 second finger y location.
2837 * @param x Gets center point x cord (output)
2838 * @param y Gets center point y cord (output)
2840 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2842 * @ingroup Elm_Gesture_Layer
2845 _finger_gap_length_get(Evas_Coord xx1,
2852 double a, b, xx, yy, gap;
2853 xx = fabs(xx2 - xx1);
2854 yy = fabs(yy2 - yy1);
2855 gap = sqrt((xx * xx) + (yy * yy));
2857 /* START - Compute zoom center point */
2858 /* The triangle defined as follows:
2866 * http://en.wikipedia.org/wiki/Trigonometric_functions
2867 *************************************/
2868 if (((int)xx) && ((int)yy))
2870 double A = atan((yy / xx));
2871 a = (Evas_Coord)((gap / 2) * sin(A));
2872 b = (Evas_Coord)((gap / 2) * cos(A));
2873 *x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
2874 *y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
2878 if ((int)xx) /* horiz line, take half width */
2880 *x = (Evas_Coord)((xx1 + xx2) / 2);
2881 *y = (Evas_Coord)(yy1);
2884 if ((int)yy) /* vert line, take half width */
2886 *x = (Evas_Coord)(xx1);
2887 *y = (Evas_Coord)((yy1 + yy2) / 2);
2890 /* END - Compute zoom center point */
2892 return (Evas_Coord)gap;
2898 * This function is used for computing zoom value.
2900 * @param st Pointer to zoom data based on user input.
2901 * @param tm_end Recent input event timestamp.
2902 * @param zoom_val Current computed zoom value.
2904 * @return zoom momentum
2906 * @ingroup Elm_Gesture_Layer
2909 _zoom_momentum_get(Zoom_Type *st,
2910 unsigned int tm_end,
2913 unsigned int tm_total;
2914 if (!st->m_st_tm) /* Init, and we don't start computing momentum yet */
2916 st->m_st_tm = st->m_prev_tm = tm_end;
2917 st->m_base = zoom_val;
2921 if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
2922 return 0.0; /* we don't start to compute momentum yet */
2924 if (st->dir) /* if direction was already defined, check if changed */
2926 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2927 /* Direction changed, reset momentum */
2928 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2931 st->dir = (-st->dir);
2936 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2938 if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
2940 st->m_st_tm = 0; /* Rest momentum when waiting too long */
2944 st->m_prev_tm = tm_end;
2945 tm_total = tm_end - st->m_st_tm;
2948 return ((zoom_val - st->m_base) * 1000) / tm_total;
2956 * This function is used for computing zoom value.
2958 * @param st Pointer to zoom data based on user input.
2959 * @param x1 first finger x location.
2960 * @param y1 first finger y location.
2961 * @param x2 second finger x location.
2962 * @param y2 second finger y location.
2963 * @param factor zoom-factor, used to determine how fast zoom works.
2965 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2967 * @ingroup Elm_Gesture_Layer
2970 _zoom_compute(Zoom_Type *st,
2975 double zoom_finger_factor)
2978 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2979 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2981 Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
2982 &st->info.x, &st->info.y);
2984 st->info.radius = diam / 2;
2988 st->zoom_base = diam;
2989 return st->info.zoom;
2992 if (st->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
2993 * zoom action NOT started yet */
2995 /* avoid jump with zoom value when break tolerance */
2996 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2998 st->zoom_base -= st->zoom_distance_tolerance;
2999 st->zoom_distance_tolerance = 0;
3002 /* avoid jump with zoom value when break tolerance */
3003 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
3005 st->zoom_base += st->zoom_distance_tolerance;
3006 st->zoom_distance_tolerance = 0;
3012 /* We use factor only on the difference between gap-base */
3013 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
3014 rt = ((1.0) + ((((float)diam - (float)st->zoom_base) /
3015 (float)st->zoom_base) * zoom_finger_factor));
3017 /* Momentum: zoom per second: */
3018 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
3026 * This function handles zoom with mouse wheel.
3027 * thats a combination of wheel + CTRL key.
3028 * @param obj The gesture-layer object.
3029 * @param event_info Original input event pointer.
3030 * @param event_type Type of original input event.
3031 * @param g_type what Gesture we are testing.
3033 * @ingroup Elm_Gesture_Layer
3036 _zoom_with_wheel_test(Evas_Object *obj,
3038 Evas_Callback_Type event_type,
3039 Elm_Gesture_Type g_type)
3041 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3043 if (!sd->gesture[g_type]) return;
3045 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3046 Zoom_Type *st = gesture_zoom->data;
3047 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3048 if (!st) /* Allocated once on first time, used for zoom intermediate data */
3050 st = calloc(1, sizeof(Zoom_Type));
3051 gesture_zoom->data = st;
3052 _zoom_test_reset(gesture_zoom);
3057 case EVAS_CALLBACK_KEY_UP:
3059 Evas_Event_Key_Up *p = event_info;
3060 if ((!strcmp(p->keyname, "Control_L")) ||
3061 /* Test if we ended a zoom gesture when releasing CTRL */
3062 (!strcmp(p->keyname, "Control_R")))
3064 if ((st->zoom_wheel) &&
3065 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3066 /* User released CTRL after zooming */
3067 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3069 st->info.momentum = _zoom_momentum_get
3070 (st, p->timestamp, st->info.zoom);
3072 ev_flag = _state_set
3073 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3075 _event_consume(sd, event_info, event_type, ev_flag);
3083 case EVAS_CALLBACK_MOUSE_WHEEL:
3086 Elm_Gesture_State s;
3087 if (!evas_key_modifier_is_set(
3088 ((Evas_Event_Mouse_Wheel *)event_info)->modifiers,
3089 "Control")) /* if using wheel witout CTRL after starting zoom */
3091 if ((st->zoom_wheel) &&
3092 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3093 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3095 ev_flag = _state_set
3096 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3098 _event_consume(sd, event_info, event_type, ev_flag);
3103 return; /* Ignore mouse-wheel without control */
3106 /* Using mouse wheel with CTRL for zoom */
3107 /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0) we
3108 * continue a zoom gesture */
3109 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
3112 s = ELM_GESTURE_STATE_MOVE;
3115 { /* On first wheel event, report START */
3116 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
3117 evas_object_evas_get(sd->target), "Control");
3119 s = ELM_GESTURE_STATE_START;
3120 if (!evas_object_key_grab
3121 (sd->target, "Control_L", mask, 0, EINA_FALSE))
3122 ERR("Failed to Grabbed CTRL_L");
3123 if (!evas_object_key_grab
3124 (sd->target, "Control_R", mask, 0, EINA_FALSE))
3125 ERR("Failed to Grabbed CTRL_R");
3128 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
3129 st->zoom_wheel = (Evas_Event_Mouse_Wheel *)event_info;
3130 st->info.x = st->zoom_wheel->canvas.x;
3131 st->info.y = st->zoom_wheel->canvas.y;
3133 if (st->zoom_wheel->z < 0) /* zoom in */
3134 st->info.zoom += (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3136 if (st->zoom_wheel->z > 0) /* zoom out */
3137 st->info.zoom -= (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3139 if (st->info.zoom < 0.0)
3140 st->info.zoom = 0.0;
3142 st->info.momentum = _zoom_momentum_get
3143 (st, st->zoom_wheel->timestamp, st->info.zoom);
3145 ev_flag = _state_set(gesture_zoom, s, &st->info, force);
3146 _event_consume(sd, event_info, event_type, ev_flag);
3158 * This function is used to test zoom gesture.
3159 * user may combine zoom, rotation together.
3160 * so its possible that both will be detected from input.
3161 * (both are two-finger movement-oriented gestures)
3163 * @param obj The gesture-layer object.
3164 * @param event_info Pointer to recent input event.
3165 * @param event_type Recent input event type.
3166 * @param g_type what Gesture we are testing.
3168 * @ingroup Elm_Gesture_Layer
3171 _zoom_test(Evas_Object *obj,
3174 Evas_Callback_Type event_type,
3175 Elm_Gesture_Type g_type)
3177 /* Test for wheel zoom. */
3178 _zoom_with_wheel_test(obj, event_info, event_type, ELM_GESTURE_ZOOM);
3180 if (!_elm_config->glayer_zoom_finger_enable)
3185 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3187 if (!sd->gesture[g_type]) return;
3189 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3190 Zoom_Type *st = gesture_zoom->data;
3192 if (!st) /* Allocated once on first time, used for zoom data */
3194 st = calloc(1, sizeof(Zoom_Type));
3195 gesture_zoom->data = st;
3196 _zoom_test_reset(gesture_zoom);
3199 /* Start - new zoom testing, letting all fingers start */
3200 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3203 case EVAS_CALLBACK_MOUSE_MOVE:
3204 case EVAS_CALLBACK_MULTI_MOVE:
3205 /* if non-continues mode and gesture NOT started, ignore MOVE */
3206 if ((!sd->glayer_continues_enable) &&
3207 (!st->zoom_st.timestamp))
3210 case EVAS_CALLBACK_MOUSE_DOWN:
3211 case EVAS_CALLBACK_MULTI_DOWN:
3212 { /* Here we take care of zoom-start and zoom move */
3216 if (eina_list_count(sd->touched) > 2) /* Process zoom only
3220 ev_flag = _state_set
3221 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3223 _event_consume(sd, event_info, event_type, ev_flag);
3228 if (!st->zoom_st.timestamp) /* Now scan touched-devices list
3229 * and find other finger */
3231 EINA_LIST_FOREACH(sd->touched, l, p)
3232 { /* Device of other finger <> pe device */
3233 if (p->device != pe->device)
3237 if (!p) /* Single finger on touch */
3240 /* Record down fingers */
3241 _event_consume(sd, event_info, event_type, ev_flag);
3242 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
3243 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
3245 /* Set mv field as well to be ready for MOVE events */
3246 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3247 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
3249 /* Here we have zoom_st, zoom_st1 set, report START */
3250 /* Set zoom-base after BOTH down events recorded */
3251 /* Compute length of line between fingers zoom start */
3252 st->info.zoom = 1.0;
3253 st->zoom_base = _finger_gap_length_get
3254 (st->zoom_st1.x, st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
3255 &st->info.x, &st->info.y);
3257 st->info.radius = st->zoom_base / 2;
3259 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
3260 /* zoom started with mouse-wheel, don't report twice */
3261 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
3263 ev_flag = _state_set
3264 (gesture_zoom, ELM_GESTURE_STATE_START, &st->info,
3266 _event_consume(sd, event_info, event_type, ev_flag);
3269 return; /* Zoom started */
3270 } /* End of ZOOM_START handling */
3272 /* if we got here, we have (exacally) two fingers on surfce */
3273 /* we also after START, report MOVE */
3274 /* First detect which finger moved */
3275 if (pe->device == st->zoom_mv.device)
3276 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3277 else if (pe->device == st->zoom_mv1.device)
3278 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
3280 /* Compute change in zoom as fingers move */
3281 st->info.zoom = _zoom_compute(st,
3282 st->zoom_mv.x, st->zoom_mv.y,
3283 st->zoom_mv1.x, st->zoom_mv1.y,
3284 sd->zoom_finger_factor);
3286 if (!st->zoom_distance_tolerance) /* Zoom broke tolerance,
3289 double d = st->info.zoom - st->next_step;
3293 if (d >= sd->zoom_step) /* Report move in steps */
3295 st->next_step = st->info.zoom;
3297 ev_flag = _state_set(gesture_zoom,
3298 ELM_GESTURE_STATE_MOVE,
3299 &st->info, EINA_TRUE);
3300 _event_consume(sd, event_info, event_type, ev_flag);
3302 } /* End of ZOOM_MOVE handling */
3307 case EVAS_CALLBACK_MOUSE_UP:
3308 case EVAS_CALLBACK_MULTI_UP:
3309 /* Reset timestamp of finger-up.This is used later
3310 by _zoom_test_reset() to retain finger-down data */
3311 _event_consume(sd, event_info, event_type, ev_flag);
3312 if (((st->zoom_wheel) || (st->zoom_base)) &&
3313 (st->zoom_distance_tolerance == 0))
3315 ev_flag = _state_set(gesture_zoom, ELM_GESTURE_STATE_END,
3316 &st->info, EINA_FALSE);
3317 _event_consume(sd, event_info, event_type, ev_flag);
3322 /* if we got here not a ZOOM */
3323 /* Must be != undefined, if gesture started */
3324 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
3326 ev_flag = _state_set
3327 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3329 _event_consume(sd, event_info, event_type, ev_flag);
3332 _zoom_test_reset(gesture_zoom);
3342 _rotate_properties_get(Rotate_Type *st,
3349 /* FIXME: Fix momentum computation, it's wrong */
3350 double prev_angle = *angle;
3352 st->info.radius = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3353 &st->info.x, &st->info.y) / 2;
3355 *angle = _angle_get(xx1, yy1, xx2, yy2);
3357 if (angle == &st->info.angle) /* Fingers are moving, compute momentum */
3359 unsigned int tm_start =
3360 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3361 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
3362 unsigned int tm_end =
3363 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3364 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3366 unsigned int tm_total = tm_end - tm_start;
3367 if (tm_total) /* Momentum computed as:
3368 accumulated roation angle (deg) divided by time */
3371 if (((prev_angle < 90) && ((*angle) > 270)) ||
3372 /* We circle passing ZERO point */
3373 ((prev_angle > 270) && ((*angle) < 90)))
3375 prev_angle = (*angle);
3377 else m = prev_angle - (*angle);
3379 st->accum_momentum += m;
3381 if ((tm_end - st->prev_momentum_tm) < 100)
3382 st->prev_momentum += m;
3385 if (fabs(st->prev_momentum) < 0.002)
3386 st->accum_momentum = 0.0; /* reset momentum */
3388 st->prev_momentum = 0.0; /* Start again */
3391 st->prev_momentum_tm = tm_end;
3392 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3396 st->info.momentum = 0;
3402 * This function is used to test rotation gesture.
3403 * user may combine zoom, rotation together.
3404 * so its possible that both will be detected from input.
3405 * (both are two-finger movement-oriented gestures)
3407 * @param obj The gesture-layer object.
3408 * @param event_info Pointer to recent input event.
3409 * @param event_type Recent input event type.
3410 * @param g_type what Gesture we are testing.
3412 * @ingroup Elm_Gesture_Layer
3415 _rotate_test(Evas_Object *obj,
3418 Evas_Callback_Type event_type,
3419 Elm_Gesture_Type g_type)
3421 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3422 Gesture_Info *gesture;
3423 Rotate_Type *st = NULL;
3425 if (!_elm_config->glayer_rotate_finger_enable)
3431 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3433 if (!sd->gesture[g_type]) return;
3435 gesture = sd->gesture[g_type];
3436 if (!gesture) return ;
3439 if (!st) /* Allocated once on first time */
3441 st = calloc(1, sizeof(Rotate_Type));
3443 _rotate_test_reset(gesture);
3448 case EVAS_CALLBACK_MOUSE_MOVE:
3449 case EVAS_CALLBACK_MULTI_MOVE:
3450 /* if non-continues mode and gesture NOT started, ignore MOVE */
3451 if ((!sd->glayer_continues_enable) &&
3452 (!st->rotate_st.timestamp))
3455 case EVAS_CALLBACK_MOUSE_DOWN:
3456 case EVAS_CALLBACK_MULTI_DOWN:
3457 { /* Here we take care of rotate-start and rotate move */
3461 if (eina_list_count(sd->touched) > 2) /* Process rotate only
3465 ev_flag = _state_set
3466 (gesture, ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3467 _event_consume(sd, event_info, event_type, ev_flag);
3472 if (!st->rotate_st.timestamp) /* Now scan touched-devices list
3473 * and find other finger */
3475 EINA_LIST_FOREACH(sd->touched, l, p)
3476 { /* Device of other finger <> pe device */
3477 if (p->device != pe->device)
3482 return; /* Single finger on touch */
3484 /* Record down fingers */
3485 _event_consume(sd, event_info, event_type, ev_flag);
3486 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3487 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3489 /* Set mv field as well to be ready for MOVE events */
3490 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3491 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3493 /* Here we have rotate_st, rotate_st1 set, report START */
3494 /* Set rotate-base after BOTH down events recorded */
3495 /* Compute length of line between fingers rotate start */
3496 _rotate_properties_get(st,
3497 st->rotate_st.x, st->rotate_st.y,
3498 st->rotate_st1.x, st->rotate_st1.y,
3499 &st->info.base_angle);
3501 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
3502 &st->info, EINA_FALSE);
3503 _event_consume(sd, event_info, event_type, ev_flag);
3505 return; /* Rotate started */
3506 } /* End of ROTATE_START handling */
3508 /* if we got here, we have (exacally) two fingers on surfce */
3509 /* we also after START, report MOVE */
3510 /* First detect which finger moved */
3511 if (pe->device == st->rotate_mv.device)
3512 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3513 else if (pe->device == st->rotate_mv1.device)
3514 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3516 /* Compute change in rotate as fingers move */
3517 _rotate_properties_get(st,
3518 st->rotate_mv.x, st->rotate_mv.y,
3519 st->rotate_mv1.x, st->rotate_mv1.y,
3522 if (_on_rotation_broke_tolerance(st)) /* Rotation broke
3526 double d = st->info.angle - st->next_step;
3530 if (d >= sd->rotate_step) /* Report move in steps */
3532 st->next_step = st->info.angle;
3534 ev_flag = _state_set
3535 (gesture, ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3536 _event_consume(sd, event_info, event_type, ev_flag);
3538 } /* End of ROTATE_MOVE handling */
3543 case EVAS_CALLBACK_MOUSE_UP:
3544 case EVAS_CALLBACK_MULTI_UP:
3545 _event_consume(sd, event_info, event_type, ev_flag);
3546 /* Reset timestamp of finger-up.This is used later
3547 by rotate_test_reset() to retain finger-down data */
3548 if (st->rotate_angular_tolerance < 0)
3550 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
3551 &st->info, EINA_FALSE);
3552 _event_consume(sd, event_info, event_type, ev_flag);
3557 /* Must be != undefined, if gesture started */
3558 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3560 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
3561 &st->info, EINA_FALSE);
3562 _event_consume(sd, event_info, event_type, ev_flag);
3565 _rotate_test_reset(gesture);
3574 _elm_gesture_layer_smart_disable(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
3576 Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3577 if (elm_widget_disabled_get(obj))
3578 _callbacks_unregister(obj);
3580 _callbacks_register(obj);
3582 if (ret) *ret = EINA_TRUE;
3586 _elm_gesture_layer_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
3588 eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
3590 Elm_Gesture_Layer_Smart_Data *priv = _pd;
3592 priv->line_min_length =
3593 _elm_config->glayer_line_min_length * elm_config_finger_size_get();
3594 priv->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance
3595 * elm_config_finger_size_get();
3596 priv->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance
3597 * elm_config_finger_size_get();
3598 priv->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3599 /* mouse wheel zoom steps */
3600 priv->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor;
3601 priv->rotate_angular_tolerance =
3602 _elm_config->glayer_rotate_angular_tolerance;
3603 priv->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3604 priv->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3605 priv->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3606 priv->repeat_events = EINA_TRUE;
3607 priv->glayer_continues_enable = _elm_config->glayer_continues_enable;
3609 /* FIXME: Hack to get around old configs - if too small, enlarge. */
3610 if (_elm_config->glayer_double_tap_timeout < 0.00001)
3611 _elm_config->glayer_double_tap_timeout = 0.25;
3612 priv->double_tap_timeout = _elm_config->glayer_double_tap_timeout;
3614 memset(priv->gesture, 0, sizeof(priv->gesture));
3618 _elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
3620 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3621 Pointer_Event *data;
3624 _event_history_clear(obj);
3625 sd->pending = eina_list_free(sd->pending);
3627 EINA_LIST_FREE(sd->touched, data)
3630 if (!elm_widget_disabled_get(obj))
3631 _callbacks_unregister(obj);
3633 /* Free all gestures internal data structures */
3634 for (i = 0; i < ELM_GESTURE_LAST; i++)
3637 if (sd->gesture[i]->data)
3638 free(sd->gesture[i]->data);
3640 free(sd->gesture[i]);
3642 if (sd->gest_taps_timeout) ecore_timer_del(sd->gest_taps_timeout);
3644 eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
3648 elm_gesture_layer_add(Evas_Object *parent)
3650 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3651 Evas_Object *obj = eo_add(MY_CLASS, parent);
3657 _constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
3659 eo_do_super(obj, MY_CLASS, eo_constructor());
3660 eo_do(obj, evas_obj_type_set(MY_CLASS_NAME));
3662 elm_widget_sub_object_add(eo_parent_get(obj), obj);
3666 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3668 ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3669 Eina_Bool ret = EINA_FALSE;
3670 eo_do((Eo *) obj, elm_obj_gesture_layer_hold_events_get(&ret));
3675 _hold_events_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3677 Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3678 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3679 *ret = !sd->repeat_events;
3683 elm_gesture_layer_hold_events_set(Evas_Object *obj,
3684 Eina_Bool hold_events)
3686 ELM_GESTURE_LAYER_CHECK(obj);
3687 eo_do(obj, elm_obj_gesture_layer_hold_events_set(hold_events));
3691 _hold_events_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3693 Eina_Bool hold_events = va_arg(*list, int);
3694 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3696 sd->repeat_events = !(!!hold_events);
3700 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3702 ELM_GESTURE_LAYER_CHECK(obj) 0;
3704 eo_do((Eo *) obj, elm_obj_gesture_layer_zoom_step_get(&ret));
3709 _zoom_step_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3711 double *ret = va_arg(*list, double *);
3712 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3713 *ret = sd->zoom_step;
3717 elm_gesture_layer_zoom_step_set(Evas_Object *obj,
3720 ELM_GESTURE_LAYER_CHECK(obj);
3721 eo_do(obj, elm_obj_gesture_layer_zoom_step_set(step));
3725 _zoom_step_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3727 double step = va_arg(*list, double);
3728 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3730 if (step < 0) return;
3732 sd->zoom_step = step;
3736 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3738 ELM_GESTURE_LAYER_CHECK(obj) 0;
3740 eo_do((Eo *) obj, elm_obj_gesture_layer_rotate_step_get(&ret));
3745 _rotate_step_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3747 double *ret = va_arg(*list, double *);
3748 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3749 *ret = sd->rotate_step;
3753 elm_gesture_layer_rotate_step_set(Evas_Object *obj,
3756 ELM_GESTURE_LAYER_CHECK(obj);
3757 eo_do(obj, elm_obj_gesture_layer_rotate_step_set(step));
3761 _rotate_step_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
3763 double step = va_arg(*list, double);
3764 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3766 if (step < 0) return;
3768 sd->rotate_step = step;
3772 elm_gesture_layer_attach(Evas_Object *obj,
3773 Evas_Object *target)
3775 ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3776 Eina_Bool ret = EINA_FALSE;
3777 eo_do(obj, elm_obj_gesture_layer_attach(target, &ret));
3782 _attach(Eo *obj, void *_pd, va_list *list)
3784 Evas_Object *target = va_arg(*list, Evas_Object *);
3785 Eina_Bool *ret = va_arg(*list, Eina_Bool *);
3786 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3787 if (ret) *ret = EINA_FALSE;
3789 if (!target) return;
3791 /* if was attached before, unregister callbacks first */
3793 _callbacks_unregister(obj);
3795 sd->target = target;
3797 _callbacks_register(obj);
3798 if (ret) *ret = EINA_TRUE;
3802 elm_gesture_layer_cb_set(Evas_Object *obj,
3803 Elm_Gesture_Type idx,
3804 Elm_Gesture_State cb_type,
3805 Elm_Gesture_Event_Cb cb,
3808 ELM_GESTURE_LAYER_CHECK(obj);
3809 eo_do(obj, elm_obj_gesture_layer_cb_set(idx, cb_type, cb, data));
3813 _cb_set(Eo *obj, void *_pd, va_list *list)
3815 Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
3816 Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
3817 Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
3818 void *data = va_arg(*list, void *);
3821 Elm_Gesture_Layer_Smart_Data *sd = _pd;
3823 if (!sd->gesture[idx])
3824 sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3825 if (!sd->gesture[idx]) return;
3827 p = sd->gesture[idx];
3830 p->fn[cb_type].cb = cb;
3831 p->fn[cb_type].user_data = data;
3832 p->state = ELM_GESTURE_STATE_UNDEFINED;
3837 elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length)
3839 ELM_GESTURE_LAYER_CHECK(obj);
3840 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3841 sd->line_min_length = line_min_length;
3846 elm_gesture_layer_line_min_length_get(const Evas_Object *obj)
3848 ELM_GESTURE_LAYER_CHECK(obj) 0;
3849 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3850 return sd->line_min_length;
3854 elm_gesture_layer_zoom_distance_tolerance_set(Evas_Object *obj, Evas_Coord zoom_distance_tolerance)
3856 ELM_GESTURE_LAYER_CHECK(obj);
3857 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3858 sd->zoom_distance_tolerance = zoom_distance_tolerance;
3862 elm_gesture_layer_zoom_distance_tolerance_get(const Evas_Object *obj)
3864 ELM_GESTURE_LAYER_CHECK(obj) 0;
3865 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3866 return sd->zoom_distance_tolerance;
3870 elm_gesture_layer_line_distance_tolerance_set(Evas_Object *obj, Evas_Coord line_distance_tolerance)
3872 ELM_GESTURE_LAYER_CHECK(obj);
3873 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3874 sd->line_distance_tolerance = line_distance_tolerance;
3878 elm_gesture_layer_line_distance_tolerance_get(const Evas_Object *obj)
3880 ELM_GESTURE_LAYER_CHECK(obj) 0;
3881 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3882 return sd->line_distance_tolerance;
3886 elm_gesture_layer_line_angular_tolerance_set(Evas_Object *obj, double line_angular_tolerance)
3888 ELM_GESTURE_LAYER_CHECK(obj);
3889 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3890 sd->line_angular_tolerance = line_angular_tolerance;
3894 elm_gesture_layer_line_angular_tolerance_get(const Evas_Object *obj)
3896 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3897 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3898 return sd->line_angular_tolerance;
3902 elm_gesture_layer_zoom_wheel_factor_set(Evas_Object *obj, double zoom_wheel_factor)
3904 ELM_GESTURE_LAYER_CHECK(obj);
3905 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3906 sd->zoom_wheel_factor = zoom_wheel_factor;
3910 elm_gesture_layer_zoom_wheel_factor_get(const Evas_Object *obj)
3912 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3913 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3914 return sd->zoom_wheel_factor;
3918 elm_gesture_layer_zoom_finger_factor_set(Evas_Object *obj, double zoom_finger_factor)
3920 ELM_GESTURE_LAYER_CHECK(obj);
3921 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3922 sd->zoom_finger_factor = zoom_finger_factor;
3926 elm_gesture_layer_zoom_finger_factor_get(const Evas_Object *obj)
3928 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3929 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3930 return sd->zoom_finger_factor;
3934 elm_gesture_layer_rotate_angular_tolerance_set(Evas_Object *obj, double rotate_angular_tolerance)
3936 ELM_GESTURE_LAYER_CHECK(obj);
3937 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3938 sd->rotate_angular_tolerance = rotate_angular_tolerance;
3942 elm_gesture_layer_rotate_angular_tolerance_get(const Evas_Object *obj)
3944 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3945 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3946 return sd->rotate_angular_tolerance;
3950 elm_gesture_layer_flick_time_limit_ms_set(Evas_Object *obj, unsigned int flick_time_limit_ms)
3952 ELM_GESTURE_LAYER_CHECK(obj);
3953 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3954 sd->flick_time_limit_ms = flick_time_limit_ms;
3958 elm_gesture_layer_flick_time_limit_ms_get(const Evas_Object *obj)
3960 ELM_GESTURE_LAYER_CHECK(obj) 0;
3961 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3962 return sd->flick_time_limit_ms;
3966 elm_gesture_layer_long_tap_start_timeout_set(Evas_Object *obj, double long_tap_start_timeout)
3968 ELM_GESTURE_LAYER_CHECK(obj);
3969 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3970 sd->long_tap_start_timeout = long_tap_start_timeout;
3974 elm_gesture_layer_long_tap_start_timeout_get(const Evas_Object *obj)
3976 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3977 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3978 return sd->long_tap_start_timeout;
3982 elm_gesture_layer_continues_enable_set(Evas_Object *obj, Eina_Bool continues_enable)
3984 ELM_GESTURE_LAYER_CHECK(obj);
3985 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3986 sd->glayer_continues_enable = continues_enable;
3990 elm_gesture_layer_continues_enable_get(const Evas_Object *obj)
3992 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3993 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3994 return sd->glayer_continues_enable;
3998 elm_gesture_layer_double_tap_timeout_set(Evas_Object *obj, double double_tap_timeout)
4000 ELM_GESTURE_LAYER_CHECK(obj);
4001 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4002 sd->double_tap_timeout = double_tap_timeout;
4006 elm_gesture_layer_double_tap_timeout_get(const Evas_Object *obj)
4008 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4009 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4010 return sd->double_tap_timeout;
4014 _class_constructor(Eo_Class *klass)
4016 const Eo_Op_Func_Description func_desc[] = {
4017 EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
4019 EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_ADD), _elm_gesture_layer_smart_add),
4020 EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_DEL), _elm_gesture_layer_smart_del),
4022 EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DISABLE), _elm_gesture_layer_smart_disable),
4024 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_GET), _hold_events_get),
4025 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_SET), _hold_events_set),
4026 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_GET), _zoom_step_get),
4027 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_SET), _zoom_step_set),
4028 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_GET), _rotate_step_get),
4029 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_SET), _rotate_step_set),
4030 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_ATTACH), _attach),
4031 EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), _cb_set),
4034 eo_class_funcs_set(klass, func_desc);
4036 evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
4039 static const Eo_Op_Description op_desc[] = {
4040 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_GET, "Call this function to get repeat-events settings."),
4041 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_HOLD_EVENTS_SET, "This function is to make gesture-layer repeat events."),
4042 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_GET, "This function returns step-value for zoom action."),
4043 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ZOOM_STEP_SET, "This function sets step-value for zoom action."),
4044 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_GET, "This function returns step-value for rotate action."),
4045 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ROTATE_STEP_SET, "This function sets step-value for rotate action."),
4046 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_ATTACH, "Attach a given gesture layer widget to an Evas object, thus setting the widget's target."),
4047 EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET, "Use function to set callbacks to be notified about change of state of gesture."),
4048 EO_OP_DESCRIPTION_SENTINEL
4051 static const Eo_Class_Description class_desc = {
4054 EO_CLASS_TYPE_REGULAR,
4055 EO_CLASS_DESCRIPTION_OPS(&ELM_OBJ_GESTURE_LAYER_BASE_ID, op_desc, ELM_OBJ_GESTURE_LAYER_SUB_ID_LAST),
4057 sizeof(Elm_Gesture_Layer_Smart_Data),
4062 EO_DEFINE_CLASS(elm_obj_gesture_layer_class_get, &class_desc, ELM_OBJ_WIDGET_CLASS, NULL);