1 #include <Elementary.h>
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
10 #define ELM_GESTURE_MULTI_TIMEOUT 50
11 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
13 /* Some Trigo values */
14 #define RAD_90DEG M_PI_2
15 #define RAD_180DEG M_PI
16 #define RAD_270DEG (M_PI_2 * 3)
17 #define RAD_360DEG (M_PI * 2)
18 /* #define DEBUG_GESTURE_LAYER 1 */
20 #define RAD2DEG(x) ((x) * 57.295779513)
21 #define DEG2RAD(x) ((x) / 57.295779513)
24 _glayer_bufdup(void *buf, size_t size)
31 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
34 #define SET_TEST_BIT(P) do { \
35 P->test = P->fn[ELM_GESTURE_STATE_START].cb || P->fn[ELM_GESTURE_STATE_MOVE].cb || P->fn[ELM_GESTURE_STATE_END].cb || P->fn[ELM_GESTURE_STATE_ABORT].cb; \
38 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
44 * Struct holds callback information.
46 * @ingroup Elm_Gesture_Layer
50 void *user_data; /**< Holds user data to CB (like sd) */
51 Elm_Gesture_Event_Cb cb;
58 * type for callback information
60 * @ingroup Elm_Gesture_Layer
62 typedef struct _Func_Data Func_Data;
67 * @struct _Gesture_Info
68 * Struct holds gesture info
70 * @ingroup Elm_Gesture_Layer
75 void *data; /**< Holds gesture intemidiate processing data */
76 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
77 Elm_Gesture_Types g_type; /**< gesture type */
78 Elm_Gesture_State state; /**< gesture state */
79 void *info; /**< Data for the state callback */
80 Eina_Bool test; /**< if true this gesture should be tested on input */
86 * @typedef Gesture_Info
87 * Type for _Gesture_Info
89 * @ingroup Elm_Gesture_Layer
91 typedef struct _Gesture_Info Gesture_Info;
96 * @struct _Event_History
97 * Struct holds event history.
98 * These events are repeated if no gesture found.
100 * @ingroup Elm_Gesture_Layer
102 struct _Event_History
106 Evas_Callback_Type event_type;
112 * @typedef Event_History
113 * Type for _Event_History
115 * @ingroup Elm_Gesture_Layer
117 typedef struct _Event_History Event_History;
122 * @struct _Pointer_Event
123 * Struct holds pointer-event info
124 * This is a generic pointer event structure
126 * @ingroup Elm_Gesture_Layer
128 struct _Pointer_Event
131 unsigned int timestamp;
133 Evas_Callback_Type event_type;
139 * @typedef Pointer_Event
140 * Type for generic pointer event structure
142 * @ingroup Elm_Gesture_Layer
144 typedef struct _Pointer_Event Pointer_Event;
146 /* All *Type structs hold result for the user in 'info' field
147 * The rest is gesture processing intermediate data.
148 * NOTE: info field must be FIRST in the struct.
149 * This is used when reporting ABORT in event_history_clear() */
152 Elm_Gesture_Taps_Info info;
155 unsigned int n_taps_needed;
159 typedef struct _Taps_Type Taps_Type;
161 struct _Long_Tap_Type
163 Elm_Gesture_Taps_Info info;
166 unsigned int max_touched;
167 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
170 typedef struct _Long_Tap_Type Long_Tap_Type;
172 struct _Momentum_Type
173 { /* Fields used by _line_test() */
174 Elm_Gesture_Momentum_Info info;
175 Evas_Coord_Point line_st;
176 Evas_Coord_Point line_end;
177 unsigned int t_st_x; /* Time start on X */
178 unsigned int t_st_y; /* Time start on Y */
179 unsigned int t_end; /* Time end */
180 unsigned int t_up; /* Recent up event time */
183 typedef struct _Momentum_Type Momentum_Type;
187 Evas_Coord_Point line_st;
188 Evas_Coord_Point line_end;
189 Evas_Coord line_length;
190 unsigned int t_st; /* Time start */
191 unsigned int t_end; /* Time end */
193 double line_angle; /* Current angle of line */
195 typedef struct _Line_Data Line_Data;
198 { /* Fields used by _line_test() */
199 Elm_Gesture_Line_Info info;
200 Eina_List *list; /* List of Line_Data */
202 typedef struct _Line_Type Line_Type;
205 { /* Fields used by _zoom_test() */
206 Elm_Gesture_Zoom_Info info;
207 Pointer_Event zoom_st;
208 Pointer_Event zoom_mv;
209 Pointer_Event zoom_st1;
210 Pointer_Event zoom_mv1;
211 Evas_Event_Mouse_Wheel *zoom_wheel;
212 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
213 Evas_Coord zoom_distance_tolerance;
214 unsigned int m_st_tm; /* momentum start time */
215 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
216 double m_base; /* zoom value when momentum starts */
219 typedef struct _Zoom_Type Zoom_Type;
222 { /* Fields used by _rotation_test() */
223 Elm_Gesture_Rotate_Info info;
224 Pointer_Event rotate_st;
225 Pointer_Event rotate_mv;
226 Pointer_Event rotate_st1;
227 Pointer_Event rotate_mv1;
228 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
229 double prev_momentum; /* Snapshot of momentum 0.01 sec ago */
230 double accum_momentum;
231 double rotate_angular_tolerance;
234 typedef struct _Rotate_Type Rotate_Type;
238 Evas_Object *target; /* Target Widget */
239 Event_History *event_history_list;
242 Evas_Coord zoom_distance_tolerance;
243 Evas_Coord line_distance_tolerance;
244 double line_angular_tolerance;
245 double zoom_wheel_factor; /* mouse wheel zoom steps */
246 double zoom_finger_factor; /* used for zoom factor */
247 double rotate_angular_tolerance;
248 unsigned int flick_time_limit_ms;
249 double long_tap_start_timeout;
250 Eina_Bool glayer_continues_enable;
255 Gesture_Info *gesture[ELM_GESTURE_LAST];
256 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
257 Eina_List *pending; /* List of devices need to refeed *UP event */
258 Eina_List *touched; /* Information of touched devices */
260 Eina_Bool repeat_events : 1;
262 typedef struct _Widget_Data Widget_Data;
264 static const char *widtype = NULL;
265 static void _del_hook(Evas_Object *obj);
267 static Eina_Bool _event_history_clear(Evas_Object *obj);
268 static void _reset_states(Widget_Data *wd);
269 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
270 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
271 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
272 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
273 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
274 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
275 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
277 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
278 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
279 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
281 /* START - Functions to manage touched-device list */
284 * This function is used to find if device is touched
286 * @ingroup Elm_Gesture_Layer
289 compare_device(const void *data1, const void *data2)
290 { /* Compare the two device numbers */
291 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
297 * Remove Pointer Event from touched device list
298 * @param list Pointer to touched device list.
299 * @param Pointer_Event Pointer to PE.
301 * @ingroup Elm_Gesture_Layer
304 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
306 Eina_List *lst = NULL;
307 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
310 lst = eina_list_remove(list, p);
321 * Recoed Pointer Event in touched device list
322 * Note: This fuction allocates memory for PE event
323 * This memory is released in _remove_touched_device()
324 * @param list Pointer to touched device list.
325 * @param Pointer_Event Pointer to PE.
327 * @ingroup Elm_Gesture_Layer
330 _add_touched_device(Eina_List *list, Pointer_Event *pe)
332 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
334 { /* We like to track device touch-position, overwrite info */
335 memcpy(p, pe, sizeof(Pointer_Event));
339 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
340 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN))
341 { /* Add touched device on DOWN event only */
342 p = malloc(sizeof(Pointer_Event));
343 /* Freed in _remove_touched_device() */
344 memcpy(p, pe, sizeof(Pointer_Event));
345 return eina_list_append(list, p);
350 /* END - Functions to manage touched-device list */
356 * @param event_info pointer to event.
358 * @ingroup Elm_Gesture_Layer
360 static Evas_Event_Flags
361 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
365 case EVAS_CALLBACK_MOUSE_IN:
366 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
367 case EVAS_CALLBACK_MOUSE_OUT:
368 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
369 case EVAS_CALLBACK_MOUSE_DOWN:
370 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
371 case EVAS_CALLBACK_MOUSE_MOVE:
372 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
373 case EVAS_CALLBACK_MOUSE_UP:
374 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
375 case EVAS_CALLBACK_MOUSE_WHEEL:
376 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
377 case EVAS_CALLBACK_MULTI_DOWN:
378 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
379 case EVAS_CALLBACK_MULTI_MOVE:
380 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
381 case EVAS_CALLBACK_MULTI_UP:
382 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
383 case EVAS_CALLBACK_KEY_DOWN:
384 return ((Evas_Event_Key_Down *) event_info)->event_flags;
385 case EVAS_CALLBACK_KEY_UP:
386 return ((Evas_Event_Key_Up *) event_info)->event_flags;
388 return EVAS_EVENT_FLAG_NONE;
395 * Sets event flag to value returned from user callback
396 * @param wd Widget Data
397 * @param event_info pointer to event.
398 * @param event_type what type was ev (mouse down, etc...)
399 * @param ev_flags event flags
401 * @ingroup Elm_Gesture_Layer
404 consume_event(Widget_Data *wd, void *event_info,
405 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
406 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
407 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
408 /* should not refeed this event. */
410 return; /* This happens when restarting gestures */
412 if ((ev_flags) || (!wd->repeat_events))
416 case EVAS_CALLBACK_MOUSE_DOWN:
417 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
419 case EVAS_CALLBACK_MOUSE_MOVE:
420 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
422 case EVAS_CALLBACK_MOUSE_UP:
423 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
425 case EVAS_CALLBACK_MOUSE_WHEEL:
426 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
428 case EVAS_CALLBACK_MULTI_DOWN:
429 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
431 case EVAS_CALLBACK_MULTI_MOVE:
432 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
434 case EVAS_CALLBACK_MULTI_UP:
435 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
437 case EVAS_CALLBACK_KEY_DOWN:
438 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
440 case EVAS_CALLBACK_KEY_UP:
441 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
452 * Report current state of a gesture by calling user callback.
453 * @param gesture what gesture state we report.
454 * @param info inforamtion for user callback
456 * @ingroup Elm_Gesture_Layer
458 static Evas_Event_Flags
459 _report_state(Gesture_Info *gesture, void *info)
460 { /* We report current state (START, MOVE, END, ABORT), once */
461 #if defined(DEBUG_GESTURE_LAYER)
462 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
465 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
466 (gesture->fn[gesture->state].cb))
467 { /* Fill state-info struct and send ptr to user callback */
468 return gesture->fn[gesture->state].cb(
469 gesture->fn[gesture->state].user_data, info);
472 return EVAS_EVENT_FLAG_NONE;
478 * Update state for a given gesture.
479 * We may update gesture state to:
480 * UNDEFINED - current input did not start gesure yet.
481 * START - gesture started according to input.
482 * MOVE - gusture in progress.
483 * END - gesture completed according to input.
484 * ABORT - input does not matches gesure.
485 * note that we may move from UNDEFINED to ABORT
486 * because we may detect that gesture will not START
487 * with a given input.
489 * @param g given gesture to change state.
490 * @param s gesure new state.
491 * @param info buffer to be sent to user callback on report_state.
492 * @param force makes report_state to report the new-state even
493 * if its same as current state. Works for MOVE - gesture in progress.
495 * @ingroup Elm_Gesture_Layer
497 static Evas_Event_Flags
498 _set_state(Gesture_Info *g, Elm_Gesture_State s,
499 void *info, Eina_Bool force)
501 Elm_Gesture_State old_state;
502 if ((g->state == s) && (!force))
503 return EVAS_EVENT_FLAG_NONE;
505 old_state = g->state;
508 g->info = info; /* Information for user callback */
509 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
510 (g->state == ELM_GESTURE_STATE_END))
511 g->test = EINA_FALSE;
513 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
514 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
515 (s == ELM_GESTURE_STATE_ABORT))))
516 return _report_state(g, g->info);
518 return EVAS_EVENT_FLAG_NONE;
524 * This resets all gesture states and sets test-bit.
525 * this is used for restarting gestures to listen to input.
526 * happens after we complete a gesture or no gesture was detected.
527 * @param wd Widget data of the gesture-layer object.
529 * @ingroup Elm_Gesture_Layer
532 _reset_states(Widget_Data *wd)
536 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
541 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
550 * if gesture was NOT detected AND we only have gestures in ABORT state
551 * we clear history immediately to be ready for input.
553 * @param obj The gesture-layer object.
554 * @return TRUE on event history_clear
556 * @ingroup Elm_Gesture_Layer
559 _clear_if_finished(Evas_Object *obj)
561 Widget_Data *wd = elm_widget_data_get(obj);
562 if (!wd) return EINA_FALSE;
565 /* Clear history if all we have aborted gestures */
566 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
567 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
568 { /* If no gesture started and all we have aborted gestures, reset all */
569 Gesture_Info *p = wd->gesture[i];
570 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
572 if ((p->state == ELM_GESTURE_STATE_START) ||
573 (p->state == ELM_GESTURE_STATE_MOVE))
574 reset_s = EINA_FALSE;
576 all_undefined = EINA_FALSE;
580 if (reset_s && (!all_undefined))
581 return _event_history_clear(obj);
587 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
589 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
605 /* All *test_reset() funcs are called to clear
606 * gesture intermediate data.
607 * This happens when we need to reset our tests.
608 * for example when gesture is detected or all ABORTed. */
610 _tap_gestures_test_reset(Gesture_Info *gesture)
615 Widget_Data *wd = elm_widget_data_get(gesture->obj);
616 wd->dbl_timeout = NULL;
623 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
624 EINA_LIST_FREE(data, pe)
627 memset(gesture->data, 0, sizeof(Taps_Type));
630 /* All *test_reset() funcs are called to clear
631 * gesture intermediate data.
632 * This happens when we need to reset our tests.
633 * for example when gesture is detected or all ABORTed. */
635 _n_long_tap_test_reset(Gesture_Info *gesture)
643 Long_Tap_Type *st = gesture->data;
646 EINA_LIST_FOREACH(st->touched, l, p)
649 eina_list_free(st->touched);
650 if (st->timeout) ecore_timer_del(st->timeout);
651 memset(gesture->data, 0, sizeof(Long_Tap_Type));
655 _momentum_test_reset(Gesture_Info *gesture)
663 memset(gesture->data, 0, sizeof(Momentum_Type));
667 _line_data_reset(Line_Data *st)
672 memset(st, 0, sizeof(Line_Data));
673 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
677 _line_test_reset(Gesture_Info *gesture)
685 Line_Type *st = gesture->data;
686 Eina_List *list = st->list;
689 EINA_LIST_FOREACH(list, l, t_line)
692 eina_list_free(list);
697 _zoom_test_reset(Gesture_Info *gesture)
705 Widget_Data *wd = elm_widget_data_get(gesture->obj);
706 Zoom_Type *st = gesture->data;
707 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
708 evas_object_evas_get(wd->target), "Control");
709 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
710 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
712 memset(st, 0, sizeof(Zoom_Type));
713 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
718 _rotate_test_reset(Gesture_Info *gesture)
726 Widget_Data *wd = elm_widget_data_get(gesture->obj);
727 Rotate_Type *st = gesture->data;
729 memset(st, 0, sizeof(Rotate_Type));
730 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
731 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
738 * We register callbacks when gesture layer is attached to an object
739 * or when its enabled after disable.
741 * @param obj The gesture-layer object.
743 * @ingroup Elm_Gesture_Layer
746 _register_callbacks(Evas_Object *obj)
748 Widget_Data *wd = elm_widget_data_get(obj);
753 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
755 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
757 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
760 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
763 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
765 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
767 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
770 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
772 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
780 * We unregister callbacks when gesture layer is disabled.
782 * @param obj The gesture-layer object.
784 * @ingroup Elm_Gesture_Layer
787 _unregister_callbacks(Evas_Object *obj)
789 Widget_Data *wd = elm_widget_data_get(obj);
794 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
796 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
798 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
801 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
804 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
807 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
810 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
813 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
815 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
820 /* START - Event history list handling functions */
823 * This function is used to find if device number
824 * is found in a list of devices.
825 * The list contains devices for refeeding *UP event
827 * @ingroup Elm_Gesture_Layer
830 device_in_pending_list(const void *data1, const void *data2)
831 { /* Compare the two device numbers */
832 return (((intptr_t) data1) - ((intptr_t) data2));
838 * This functions adds device to refeed-pending device list
839 * @ingroup Elm_Gesture_Layer
842 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
844 int device = ELM_MOUSE_DEVICE;
847 case EVAS_CALLBACK_MOUSE_DOWN:
849 case EVAS_CALLBACK_MULTI_DOWN:
850 device = ((Evas_Event_Multi_Down *) event)->device;
856 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
859 return eina_list_append(list, (intptr_t*) device);
868 * This functions returns pending-device node
869 * @ingroup Elm_Gesture_Layer
872 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
874 int device = ELM_MOUSE_DEVICE;
877 case EVAS_CALLBACK_MOUSE_UP:
879 case EVAS_CALLBACK_MULTI_UP:
880 device = ((Evas_Event_Multi_Up *) event)->device;
886 return eina_list_search_unsorted_list(list, device_in_pending_list,
887 (intptr_t *) device);
893 * This function reports ABORT to all none-detected gestures
894 * Then resets test bits for all desired gesures
895 * and clears input-events history.
896 * note: if no gesture was detected, events from history list
897 * are streamed to the widget because it's unused by layer.
898 * user may cancel refeed of events by setting repeat events.
900 * @param obj The gesture-layer object.
902 * @ingroup Elm_Gesture_Layer
905 _event_history_clear(Evas_Object *obj)
907 Widget_Data *wd = elm_widget_data_get(obj);
908 if (!wd) return EINA_FALSE;
912 Evas *e = evas_object_evas_get(obj);
913 Eina_Bool gesture_found = EINA_FALSE;
914 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
919 if (p->state == ELM_GESTURE_STATE_END)
920 gesture_found = EINA_TRUE;
922 { /* Report ABORT to all gestures that still not finished */
923 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
929 _reset_states(wd); /* we are ready to start testing for gestures again */
931 /* Clear all gestures intermediate data */
932 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
933 { /* We do not clear a long-tap gesture if fingers still on surface */
934 /* and gesture timer still pending to test gesture state */
935 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
936 if ((st) && /* st not allocated if clear occurs before 1st input */
937 ((!eina_list_count(st->touched)) || (!st->timeout)))
938 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
943 ecore_timer_del(wd->dbl_timeout);
944 wd->dbl_timeout = NULL;
947 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
948 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
949 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
950 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
951 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
952 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
953 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
954 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
956 /* Disable gesture layer so refeeded events won't be consumed by it */
957 _unregister_callbacks(obj);
958 while (wd->event_history_list)
961 t = wd->event_history_list;
962 Eina_List *pending = _device_is_pending(wd->pending,
963 wd->event_history_list->event,
964 wd->event_history_list->event_type);
966 /* Refeed events if no gesture matched input */
967 if (pending || ((!gesture_found) && (!wd->repeat_events)))
969 evas_event_refeed_event(e, wd->event_history_list->event,
970 wd->event_history_list->event_type);
974 wd->pending = eina_list_remove_list(wd->pending, pending);
978 wd->pending = _add_device_pending(wd->pending,
979 wd->event_history_list->event,
980 wd->event_history_list->event_type);
984 free(wd->event_history_list->event);
985 wd->event_history_list = (Event_History *) eina_inlist_remove(
986 EINA_INLIST_GET(wd->event_history_list),
987 EINA_INLIST_GET(wd->event_history_list));
990 _register_callbacks(obj);
997 * This function copies input events.
998 * We copy event info before adding it to history.
999 * The memory is freed when we clear history.
1001 * @param event the event to copy
1002 * @param event_type event type to copy
1004 * @ingroup Elm_Gesture_Layer
1007 _copy_event_info(void *event, Evas_Callback_Type event_type)
1011 case EVAS_CALLBACK_MOUSE_DOWN:
1012 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1014 case EVAS_CALLBACK_MOUSE_MOVE:
1015 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1017 case EVAS_CALLBACK_MOUSE_UP:
1018 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1020 case EVAS_CALLBACK_MOUSE_WHEEL:
1021 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1023 case EVAS_CALLBACK_MULTI_DOWN:
1024 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1026 case EVAS_CALLBACK_MULTI_MOVE:
1027 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1029 case EVAS_CALLBACK_MULTI_UP:
1030 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1032 case EVAS_CALLBACK_KEY_DOWN:
1033 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1035 case EVAS_CALLBACK_KEY_UP:
1036 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1044 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1046 Widget_Data *wd = elm_widget_data_get(obj);
1048 if (!wd) return EINA_FALSE;
1050 ev = malloc(sizeof(Event_History));
1051 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1052 ev->event_type = event_type;
1053 wd->event_history_list = (Event_History *) eina_inlist_append(
1054 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1058 /* END - Event history list handling functions */
1061 _del_hook(Evas_Object *obj)
1063 Widget_Data *wd = elm_widget_data_get(obj);
1066 _event_history_clear(obj);
1067 eina_list_free(wd->pending);
1069 Pointer_Event *data;
1070 EINA_LIST_FREE(wd->touched, data)
1073 if (!elm_widget_disabled_get(obj))
1074 _unregister_callbacks(obj);
1076 /* Free all gestures internal data structures */
1078 for (i = 0; i < ELM_GESTURE_LAST; i++)
1081 if (wd->gesture[i]->data)
1082 free(wd->gesture[i]->data);
1084 free(wd->gesture[i]);
1091 compare_match_fingers(const void *data1, const void *data2)
1092 { /* Compare coords of first item in list to cur coords */
1093 const Pointer_Event *pe1 = eina_list_data_get(data1);
1094 const Pointer_Event *pe2 = data2;
1096 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1098 else if (pe1->x < pe2->x)
1102 if (pe1->x == pe2->x)
1103 return pe1->y - pe2->y;
1110 compare_pe_device(const void *data1, const void *data2)
1111 { /* Compare device of first item in list to our pe device */
1112 const Pointer_Event *pe1 = eina_list_data_get(data1);
1113 const Pointer_Event *pe2 = data2;
1115 /* Only match if last was a down event */
1116 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1117 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1121 if (pe1->device == pe2->device)
1123 else if (pe1->device < pe2->device)
1130 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1131 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1132 { /* Keep copy of pe and record it in list */
1133 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1134 memcpy(p, pe, sizeof(Pointer_Event));
1135 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1141 /* This will also update middle-point to report to user later */
1142 st->info.x = st->sum_x / st->n_taps;
1143 st->info.y = st->sum_y / st->n_taps;
1144 st->info.timestamp = pe->timestamp;
1148 pe_list = eina_list_append(pe_list, p);
1149 st->l = eina_list_append(st->l, pe_list);
1152 pe_list = eina_list_append(pe_list, p);
1160 * This function sets state a tap-gesture to END or ABORT
1162 * @param data gesture info pointer
1164 * @ingroup Elm_Gesture_Layer
1167 _tap_gesture_finish(void *data)
1168 { /* This function will test each tap gesture when timer expires */
1169 Gesture_Info *gesture = data;
1170 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1171 /* Here we check if taps-gesture was completed successfuly */
1172 /* Count how many taps were recieved on each device then */
1173 /* determine if it matches n_taps_needed defined on START */
1174 Taps_Type *st = gesture->data;
1177 EINA_LIST_FOREACH(st->l, l, pe_list)
1179 if (eina_list_count(pe_list) != st->n_taps_needed)
1180 { /* No match taps number on device, ABORT */
1181 s = ELM_GESTURE_STATE_ABORT;
1186 st->info.n = eina_list_count(st->l);
1187 _set_state(gesture, s, gesture->info, EINA_FALSE);
1188 _tap_gestures_test_reset(gesture);
1194 * when this timer expires we finish tap gestures.
1196 * @param data The gesture-layer object.
1197 * @return cancles callback for this timer.
1199 * @ingroup Elm_Gesture_Layer
1202 _multi_tap_timeout(void *data)
1204 Widget_Data *wd = elm_widget_data_get(data);
1205 if (!wd) return EINA_FALSE;
1207 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1208 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1210 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1211 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1213 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1214 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1216 _clear_if_finished(data);
1217 wd->dbl_timeout = NULL;
1218 return ECORE_CALLBACK_CANCEL;
1224 * when this timer expires we START long tap gesture
1226 * @param data The gesture-layer object.
1227 * @return cancles callback for this timer.
1229 * @ingroup Elm_Gesture_Layer
1232 _long_tap_timeout(void *data)
1234 Gesture_Info *gesture = data;
1235 Long_Tap_Type *st = gesture->data;
1238 _set_state(gesture, ELM_GESTURE_STATE_START,
1239 gesture->data, EINA_FALSE);
1241 return ECORE_CALLBACK_CANCEL;
1248 * This function checks if a tap gesture should start
1250 * @param wd Gesture Layer Widget Data.
1251 * @param pe The recent input event as stored in pe struct.
1252 * @param event_info Original input event pointer.
1253 * @param event_type Type of original input event.
1254 * @param gesture what gesture is tested
1255 * @param how many taps for this gesture (1, 2 or 3)
1257 * @return Flag to determine if we need to set a timer for finish
1259 * @ingroup Elm_Gesture_Layer
1262 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1263 void *event_info, Evas_Callback_Type event_type,
1264 Gesture_Info *gesture, int taps)
1265 { /* Here we fill Tap struct */
1266 Taps_Type *st = gesture->data;
1268 { /* Allocated once on first time */
1269 st = calloc(1, sizeof(Taps_Type));
1271 _tap_gestures_test_reset(gesture);
1274 Eina_List *pe_list = NULL;
1275 Pointer_Event *pe_down = NULL;
1276 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1277 switch (pe->event_type)
1279 case EVAS_CALLBACK_MULTI_DOWN:
1280 case EVAS_CALLBACK_MOUSE_DOWN:
1281 /* Check if got tap on same cord was tapped before */
1282 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1285 eina_list_search_unsorted(st->l, compare_pe_device, pe))
1286 { /* This device was touched in other cord before completion */
1287 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1288 &st->info, EINA_FALSE);
1289 consume_event(wd, event_info, event_type, ev_flag);
1294 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1295 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1296 { /* This is the first mouse down we got */
1297 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1298 &st->info, EINA_FALSE);
1299 consume_event(wd, event_info, event_type, ev_flag);
1301 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1308 case EVAS_CALLBACK_MULTI_UP:
1309 case EVAS_CALLBACK_MOUSE_UP:
1310 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1314 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1317 case EVAS_CALLBACK_MULTI_MOVE:
1318 case EVAS_CALLBACK_MOUSE_MOVE:
1319 /* Get first event in first list, this has to be a Mouse Down event */
1320 /* and verify that user didn't move out of this area before next tap */
1321 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1324 pe_down = eina_list_data_get(pe_list);
1325 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1327 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1328 &st->info, EINA_FALSE);
1329 consume_event(wd, event_info, event_type, ev_flag);
1345 * This function checks all click/tap and double/triple taps
1347 * @param obj The gesture-layer object.
1348 * @param pe The recent input event as stored in pe struct.
1349 * @param event_info Original input event pointer.
1350 * @param event_type Type of original input event.
1352 * @ingroup Elm_Gesture_Layer
1355 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1356 void *event_info, Evas_Callback_Type event_type)
1357 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1358 Eina_Bool need_timer = EINA_FALSE;
1359 Widget_Data *wd = elm_widget_data_get(obj);
1362 if (!pe) /* this happens when unhandled event arrived */
1363 return; /* see _make_pointer_event function */
1365 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1366 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1367 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1369 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1370 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1371 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1373 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1374 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1375 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1377 if ((need_timer) && (!wd->dbl_timeout))
1378 { /* Set a timer to finish these gestures */
1379 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1387 * This function computes center-point for long-tap gesture
1389 * @param st Long Tap gesture info pointer
1390 * @param pe The recent input event as stored in pe struct.
1392 * @ingroup Elm_Gesture_Layer
1395 _compute_taps_center(Long_Tap_Type *st,
1396 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1398 if(!eina_list_count(st->touched))
1403 Evas_Coord x = 0, y = 0;
1404 EINA_LIST_FOREACH(st->touched, l, p)
1405 { /* Accumulate all then take avarage */
1406 if (p->device == pe->device)
1407 { /* This will take care of values coming from MOVE event */
1418 *x_out = x / eina_list_count(st->touched);
1419 *y_out = y / eina_list_count(st->touched);
1425 * This function checks N long-tap gesture.
1427 * @param obj The gesture-layer object.
1428 * @param pe The recent input event as stored in pe struct.
1429 * @param event_info Original input event pointer.
1430 * @param event_type Type of original input event.
1431 * @param g_type what Gesture we are testing.
1432 * @param taps How many click/taps we test for.
1434 * @ingroup Elm_Gesture_Layer
1437 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1438 void *event_info, Evas_Callback_Type event_type,
1439 Elm_Gesture_Types g_type)
1440 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1441 Widget_Data *wd = elm_widget_data_get(obj);
1444 if (!pe) /* this happens when unhandled event arrived */
1445 return; /* see _make_pointer_event function */
1446 Gesture_Info *gesture = wd->gesture[g_type];
1447 if (!gesture) return;
1449 Long_Tap_Type *st = gesture->data;
1451 { /* Allocated once on first time */
1452 st = calloc(1, sizeof(Long_Tap_Type));
1454 _n_long_tap_test_reset(gesture);
1457 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1458 switch (pe->event_type)
1460 case EVAS_CALLBACK_MULTI_DOWN:
1461 case EVAS_CALLBACK_MOUSE_DOWN:
1462 st->touched = _add_touched_device(st->touched, pe);
1463 st->info.n = eina_list_count(st->touched);
1464 if (st->info.n > st->max_touched)
1465 st->max_touched = st->info.n;
1467 { /* User removed finger from touch, then put back - ABORT */
1468 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1469 (gesture->state == ELM_GESTURE_STATE_MOVE))
1471 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1472 &st->info, EINA_FALSE);
1473 consume_event(wd, event_info, event_type, ev_flag);
1477 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1478 { /* This is the first mouse down we got */
1479 st->info.timestamp = pe->timestamp;
1481 /* To test long tap */
1482 /* When this timer expires, gesture STARTED */
1484 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1485 _long_tap_timeout, gesture);
1488 consume_event(wd, event_info, event_type, ev_flag);
1489 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1490 st->center_x = st->info.x;
1491 st->center_y = st->info.y;
1494 case EVAS_CALLBACK_MULTI_UP:
1495 case EVAS_CALLBACK_MOUSE_UP:
1496 st->touched = _remove_touched_device(st->touched, pe);
1497 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1499 ((gesture->state == ELM_GESTURE_STATE_START) ||
1500 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1501 { /* Report END only for gesture that STARTed */
1502 if (eina_list_count(st->touched) == 0)
1503 { /* Report END only at last release event */
1504 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1505 &st->info, EINA_FALSE);
1506 consume_event(wd, event_info, event_type, ev_flag);
1510 { /* Stop test, user lifts finger before long-start */
1511 if (st->timeout) ecore_timer_del(st->timeout);
1513 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1514 &st->info, EINA_FALSE);
1515 consume_event(wd, event_info, event_type, ev_flag);
1520 case EVAS_CALLBACK_MULTI_MOVE:
1521 case EVAS_CALLBACK_MOUSE_MOVE:
1523 ((gesture->state == ELM_GESTURE_STATE_START) ||
1524 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1525 { /* Report MOVE only if STARTED */
1528 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1530 _compute_taps_center(st, &x, &y, pe);
1531 /* ABORT if user moved fingers out of tap area */
1532 #if defined(DEBUG_GESTURE_LAYER)
1533 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1535 if (!_inside(x, y, st->center_x, st->center_y))
1536 state_to_report = ELM_GESTURE_STATE_ABORT;
1538 /* Report MOVE if gesture started */
1539 ev_flag = _set_state(gesture, state_to_report,
1540 &st->info, EINA_TRUE);
1541 consume_event(wd, event_info, event_type, ev_flag);
1553 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1554 * This momentum value will be sent to widget when gesture is completed.
1556 * @param momentum pointer to buffer where we record momentum value.
1557 * @param x1 x coord where user started gesture.
1558 * @param y1 y coord where user started gesture.
1559 * @param x2 x coord where user completed gesture.
1560 * @param y2 y coord where user completed gesture.
1561 * @param t1x timestamp for X, when user started gesture.
1562 * @param t1y timestamp for Y, when user started gesture.
1563 * @param t2 timestamp when user completed gesture.
1565 * @ingroup Elm_Gesture_Layer
1568 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1569 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1572 Evas_Coord velx = 0, vely = 0, vel;
1573 Evas_Coord dx = x2 - x1;
1574 Evas_Coord dy = y2 - y1;
1578 velx = (dx * 1000) / dtx;
1581 vely = (dy * 1000) / dty;
1583 vel = sqrt((velx * velx) + (vely * vely));
1585 if ((_elm_config->thumbscroll_friction > 0.0) &&
1586 (vel > _elm_config->thumbscroll_momentum_threshold))
1587 { /* report momentum */
1588 momentum->mx = velx;
1589 momentum->my = vely;
1601 * This function is used for computing rotation angle (DEG).
1603 * @param x1 first finger x location.
1604 * @param y1 first finger y location.
1605 * @param x2 second finger x location.
1606 * @param y2 second finger y location.
1608 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1610 * @ingroup Elm_Gesture_Layer
1613 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1615 double a, xx, yy, rt = (-1);
1619 if (((int) xx) && ((int) yy))
1621 rt = a = RAD2DEG(atan(yy / xx));
1647 { /* Do this only if rt is not set */
1649 { /* Horizontal line */
1660 { /* Vertical line */
1672 /* Now we want to change from:
1674 * original circle 180 0 We want: 270 90
1688 * This function is used for computing the magnitude and direction
1689 * of vector between two points.
1691 * @param x1 first finger x location.
1692 * @param y1 first finger y location.
1693 * @param x2 second finger x location.
1694 * @param y2 second finger y location.
1695 * @param l length computed (output)
1696 * @param a angle computed (output)
1698 * @ingroup Elm_Gesture_Layer
1701 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1702 Evas_Coord *l, double *a)
1707 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1708 *a = get_angle(x1, y1, x2, y2);
1712 _get_direction(Evas_Coord x1, Evas_Coord x2)
1725 * This function tests momentum gesture.
1726 * @param obj The gesture-layer object.
1727 * @param pe The recent input event as stored in pe struct.
1728 * @param event_info recent input event.
1729 * @param event_type recent event type.
1730 * @param g_type what Gesture we are testing.
1732 * @ingroup Elm_Gesture_Layer
1735 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1736 void *event_info, Evas_Callback_Type event_type,
1737 Elm_Gesture_Types g_type)
1739 Widget_Data *wd = elm_widget_data_get(obj);
1741 Gesture_Info *gesture = wd->gesture[g_type];
1742 if (!gesture ) return;
1744 /* When continues enable = TRUE a gesture may START on MOVE event */
1745 /* We don't allow this to happen with the if-statement below. */
1746 /* When continues enable = FALSE a gesture may START on DOWN only */
1747 /* Therefor it would NOT start on MOVE event. */
1748 /* NOTE that touched list is updated AFTER this function returns */
1749 /* so (count == 0) when we get here on first touch on surface. */
1750 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1751 return; /* Got move on mouse-over move */
1753 Momentum_Type *st = gesture->data;
1754 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1756 { /* Allocated once on first time */
1757 st = calloc(1, sizeof(Momentum_Type));
1759 _momentum_test_reset(gesture);
1765 /* First make avarage of all touched devices to determine center point */
1768 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1769 unsigned int cnt = 1; /* We start counter counting current pe event */
1770 EINA_LIST_FOREACH(wd->touched, l, p)
1771 if (p->device != pe_local.device)
1779 /* Compute avarage to get center point */
1783 /* If user added finger - reset gesture */
1784 if ((st->info.n) && (st->info.n < cnt))
1785 state_to_report = ELM_GESTURE_STATE_ABORT;
1787 if (st->info.n < cnt)
1790 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1793 case EVAS_CALLBACK_MOUSE_DOWN:
1794 case EVAS_CALLBACK_MULTI_DOWN:
1795 case EVAS_CALLBACK_MOUSE_MOVE:
1796 case EVAS_CALLBACK_MULTI_MOVE:
1799 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1800 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1801 (wd->glayer_continues_enable)) /* start also on MOVE */
1802 { /* We start on MOVE when cont-enabled only */
1803 st->line_st.x = st->line_end.x = pe_local.x;
1804 st->line_st.y = st->line_end.y = pe_local.y;
1805 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1806 st->xdir = st->ydir = 0;
1807 st->info.x2 = st->info.x1 = pe_local.x;
1808 st->info.y2 = st->info.y1 = pe_local.y;
1809 st->info.tx = st->info.ty = pe_local.timestamp;
1810 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1811 &st->info, EINA_FALSE);
1812 consume_event(wd, event_info, event_type, ev_flag);
1819 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1821 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1822 state_to_report = ELM_GESTURE_STATE_ABORT;
1824 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1825 { /* Too long of a wait, reset all values */
1826 st->line_st.x = pe_local.x;
1827 st->line_st.y = pe_local.y;
1828 st->t_st_y = st->t_st_x = pe_local.timestamp;
1829 st->info.tx = st->t_st_x;
1830 st->info.ty = st->t_st_y;
1831 st->xdir = st->ydir = 0;
1836 xdir = _get_direction(st->line_end.x, pe_local.x);
1837 ydir = _get_direction(st->line_end.y, pe_local.y);
1838 if (xdir != st->xdir)
1840 st->line_st.x = st->line_end.x;
1841 st->info.tx = st->t_st_x = st->t_end;
1845 if (ydir != st->ydir)
1847 st->line_st.y = st->line_end.y;
1848 st->info.ty = st->t_st_y = st->t_end;
1853 st->info.x2 = st->line_end.x = pe_local.x;
1854 st->info.y2 = st->line_end.y = pe_local.y;
1855 st->t_end = pe_local.timestamp;
1856 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1857 st->t_st_x, st->t_st_y, pe_local.timestamp);
1858 ev_flag = _set_state(gesture, state_to_report, &st->info,
1860 consume_event(wd, event_info, event_type, ev_flag);
1864 case EVAS_CALLBACK_MOUSE_UP:
1865 case EVAS_CALLBACK_MULTI_UP:
1866 st->t_up = pe_local.timestamp; /* Record recent up event time */
1867 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1868 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1871 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1872 { /* Too long of a wait, reset all values */
1873 st->line_st.x = pe_local.x;
1874 st->line_st.y = pe_local.y;
1875 st->t_st_y = st->t_st_x = pe_local.timestamp;
1876 st->xdir = st->ydir = 0;
1879 st->info.x2 = pe_local.x;
1880 st->info.y2 = pe_local.y;
1881 st->line_end.x = pe_local.x;
1882 st->line_end.y = pe_local.y;
1883 st->t_end = pe_local.timestamp;
1885 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1886 st->t_st_x, st->t_st_y, pe_local.timestamp);
1888 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
1889 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
1890 state_to_report = ELM_GESTURE_STATE_END;
1892 state_to_report = ELM_GESTURE_STATE_ABORT;
1894 ev_flag = _set_state(gesture, state_to_report, &st->info,
1896 consume_event(wd, event_info, event_type, ev_flag);
1905 compare_line_device(const void *data1, const void *data2)
1906 { /* Compare device component of line struct */
1907 const Line_Data *ln1 = data1;
1908 const int *device = data2;
1910 if (ln1->t_st) /* Compare only with lines that started */
1911 return (ln1->device - (*device));
1919 * This function construct line struct from input.
1920 * @param info pointer to store line momentum.
1921 * @param st line info to store input data.
1922 * @param pe The recent input event as stored in pe struct.
1924 * @ingroup Elm_Gesture_Layer
1927 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1928 Pointer_Event *pe, Evas_Callback_Type event_type)
1929 { /* Record events and set momentum for line pointed by st */
1935 case EVAS_CALLBACK_MOUSE_DOWN:
1936 case EVAS_CALLBACK_MOUSE_MOVE:
1937 case EVAS_CALLBACK_MULTI_DOWN:
1938 case EVAS_CALLBACK_MULTI_MOVE:
1940 { /* This happens only when line starts */
1941 st->line_st.x = pe->x;
1942 st->line_st.y = pe->y;
1943 st->t_st = pe->timestamp;
1944 st->device = pe->device;
1945 info->momentum.x1 = pe->x;
1946 info->momentum.y1 = pe->y;
1947 info->momentum.tx = pe->timestamp;
1948 info->momentum.ty = pe->timestamp;
1955 case EVAS_CALLBACK_MOUSE_UP:
1956 case EVAS_CALLBACK_MULTI_UP:
1957 /* IGNORE if line info was cleared, like long press, move */
1961 st->line_end.x = pe->x;
1962 st->line_end.y = pe->y;
1963 st->t_end = pe->timestamp;
1972 _line_data_reset(st);
1976 info->momentum.x2 = pe->x;
1977 info->momentum.y2 = pe->y;
1978 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1979 st->t_st, st->t_st, pe->timestamp);
1987 * This function test for (n) line gesture.
1988 * @param obj The gesture-layer object.
1989 * @param pe The recent input event as stored in pe struct.
1990 * @param event_info Original input event pointer.
1991 * @param event_type Type of original input event.
1992 * @param g_type what Gesture we are testing.
1994 * @ingroup Elm_Gesture_Layer
1997 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1998 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2002 Widget_Data *wd = elm_widget_data_get(obj);
2004 Gesture_Info *gesture = wd->gesture[g_type];
2005 if (!gesture ) return;
2007 /* When continues enable = TRUE a gesture may START on MOVE event */
2008 /* We don't allow this to happen with the if-statement below. */
2009 /* When continues enable = FALSE a gesture may START on DOWN only */
2010 /* Therefor it would NOT start on MOVE event. */
2011 /* NOTE that touched list is updated AFTER this function returns */
2012 /* so (count == 0) when we get here on first touch on surface. */
2013 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
2014 return; /* Got move on mouse-over move */
2016 Line_Type *st = gesture->data;
2019 st = calloc(1, sizeof(Line_Type));
2023 Line_Data *line = NULL;
2024 Eina_List *list = st->list;
2025 unsigned cnt = eina_list_count(list);
2028 { /* list is not empty, locate this device on list */
2029 line = (Line_Data *) eina_list_search_unsorted(st->list,
2030 compare_line_device, &pe->device);
2034 { /* List is empty or device not found, new line-struct on START only */
2035 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2036 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2037 ((wd->glayer_continues_enable) && /* START on MOVE also */
2038 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2039 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2040 { /* Allocate new item on START only */
2041 line = calloc(1, sizeof(Line_Data));
2042 _line_data_reset(line);
2043 list = eina_list_append(list, line);
2048 if (!line) /* This may happen on MOVE that comes before DOWN */
2049 return; /* No line-struct to work with, can't continue testing */
2051 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2052 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2054 /* Get direction and magnitude of the line */
2056 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2057 &line->line_length, &angle);
2059 /* These are used later to compare lines length */
2060 Evas_Coord shortest_line_len = line->line_length;
2061 Evas_Coord longest_line_len = line->line_length;
2062 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2064 /* Now update line-state */
2066 { /* Analyze line only if line started */
2067 if (line->line_angle >= 0.0)
2068 { /* if line direction was set, we test if broke tolerance */
2069 double a = fabs(angle - line->line_angle);
2071 double d = (tan(DEG2RAD(a))) * line->line_length; /* Distance from line */
2072 #if defined(DEBUG_GESTURE_LAYER)
2073 printf("%s a=<%f> d=<%f>\n", __func__, a, d);
2075 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2076 { /* Broke tolerance: abort line and start a new one */
2077 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2078 &st->info, EINA_FALSE);
2079 consume_event(wd, event_info, event_type, ev_flag);
2083 if (wd->glayer_continues_enable)
2084 { /* We may finish line if momentum is zero */
2085 /* This is for continues-gesture */
2086 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2087 { /* Finish line on zero momentum for continues gesture */
2088 line->line_end.x = pe->x;
2089 line->line_end.y = pe->y;
2090 line->t_end = pe->timestamp;
2095 { /* Record the line angle as it broke minimum length for line */
2096 if (line->line_length >= wd->line_min_length)
2097 st->info.angle = line->line_angle = angle;
2103 if (line->line_angle < 0.0)
2104 { /* it's not a line, too short more close to a tap */
2105 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2106 &st->info, EINA_FALSE);
2107 consume_event(wd, event_info, event_type, ev_flag);
2113 /* Count how many lines already started / ended */
2116 unsigned int tm_start = pe->timestamp;
2117 unsigned int tm_end = pe->timestamp;
2120 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2121 Eina_Bool lines_parallel = EINA_TRUE;
2122 EINA_LIST_FOREACH(list, l, t_line)
2125 base_angle = t_line->line_angle;
2128 if (t_line->line_angle >= 0)
2129 { /* Compare angle only with lines with direction defined */
2130 if (fabs(base_angle - t_line->line_angle) >
2131 wd->line_angular_tolerance)
2132 lines_parallel = EINA_FALSE;
2136 if (t_line->line_length)
2137 { /* update only if this line is used */
2138 if (shortest_line_len > t_line->line_length)
2139 shortest_line_len = t_line->line_length;
2141 if (longest_line_len < t_line->line_length)
2142 longest_line_len = t_line->line_length;
2148 if (t_line->t_st < tm_start)
2149 tm_start = t_line->t_st;
2155 if (t_line->t_end < tm_end)
2156 tm_end = t_line->t_end;
2160 st->info.momentum.n = started;
2164 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2165 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2166 { /* user lift one finger then starts again without line-end - ABORT */
2167 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2169 consume_event(wd, event_info, event_type, ev_flag);
2173 if (!lines_parallel)
2174 { /* Lines are NOT at same direction, abort this gesture */
2175 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2177 consume_event(wd, event_info, event_type, ev_flag);
2182 /* We report ABORT if lines length are NOT matching when fingers are up */
2183 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2185 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2187 consume_event(wd, event_info, event_type, ev_flag);
2191 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2192 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2193 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2195 consume_event(wd, event_info, event_type, ev_flag);
2201 case EVAS_CALLBACK_MOUSE_UP:
2202 case EVAS_CALLBACK_MULTI_UP:
2203 if ((started) && (started == ended))
2205 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2206 &st->info, EINA_FALSE);
2207 consume_event(wd, event_info, event_type, ev_flag);
2212 case EVAS_CALLBACK_MOUSE_DOWN:
2213 case EVAS_CALLBACK_MULTI_DOWN:
2214 case EVAS_CALLBACK_MOUSE_MOVE:
2215 case EVAS_CALLBACK_MULTI_MOVE:
2218 if (wd->glayer_continues_enable && (started == ended))
2219 { /* For continues gesture */
2220 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2221 &st->info, EINA_FALSE);
2222 consume_event(wd, event_info, event_type, ev_flag);
2225 { /* When continues, may START on MOVE event too */
2226 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2228 /* This happens when: on n > 1 lines then one finger up */
2229 /* caused abort, then put finger down. */
2230 /* This will stop line from starting again. */
2231 /* Number of lines, MUST match touched-device in list */
2232 if ((!wd->glayer_continues_enable) &&
2233 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2234 s = ELM_GESTURE_STATE_ABORT;
2236 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2237 s = ELM_GESTURE_STATE_START;
2239 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2240 consume_event(wd, event_info, event_type, ev_flag);
2246 return; /* Unhandeld event type */
2253 * This function is used to check if rotation gesture started.
2254 * @param st Contains current rotation values from user input.
2255 * @return TRUE/FALSE if we need to set rotation START.
2257 * @ingroup Elm_Gesture_Layer
2260 rotation_broke_tolerance(Rotate_Type *st)
2262 if (st->info.base_angle < 0)
2263 return EINA_FALSE; /* Angle has to be computed first */
2265 if (st->rotate_angular_tolerance < 0)
2268 double low = st->info.base_angle - st->rotate_angular_tolerance;
2269 double high = st->info.base_angle + st->rotate_angular_tolerance;
2270 double t = st->info.angle;
2294 #if defined(DEBUG_GESTURE_LAYER)
2295 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2297 if ((t < low) || (t > high))
2298 { /* This marks that roation action has started */
2299 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2300 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2310 * This function is used for computing the gap between fingers.
2311 * It returns the length and center point between fingers.
2313 * @param x1 first finger x location.
2314 * @param y1 first finger y location.
2315 * @param x2 second finger x location.
2316 * @param y2 second finger y location.
2317 * @param x Gets center point x cord (output)
2318 * @param y Gets center point y cord (output)
2320 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2322 * @ingroup Elm_Gesture_Layer
2325 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2326 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2328 double a, b, xx, yy, gap;
2331 gap = sqrt(xx*xx + yy*yy);
2333 /* START - Compute zoom center point */
2334 /* The triangle defined as follows:
2342 * http://en.wikipedia.org/wiki/Trigonometric_functions
2343 *************************************/
2344 if (((int) xx) && ((int) yy))
2346 double A = atan((yy / xx));
2347 #if defined(DEBUG_GESTURE_LAYER)
2348 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2350 a = (Evas_Coord) ((gap / 2) * sin(A));
2351 b = (Evas_Coord) ((gap / 2) * cos(A));
2352 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2353 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2358 { /* horiz line, take half width */
2359 #if defined(DEBUG_GESTURE_LAYER)
2360 printf("==== HORIZ ====\n");
2362 *x = (Evas_Coord) (xx / 2);
2363 *y = (Evas_Coord) (y1);
2367 { /* vert line, take half width */
2368 #if defined(DEBUG_GESTURE_LAYER)
2369 printf("==== VERT ====\n");
2371 *x = (Evas_Coord) (x1);
2372 *y = (Evas_Coord) (yy / 2);
2375 /* END - Compute zoom center point */
2377 return (Evas_Coord) gap;
2383 * This function is used for computing zoom value.
2385 * @param st Pointer to zoom data based on user input.
2386 * @param tm_end Recent input event timestamp.
2387 * @param zoom_val Current computed zoom value.
2389 * @return zoom momentum
2391 * @ingroup Elm_Gesture_Layer
2394 _zoom_momentum_get(Zoom_Type *st, unsigned int tm_end, double zoom_val)
2396 unsigned int tm_total;
2399 { /* if direction was already defined, check if changed */
2400 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2401 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2402 { /* Direction changed, reset momentum */
2404 st->dir = (-st->dir);
2408 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2412 st->m_st_tm = tm_end;
2413 st->m_base = zoom_val;
2416 tm_total = tm_end - st->m_st_tm;
2419 return (((zoom_val / st->m_base) - 1.0) * 1000) / tm_total;
2427 * This function is used for computing zoom value.
2429 * @param st Pointer to zoom data based on user input.
2430 * @param x1 first finger x location.
2431 * @param y1 first finger y location.
2432 * @param x2 second finger x location.
2433 * @param y2 second finger y location.
2434 * @param factor zoom-factor, used to determine how fast zoom works.
2436 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2438 * @ingroup Elm_Gesture_Layer
2441 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1,
2442 Evas_Coord x2, Evas_Coord y2, double zoom_finger_factor)
2445 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2446 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2448 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2449 &st->info.x, &st->info.y);
2451 st->info.radius = diam / 2;
2455 st->zoom_base = diam;
2456 return st->info.zoom;
2459 if (st->zoom_distance_tolerance)
2460 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2461 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2462 { /* avoid jump with zoom value when break tolerance */
2463 st->zoom_base -= st->zoom_distance_tolerance;
2464 st->zoom_distance_tolerance = 0;
2467 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2468 { /* avoid jump with zoom value when break tolerance */
2469 st->zoom_base += st->zoom_distance_tolerance;
2470 st->zoom_distance_tolerance = 0;
2476 /* We use factor only on the difference between gap-base */
2477 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2478 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2479 (float) st->zoom_base) * zoom_finger_factor));
2481 /* Momentum: zoom per second: */
2482 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
2490 * This function handles zoom with mouse wheel.
2491 * thats a combination of wheel + CTRL key.
2492 * @param obj The gesture-layer object.
2493 * @param event_info Original input event pointer.
2494 * @param event_type Type of original input event.
2495 * @param g_type what Gesture we are testing.
2497 * @ingroup Elm_Gesture_Layer
2500 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2501 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2503 Widget_Data *wd = elm_widget_data_get(obj);
2505 if (!wd->gesture[g_type]) return;
2507 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2508 Zoom_Type *st = gesture_zoom->data;
2509 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2511 { /* Allocated once on first time, used for zoom intermediate data */
2512 st = calloc(1, sizeof(Zoom_Type));
2513 gesture_zoom->data = st;
2514 _zoom_test_reset(gesture_zoom);
2519 case EVAS_CALLBACK_KEY_UP:
2521 Evas_Event_Key_Up *p = event_info;
2522 if ((!strcmp(p->keyname, "Control_L")) ||
2523 (!strcmp(p->keyname, "Control_R")))
2524 { /* Test if we ended a zoom gesture when releasing CTRL */
2525 if ((st->zoom_wheel) &&
2526 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2527 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2528 { /* User released CTRL after zooming */
2529 st->info.momentum = _zoom_momentum_get(st,
2530 p->timestamp, st->info.zoom);
2532 ev_flag = _set_state(gesture_zoom,
2533 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2534 consume_event(wd, event_info, event_type, ev_flag);
2542 case EVAS_CALLBACK_MOUSE_WHEEL:
2545 Elm_Gesture_State s;
2546 if (!evas_key_modifier_is_set(
2547 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2549 { /* if using wheel witout CTRL after starting zoom */
2550 if ((st->zoom_wheel) &&
2551 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2552 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2554 ev_flag = _set_state(gesture_zoom,
2555 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2556 consume_event(wd, event_info, event_type, ev_flag);
2561 return; /* Ignore mouse-wheel without control */
2564 /* Using mouse wheel with CTRL for zoom */
2565 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2566 { /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2567 we continue a zoom gesture */
2569 s = ELM_GESTURE_STATE_MOVE;
2572 { /* On first wheel event, report START */
2573 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2574 evas_object_evas_get(wd->target), "Control");
2576 s = ELM_GESTURE_STATE_START;
2577 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2578 ERR("Failed to Grabbed CTRL_L");
2579 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2580 ERR("Failed to Grabbed CTRL_R");
2583 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2584 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2585 st->info.x = st->zoom_wheel->canvas.x;
2586 st->info.y = st->zoom_wheel->canvas.y;
2588 if (st->zoom_wheel->z < 0) /* zoom in */
2589 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2591 if (st->zoom_wheel->z > 0) /* zoom out */
2592 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2594 if (st->info.zoom < 0.0)
2595 st->info.zoom = 0.0;
2597 st->info.momentum = _zoom_momentum_get(st,
2598 st->zoom_wheel->timestamp, st->info.zoom);
2600 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2601 consume_event(wd, event_info, event_type, ev_flag);
2613 * This function is used to test zoom gesture.
2614 * user may combine zoom, rotation together.
2615 * so its possible that both will be detected from input.
2616 * (both are two-finger movement-oriented gestures)
2618 * @param obj The gesture-layer object.
2619 * @param event_info Pointer to recent input event.
2620 * @param event_type Recent input event type.
2621 * @param g_type what Gesture we are testing.
2623 * @ingroup Elm_Gesture_Layer
2626 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2627 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2631 Widget_Data *wd = elm_widget_data_get(obj);
2633 if (!wd->gesture[g_type]) return;
2635 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2636 Zoom_Type *st = gesture_zoom->data;
2639 { /* Allocated once on first time, used for zoom data */
2640 st = calloc(1, sizeof(Zoom_Type));
2641 gesture_zoom->data = st;
2642 _zoom_test_reset(gesture_zoom);
2646 /* Start - new zoom testing, letting all fingers start */
2647 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2650 case EVAS_CALLBACK_MOUSE_MOVE:
2651 case EVAS_CALLBACK_MULTI_MOVE:
2652 /* if non-continues mode and gesture NOT started, ignore MOVE */
2653 if ((!wd->glayer_continues_enable) &&
2654 (!st->zoom_st.timestamp))
2657 case EVAS_CALLBACK_MOUSE_DOWN:
2658 case EVAS_CALLBACK_MULTI_DOWN:
2659 { /* Here we take care of zoom-start and zoom move */
2663 if(eina_list_count(wd->touched) > 2)
2664 { /* Process zoom only when 2 fingers on surface */
2665 ev_flag = _set_state(gesture_zoom,
2666 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2667 consume_event(wd, event_info, event_type, ev_flag);
2672 if (!st->zoom_st.timestamp)
2673 { /* Now scan touched-devices list and find other finger */
2674 EINA_LIST_FOREACH(wd->touched, l, p)
2675 { /* Device of other finger <> pe device */
2676 if (p->device != pe->device)
2680 if (!p) /* Single finger on touch */
2683 /* Record down fingers */
2684 consume_event(wd, event_info, event_type, ev_flag);
2685 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2686 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2688 /* Set mv field as well to be ready for MOVE events */
2689 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2690 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2692 /* Here we have zoom_st, zoom_st1 set, report START */
2693 /* Set zoom-base after BOTH down events recorded */
2694 /* Compute length of line between fingers zoom start */
2695 st->info.zoom = 1.0;
2696 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2697 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2698 &st->info.x, &st->info.y);
2700 st->info.radius = st->zoom_base / 2;
2702 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2703 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2704 { /* zoom started with mouse-wheel, don't report twice */
2705 ev_flag = _set_state(gesture_zoom,
2706 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2707 consume_event(wd, event_info, event_type, ev_flag);
2710 return; /* Zoom started */
2711 } /* End of ZOOM_START handling */
2714 /* if we got here, we have (exacally) two fingers on surfce */
2715 /* we also after START, report MOVE */
2716 /* First detect which finger moved */
2717 if (pe->device == st->zoom_mv.device)
2718 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2719 else if (pe->device == st->zoom_mv1.device)
2720 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2722 /* Compute change in zoom as fingers move */
2723 st->info.zoom = compute_zoom(st,
2724 st->zoom_mv.x, st->zoom_mv.y,
2725 st->zoom_mv1.x, st->zoom_mv1.y,
2726 wd->zoom_finger_factor);
2728 if (!st->zoom_distance_tolerance)
2729 { /* Zoom broke tolerance, report move */
2730 double d = st->info.zoom - st->next_step;
2734 if (d >= wd->zoom_step)
2735 { /* Report move in steps */
2736 st->next_step = st->info.zoom;
2738 ev_flag = _set_state(gesture_zoom,
2739 ELM_GESTURE_STATE_MOVE,
2740 &st->info, EINA_TRUE);
2741 consume_event(wd, event_info, event_type, ev_flag);
2743 } /* End of ZOOM_MOVE handling */
2748 case EVAS_CALLBACK_MOUSE_UP:
2749 case EVAS_CALLBACK_MULTI_UP:
2750 /* Reset timestamp of finger-up.This is used later
2751 by _zoom_test_reset() to retain finger-down data */
2752 consume_event(wd, event_info, event_type, ev_flag);
2753 if (((st->zoom_wheel) || (st->zoom_base)) &&
2754 (st->zoom_distance_tolerance == 0))
2756 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2757 &st->info, EINA_FALSE);
2758 consume_event(wd, event_info, event_type, ev_flag);
2763 /* if we got here not a ZOOM */
2764 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2765 { /* Must be != undefined, if gesture started */
2766 ev_flag = _set_state(gesture_zoom,
2767 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2768 consume_event(wd, event_info, event_type, ev_flag);
2771 _zoom_test_reset(gesture_zoom);
2781 _get_rotate_properties(Rotate_Type *st,
2782 Evas_Coord x1, Evas_Coord y1,
2783 Evas_Coord x2, Evas_Coord y2,
2785 { /* FIXME: Fix momentum computation, it's wrong */
2786 double prev_angle = *angle;
2787 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2788 &st->info.x, &st->info.y) / 2;
2790 *angle = get_angle(x1, y1, x2, y2);
2792 if (angle == &st->info.angle)
2793 { /* Fingers are moving, compute momentum */
2794 unsigned int tm_start =
2795 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
2796 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
2797 unsigned int tm_end =
2798 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
2799 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
2801 unsigned int tm_total = tm_end - tm_start;
2803 { /* Momentum computed as:
2804 accumulated roation angle (deg) divided by time */
2806 if (((prev_angle < 90) && ((*angle) > 270)) ||
2807 ((prev_angle > 270) && ((*angle) < 90)))
2808 { /* We circle passing ZERO point */
2809 prev_angle = (*angle);
2811 else m = (*angle) - prev_angle;
2813 st->accum_momentum += m;
2815 if ((tm_end - st->prev_momentum_tm) < 100)
2816 st->prev_momentum += m;
2819 if (fabs(st->prev_momentum) < 0.002)
2820 st->accum_momentum = 0.0; /* reset momentum */
2822 st->prev_momentum = 0.0; /* Start again */
2825 st->prev_momentum_tm = tm_end;
2826 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
2830 st->info.momentum = 0;
2836 * This function is used to test rotation gesture.
2837 * user may combine zoom, rotation together.
2838 * so its possible that both will be detected from input.
2839 * (both are two-finger movement-oriented gestures)
2841 * @param obj The gesture-layer object.
2842 * @param event_info Pointer to recent input event.
2843 * @param event_type Recent input event type.
2844 * @param g_type what Gesture we are testing.
2846 * @ingroup Elm_Gesture_Layer
2849 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2850 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2855 Widget_Data *wd = elm_widget_data_get(obj);
2857 if (!wd->gesture[g_type]) return;
2859 Gesture_Info *gesture = wd->gesture[g_type];
2865 { /* Allocated once on first time */
2866 st = calloc(1, sizeof(Rotate_Type));
2868 _rotate_test_reset(gesture);
2872 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2875 case EVAS_CALLBACK_MOUSE_MOVE:
2876 case EVAS_CALLBACK_MULTI_MOVE:
2877 /* if non-continues mode and gesture NOT started, ignore MOVE */
2878 if ((!wd->glayer_continues_enable) &&
2879 (!st->rotate_st.timestamp))
2882 case EVAS_CALLBACK_MOUSE_DOWN:
2883 case EVAS_CALLBACK_MULTI_DOWN:
2884 { /* Here we take care of rotate-start and rotate move */
2888 if(eina_list_count(wd->touched) > 2)
2889 { /* Process rotate only when 2 fingers on surface */
2890 ev_flag = _set_state(gesture,
2891 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2892 consume_event(wd, event_info, event_type, ev_flag);
2897 if (!st->rotate_st.timestamp)
2898 { /* Now scan touched-devices list and find other finger */
2899 EINA_LIST_FOREACH(wd->touched, l, p)
2900 { /* Device of other finger <> pe device */
2901 if (p->device != pe->device)
2906 return; /* Single finger on touch */
2908 /* Record down fingers */
2909 consume_event(wd, event_info, event_type, ev_flag);
2910 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2911 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2913 /* Set mv field as well to be ready for MOVE events */
2914 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2915 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2917 /* Here we have rotate_st, rotate_st1 set, report START */
2918 /* Set rotate-base after BOTH down events recorded */
2919 /* Compute length of line between fingers rotate start */
2920 _get_rotate_properties(st,
2921 st->rotate_st.x, st->rotate_st.y,
2922 st->rotate_st1.x, st->rotate_st1.y,
2923 &st->info.base_angle);
2925 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2926 &st->info, EINA_FALSE);
2927 consume_event(wd, event_info, event_type, ev_flag);
2929 return; /* Rotate started */
2930 } /* End of ROTATE_START handling */
2933 /* if we got here, we have (exacally) two fingers on surfce */
2934 /* we also after START, report MOVE */
2935 /* First detect which finger moved */
2936 if (pe->device == st->rotate_mv.device)
2937 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2938 else if (pe->device == st->rotate_mv1.device)
2939 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2941 /* Compute change in rotate as fingers move */
2942 _get_rotate_properties(st,
2943 st->rotate_mv.x, st->rotate_mv.y,
2944 st->rotate_mv1.x, st->rotate_mv1.y,
2947 if (rotation_broke_tolerance(st))
2948 { /* Rotation broke tolerance, report move */
2949 double d = st->info.angle - st->next_step;
2953 if (d >= wd->rotate_step)
2954 { /* Report move in steps */
2955 st->next_step = st->info.angle;
2957 ev_flag = _set_state(gesture,
2958 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2959 consume_event(wd, event_info, event_type, ev_flag);
2961 } /* End of ROTATE_MOVE handling */
2966 case EVAS_CALLBACK_MOUSE_UP:
2967 case EVAS_CALLBACK_MULTI_UP:
2968 consume_event(wd, event_info, event_type, ev_flag);
2969 /* Reset timestamp of finger-up.This is used later
2970 by rotate_test_reset() to retain finger-down data */
2971 if (st->rotate_angular_tolerance < 0)
2973 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2974 &st->info, EINA_FALSE);
2975 consume_event(wd, event_info, event_type, ev_flag);
2980 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2981 { /* Must be != undefined, if gesture started */
2982 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2983 &st->info, EINA_FALSE);
2984 consume_event(wd, event_info, event_type, ev_flag);
2987 _rotate_test_reset(gesture);
2998 * This function is used to save input events in an abstract struct
2999 * to be used later by getsure-testing functions.
3001 * @param data The gesture-layer object.
3002 * @param event_info Pointer to recent input event.
3003 * @param event_type Recent input event type.
3004 * @param pe The abstract data-struct (output).
3006 * @ingroup Elm_Gesture_Layer
3009 _make_pointer_event(void *data, void *event_info,
3010 Evas_Callback_Type event_type, Pointer_Event *pe)
3012 Widget_Data *wd = elm_widget_data_get(data);
3013 if (!wd) return EINA_FALSE;
3015 memset(pe, '\0', sizeof(*pe));
3018 case EVAS_CALLBACK_MOUSE_DOWN:
3019 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
3020 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
3021 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
3022 pe->device = ELM_MOUSE_DEVICE;
3025 case EVAS_CALLBACK_MOUSE_UP:
3026 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
3027 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
3028 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
3029 pe->device = ELM_MOUSE_DEVICE;
3032 case EVAS_CALLBACK_MOUSE_MOVE:
3033 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
3034 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
3035 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
3036 pe->device = ELM_MOUSE_DEVICE;
3039 case EVAS_CALLBACK_MULTI_DOWN:
3040 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
3041 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
3042 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
3043 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
3046 case EVAS_CALLBACK_MULTI_UP:
3047 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
3048 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
3049 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
3050 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
3053 case EVAS_CALLBACK_MULTI_MOVE:
3054 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
3055 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
3056 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
3057 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
3064 pe->event_type = event_type;
3071 * This function restartes line, flick, zoom and rotate gestures
3072 * when gesture-layer continues-gestures enabled.
3073 * Example of continues-gesture:
3074 * When doing a line, user stops moving finger but keeps fingers on touch.
3075 * This will cause line-end, then as user continues moving his finger
3076 * it re-starts line gesture.
3077 * When continue mode is disabled, user has to lift finger from touch
3078 * to end a gesture. Them touch-again to start a new one.
3080 * @param data The gesture-layer object.
3081 * @param wd gesture layer widget data.
3082 * @param states_reset flag that marks gestures were reset in history clear.
3084 * @ingroup Elm_Gesture_Layer
3086 void continues_gestures_restart(void *data, Eina_Bool states_reset)
3088 Widget_Data *wd = elm_widget_data_get(data);
3091 /* Run through events to restart gestures */
3093 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
3094 /* We turn-on flag for finished, aborted, not-started gestures */
3095 g = wd->gesture[ELM_GESTURE_MOMENTUM];
3096 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3097 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3100 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
3101 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3105 g = wd->gesture[ELM_GESTURE_N_LINES];
3106 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3107 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3110 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3111 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3115 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3116 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3117 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3120 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3121 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3125 g = wd->gesture[ELM_GESTURE_ZOOM];
3126 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3127 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3130 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3131 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3135 g = wd->gesture[ELM_GESTURE_ROTATE];
3136 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3137 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3140 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3141 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3149 * This function the core-function where input handling is done.
3150 * Here we get user input and stream it to gesture testing.
3151 * We notify user about any gestures with new state:
3153 * START - gesture started.
3154 * MOVE - gesture is ongoing.
3155 * END - gesture was completed.
3156 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3158 * We also check if a gesture was detected, then reset event history
3159 * If no gestures were found we reset gesture test flag
3160 * after streaming event-history to widget.
3161 * (stream to the widget all events not consumed as a gesture)
3163 * @param data The gesture-layer object.
3164 * @param event_info Pointer to recent input event.
3165 * @param event_type Recent input event type.
3167 * @ingroup Elm_Gesture_Layer
3170 _event_process(void *data, Evas_Object *obj __UNUSED__,
3171 void *event_info, Evas_Callback_Type event_type)
3174 Pointer_Event *pe = NULL;
3175 Widget_Data *wd = elm_widget_data_get(data);
3178 #if defined(DEBUG_GESTURE_LAYER)
3181 printf("Gesture | State | is tested\n");
3182 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3186 printf(" %d %d %d\n", i, g->state, g->test);
3190 /* Start testing candidate gesture from here */
3191 if (_make_pointer_event(data, event_info, event_type, &_pe))
3194 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3195 _n_long_tap_test(data, pe, event_info, event_type,
3196 ELM_GESTURE_N_LONG_TAPS);
3198 /* This takes care of single, double and tripple tap */
3199 _tap_gestures_test(data, pe, event_info, event_type);
3201 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3202 _momentum_test(data, pe, event_info, event_type,
3203 ELM_GESTURE_MOMENTUM);
3205 if (IS_TESTED(ELM_GESTURE_N_LINES))
3206 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3208 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3209 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3211 if (_elm_config->glayer_zoom_finger_enable && IS_TESTED(ELM_GESTURE_ZOOM))
3212 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3214 if (IS_TESTED(ELM_GESTURE_ZOOM))
3215 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3217 if (_elm_config->glayer_rotate_finger_enable && IS_TESTED(ELM_GESTURE_ROTATE))
3218 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3220 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3221 _event_history_add(data, event_info, event_type);
3222 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3223 (event_type == EVAS_CALLBACK_MULTI_UP))
3225 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3228 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3229 _event_history_add(data, event_info, event_type);
3233 /* we maintain list of touched devices */
3234 /* We also use move to track current device x.y pos */
3235 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3236 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3237 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3238 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3240 wd->touched = _add_touched_device(wd->touched, pe);
3242 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3243 (event_type == EVAS_CALLBACK_MULTI_UP))
3245 wd->touched = _remove_touched_device(wd->touched, pe);
3248 /* Report current states and clear history if needed */
3249 Eina_Bool states_reset = _clear_if_finished(data);
3250 if (wd->glayer_continues_enable)
3251 continues_gestures_restart(data, states_reset);
3256 * For all _mouse_* / multi_* functions wethen send this event to
3257 * _event_process function.
3259 * @param data The gesture-layer object.
3260 * @param event_info Pointer to recent input event.
3262 * @ingroup Elm_Gesture_Layer
3265 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3268 Widget_Data *wd = elm_widget_data_get(data);
3270 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3271 return; /* We only process left-click at the moment */
3273 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3277 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3280 Widget_Data *wd = elm_widget_data_get(data);
3283 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3287 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3290 Widget_Data *wd = elm_widget_data_get(data);
3293 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3297 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3300 Widget_Data *wd = elm_widget_data_get(data);
3303 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3307 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3310 Widget_Data *wd = elm_widget_data_get(data);
3313 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3314 return; /* We only process left-click at the moment */
3316 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3320 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3323 Widget_Data *wd = elm_widget_data_get(data);
3326 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3330 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3333 Widget_Data *wd = elm_widget_data_get(data);
3336 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3340 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3343 Widget_Data *wd = elm_widget_data_get(data);
3346 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3350 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3353 Widget_Data *wd = elm_widget_data_get(data);
3356 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3360 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3362 Widget_Data *wd = elm_widget_data_get(obj);
3363 if (!wd) return EINA_FALSE;
3365 return !wd->repeat_events;
3369 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3371 Widget_Data *wd = elm_widget_data_get(obj);
3374 wd->repeat_events = !r;
3378 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3380 Widget_Data *wd = elm_widget_data_get(obj);
3390 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3392 Widget_Data *wd = elm_widget_data_get(obj);
3398 wd->rotate_step = s;
3402 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3404 Widget_Data *wd = elm_widget_data_get(obj);
3405 if (!wd) return EINA_FALSE;
3410 /* if was attached before, unregister callbacks first */
3412 _unregister_callbacks(obj);
3416 _register_callbacks(obj);
3421 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3422 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3424 Widget_Data *wd = elm_widget_data_get(obj);
3428 if (!wd->gesture[idx])
3429 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3430 if (!wd->gesture[idx]) return;
3432 p = wd->gesture[idx];
3435 p->fn[cb_type].cb = cb;
3436 p->fn[cb_type].user_data = data;
3437 p->state = ELM_GESTURE_STATE_UNDEFINED;
3442 _disable_hook(Evas_Object *obj)
3444 if (elm_widget_disabled_get(obj))
3445 _unregister_callbacks(obj);
3447 _register_callbacks(obj);
3451 elm_gesture_layer_add(Evas_Object *parent)
3457 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3459 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3460 elm_widget_type_set(obj, "gesture_layer");
3461 elm_widget_sub_object_add(parent, obj);
3462 elm_widget_data_set(obj, wd);
3463 elm_widget_del_hook_set(obj, _del_hook);
3464 elm_widget_disable_hook_set(obj, _disable_hook);
3467 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3468 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3469 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3470 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3471 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3472 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3473 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3474 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3475 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3476 wd->repeat_events = EINA_TRUE;
3477 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3479 #if defined(DEBUG_GESTURE_LAYER)
3480 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3481 printf("initial values:\n\tzoom_finger_factor=<%f>\n\tzoom_distance_tolerance=<%d>\n\tline_min_length=<%d>\n\tline_distance_tolerance=<%d>\n\tzoom_wheel_factor=<%f>\n\trotate_angular_tolerance=<%f>\n\twd->line_angular_tolerance=<%f>\n\twd->flick_time_limit_ms=<%d>\n\twd->long_tap_start_timeout=<%f>\n\twd->zoom_step=<%f>\n\twd->rotate_step=<%f>\n\twd->glayer_continues_enable=<%d>\n ", wd->zoom_finger_factor, wd->zoom_distance_tolerance, wd->line_min_length, wd->line_distance_tolerance, wd->zoom_wheel_factor, wd->rotate_angular_tolerance, wd->line_angular_tolerance, wd->flick_time_limit_ms, wd->long_tap_start_timeout, wd->zoom_step, wd->rotate_step, wd->glayer_continues_enable);
3483 memset(wd->gesture, 0, sizeof(wd->gesture));