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 */
21 _glayer_bufdup(void *buf, size_t size)
28 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
31 #define SET_TEST_BIT(P) do { \
32 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; \
35 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
41 * Struct holds callback information.
43 * @ingroup Elm_Gesture_Layer
47 void *user_data; /**< Holds user data to CB (like sd) */
48 Elm_Gesture_Event_Cb cb;
55 * type for callback information
57 * @ingroup Elm_Gesture_Layer
59 typedef struct _Func_Data Func_Data;
64 * @struct _Gesture_Info
65 * Struct holds gesture info
67 * @ingroup Elm_Gesture_Layer
72 void *data; /**< Holds gesture intemidiate processing data */
73 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
74 Elm_Gesture_Types g_type; /**< gesture type */
75 Elm_Gesture_State state; /**< gesture state */
76 void *info; /**< Data for the state callback */
77 Eina_Bool test; /**< if true this gesture should be tested on input */
83 * @typedef Gesture_Info
84 * Type for _Gesture_Info
86 * @ingroup Elm_Gesture_Layer
88 typedef struct _Gesture_Info Gesture_Info;
93 * @struct _Event_History
94 * Struct holds event history.
95 * These events are repeated if no gesture found.
97 * @ingroup Elm_Gesture_Layer
103 Evas_Callback_Type event_type;
109 * @typedef Event_History
110 * Type for _Event_History
112 * @ingroup Elm_Gesture_Layer
114 typedef struct _Event_History Event_History;
119 * @struct _Pointer_Event
120 * Struct holds pointer-event info
121 * This is a generic pointer event structure
123 * @ingroup Elm_Gesture_Layer
125 struct _Pointer_Event
128 unsigned int timestamp;
130 Evas_Callback_Type event_type;
136 * @typedef Pointer_Event
137 * Type for generic pointer event structure
139 * @ingroup Elm_Gesture_Layer
141 typedef struct _Pointer_Event Pointer_Event;
143 /* All *Type structs hold result for the user in 'info' field
144 * The rest is gesture processing intermediate data.
145 * NOTE: info field must be FIRST in the struct.
146 * This is used when reporting ABORT in event_history_clear() */
149 Elm_Gesture_Taps_Info info;
152 unsigned int n_taps_needed;
156 typedef struct _Taps_Type Taps_Type;
158 struct _Long_Tap_Type
160 Elm_Gesture_Taps_Info info;
163 unsigned int max_touched;
164 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
167 typedef struct _Long_Tap_Type Long_Tap_Type;
169 struct _Momentum_Type
170 { /* Fields used by _line_test() */
171 Elm_Gesture_Momentum_Info info;
172 Evas_Coord_Point line_st;
173 Evas_Coord_Point line_end;
174 unsigned int t_st_x; /* Time start on X */
175 unsigned int t_st_y; /* Time start on Y */
176 unsigned int t_end; /* Time end */
177 unsigned int t_up; /* Recent up event time */
180 typedef struct _Momentum_Type Momentum_Type;
184 Evas_Coord_Point line_st;
185 Evas_Coord_Point line_end;
186 Evas_Coord line_length;
187 unsigned int t_st; /* Time start */
188 unsigned int t_end; /* Time end */
190 double line_angle; /* Current angle of line */
192 typedef struct _Line_Data Line_Data;
195 { /* Fields used by _line_test() */
196 Elm_Gesture_Line_Info info;
197 Eina_List *list; /* List of Line_Data */
199 typedef struct _Line_Type Line_Type;
202 { /* Fields used by _zoom_test() */
203 Elm_Gesture_Zoom_Info info;
204 Pointer_Event zoom_st;
205 Pointer_Event zoom_mv;
206 Pointer_Event zoom_st1;
207 Pointer_Event zoom_mv1;
208 Evas_Event_Mouse_Wheel *zoom_wheel;
209 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
210 Evas_Coord zoom_distance_tolerance;
211 unsigned int m_st_tm; /* momentum start time */
212 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
213 double m_base; /* zoom value when momentum starts */
216 typedef struct _Zoom_Type Zoom_Type;
219 { /* Fields used by _rotation_test() */
220 Elm_Gesture_Rotate_Info info;
221 Pointer_Event rotate_st;
222 Pointer_Event rotate_mv;
223 Pointer_Event rotate_st1;
224 Pointer_Event rotate_mv1;
225 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
226 double prev_momentum; /* Snapshot of momentum 0.01 sec ago */
227 double accum_momentum;
228 double rotate_angular_tolerance;
231 typedef struct _Rotate_Type Rotate_Type;
235 Evas_Object *target; /* Target Widget */
236 Event_History *event_history_list;
239 Evas_Coord zoom_distance_tolerance;
240 Evas_Coord line_distance_tolerance;
241 double line_angular_tolerance;
242 double zoom_wheel_factor; /* mouse wheel zoom steps */
243 double zoom_finger_factor; /* used for zoom factor */
244 double rotate_angular_tolerance;
245 unsigned int flick_time_limit_ms;
246 double long_tap_start_timeout;
247 Eina_Bool glayer_continues_enable;
252 Gesture_Info *gesture[ELM_GESTURE_LAST];
253 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
254 Eina_List *pending; /* List of devices need to refeed *UP event */
255 Eina_List *touched; /* Information of touched devices */
257 Eina_Bool repeat_events : 1;
259 typedef struct _Widget_Data Widget_Data;
261 static const char *widtype = NULL;
262 static void _del_hook(Evas_Object *obj);
264 static Eina_Bool _event_history_clear(Evas_Object *obj);
265 static void _reset_states(Widget_Data *wd);
266 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
267 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
268 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
269 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
270 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
271 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
272 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
274 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
275 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
276 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
278 /* START - Functions to manage touched-device list */
281 * This function is used to find if device is touched
283 * @ingroup Elm_Gesture_Layer
286 compare_device(const void *data1, const void *data2)
287 { /* Compare the two device numbers */
288 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
294 * Remove Pointer Event from touched device list
295 * @param list Pointer to touched device list.
296 * @param Pointer_Event Pointer to PE.
298 * @ingroup Elm_Gesture_Layer
301 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
303 Eina_List *lst = NULL;
304 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
307 lst = eina_list_remove(list, p);
318 * Recoed Pointer Event in touched device list
319 * Note: This fuction allocates memory for PE event
320 * This memory is released in _remove_touched_device()
321 * @param list Pointer to touched device list.
322 * @param Pointer_Event Pointer to PE.
324 * @ingroup Elm_Gesture_Layer
327 _add_touched_device(Eina_List *list, Pointer_Event *pe)
329 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
331 { /* We like to track device touch-position, overwrite info */
332 memcpy(p, pe, sizeof(Pointer_Event));
336 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
337 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN))
338 { /* Add touched device on DOWN event only */
339 p = malloc(sizeof(Pointer_Event));
340 /* Freed in _remove_touched_device() */
341 memcpy(p, pe, sizeof(Pointer_Event));
342 return eina_list_append(list, p);
347 /* END - Functions to manage touched-device list */
353 * @param event_info pointer to event.
355 * @ingroup Elm_Gesture_Layer
357 static Evas_Event_Flags
358 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
362 case EVAS_CALLBACK_MOUSE_IN:
363 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
364 case EVAS_CALLBACK_MOUSE_OUT:
365 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
366 case EVAS_CALLBACK_MOUSE_DOWN:
367 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
368 case EVAS_CALLBACK_MOUSE_MOVE:
369 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
370 case EVAS_CALLBACK_MOUSE_UP:
371 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
372 case EVAS_CALLBACK_MOUSE_WHEEL:
373 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
374 case EVAS_CALLBACK_MULTI_DOWN:
375 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
376 case EVAS_CALLBACK_MULTI_MOVE:
377 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
378 case EVAS_CALLBACK_MULTI_UP:
379 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
380 case EVAS_CALLBACK_KEY_DOWN:
381 return ((Evas_Event_Key_Down *) event_info)->event_flags;
382 case EVAS_CALLBACK_KEY_UP:
383 return ((Evas_Event_Key_Up *) event_info)->event_flags;
385 return EVAS_EVENT_FLAG_NONE;
392 * Sets event flag to value returned from user callback
393 * @param wd Widget Data
394 * @param event_info pointer to event.
395 * @param event_type what type was ev (mouse down, etc...)
396 * @param ev_flags event flags
398 * @ingroup Elm_Gesture_Layer
401 consume_event(Widget_Data *wd, void *event_info,
402 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
403 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
404 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
405 /* should not refeed this event. */
407 return; /* This happens when restarting gestures */
409 if ((ev_flags) || (!wd->repeat_events))
413 case EVAS_CALLBACK_MOUSE_DOWN:
414 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
416 case EVAS_CALLBACK_MOUSE_MOVE:
417 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
419 case EVAS_CALLBACK_MOUSE_UP:
420 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
422 case EVAS_CALLBACK_MOUSE_WHEEL:
423 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
425 case EVAS_CALLBACK_MULTI_DOWN:
426 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
428 case EVAS_CALLBACK_MULTI_MOVE:
429 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
431 case EVAS_CALLBACK_MULTI_UP:
432 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
434 case EVAS_CALLBACK_KEY_DOWN:
435 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
437 case EVAS_CALLBACK_KEY_UP:
438 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
449 * Report current state of a gesture by calling user callback.
450 * @param gesture what gesture state we report.
451 * @param info inforamtion for user callback
453 * @ingroup Elm_Gesture_Layer
455 static Evas_Event_Flags
456 _report_state(Gesture_Info *gesture, void *info)
457 { /* We report current state (START, MOVE, END, ABORT), once */
458 #if defined(DEBUG_GESTURE_LAYER)
459 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
462 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
463 (gesture->fn[gesture->state].cb))
464 { /* Fill state-info struct and send ptr to user callback */
465 return gesture->fn[gesture->state].cb(
466 gesture->fn[gesture->state].user_data, info);
469 return EVAS_EVENT_FLAG_NONE;
475 * Update state for a given gesture.
476 * We may update gesture state to:
477 * UNDEFINED - current input did not start gesure yet.
478 * START - gesture started according to input.
479 * MOVE - gusture in progress.
480 * END - gesture completed according to input.
481 * ABORT - input does not matches gesure.
482 * note that we may move from UNDEFINED to ABORT
483 * because we may detect that gesture will not START
484 * with a given input.
486 * @param g given gesture to change state.
487 * @param s gesure new state.
488 * @param info buffer to be sent to user callback on report_state.
489 * @param force makes report_state to report the new-state even
490 * if its same as current state. Works for MOVE - gesture in progress.
492 * @ingroup Elm_Gesture_Layer
494 static Evas_Event_Flags
495 _set_state(Gesture_Info *g, Elm_Gesture_State s,
496 void *info, Eina_Bool force)
498 Elm_Gesture_State old_state;
499 if ((g->state == s) && (!force))
500 return EVAS_EVENT_FLAG_NONE;
502 old_state = g->state;
505 g->info = info; /* Information for user callback */
506 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
507 (g->state == ELM_GESTURE_STATE_END))
508 g->test = EINA_FALSE;
510 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
511 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
512 (s == ELM_GESTURE_STATE_ABORT))))
513 return _report_state(g, g->info);
515 return EVAS_EVENT_FLAG_NONE;
521 * This resets all gesture states and sets test-bit.
522 * this is used for restarting gestures to listen to input.
523 * happens after we complete a gesture or no gesture was detected.
524 * @param wd Widget data of the gesture-layer object.
526 * @ingroup Elm_Gesture_Layer
529 _reset_states(Widget_Data *wd)
533 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
538 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
547 * if gesture was NOT detected AND we only have gestures in ABORT state
548 * we clear history immediately to be ready for input.
550 * @param obj The gesture-layer object.
551 * @return TRUE on event history_clear
553 * @ingroup Elm_Gesture_Layer
556 _clear_if_finished(Evas_Object *obj)
558 Widget_Data *wd = elm_widget_data_get(obj);
559 if (!wd) return EINA_FALSE;
562 /* Clear history if all we have aborted gestures */
563 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
564 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
565 { /* If no gesture started and all we have aborted gestures, reset all */
566 Gesture_Info *p = wd->gesture[i];
567 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
569 if ((p->state == ELM_GESTURE_STATE_START) ||
570 (p->state == ELM_GESTURE_STATE_MOVE))
571 reset_s = EINA_FALSE;
573 all_undefined = EINA_FALSE;
577 if (reset_s && (!all_undefined))
578 return _event_history_clear(obj);
584 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
586 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
602 /* All *test_reset() funcs are called to clear
603 * gesture intermediate data.
604 * This happens when we need to reset our tests.
605 * for example when gesture is detected or all ABORTed. */
607 _tap_gestures_test_reset(Gesture_Info *gesture)
612 Widget_Data *wd = elm_widget_data_get(gesture->obj);
613 wd->dbl_timeout = NULL;
620 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
621 EINA_LIST_FREE(data, pe)
624 memset(gesture->data, 0, sizeof(Taps_Type));
627 /* All *test_reset() funcs are called to clear
628 * gesture intermediate data.
629 * This happens when we need to reset our tests.
630 * for example when gesture is detected or all ABORTed. */
632 _n_long_tap_test_reset(Gesture_Info *gesture)
640 Long_Tap_Type *st = gesture->data;
643 EINA_LIST_FOREACH(st->touched, l, p)
646 eina_list_free(st->touched);
647 if (st->timeout) ecore_timer_del(st->timeout);
648 memset(gesture->data, 0, sizeof(Long_Tap_Type));
652 _momentum_test_reset(Gesture_Info *gesture)
660 memset(gesture->data, 0, sizeof(Momentum_Type));
664 _line_data_reset(Line_Data *st)
669 memset(st, 0, sizeof(Line_Data));
670 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
674 _line_test_reset(Gesture_Info *gesture)
682 Line_Type *st = gesture->data;
683 Eina_List *list = st->list;
686 EINA_LIST_FOREACH(list, l, t_line)
689 eina_list_free(list);
694 _zoom_test_reset(Gesture_Info *gesture)
702 Widget_Data *wd = elm_widget_data_get(gesture->obj);
703 Zoom_Type *st = gesture->data;
704 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
705 evas_object_evas_get(wd->target), "Control");
706 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
707 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
709 memset(st, 0, sizeof(Zoom_Type));
710 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
715 _rotate_test_reset(Gesture_Info *gesture)
723 Widget_Data *wd = elm_widget_data_get(gesture->obj);
724 Rotate_Type *st = gesture->data;
726 memset(st, 0, sizeof(Rotate_Type));
727 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
728 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
735 * We register callbacks when gesture layer is attached to an object
736 * or when its enabled after disable.
738 * @param obj The gesture-layer object.
740 * @ingroup Elm_Gesture_Layer
743 _register_callbacks(Evas_Object *obj)
745 Widget_Data *wd = elm_widget_data_get(obj);
750 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
752 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
754 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
757 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
760 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
762 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
764 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
767 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
769 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
777 * We unregister callbacks when gesture layer is disabled.
779 * @param obj The gesture-layer object.
781 * @ingroup Elm_Gesture_Layer
784 _unregister_callbacks(Evas_Object *obj)
786 Widget_Data *wd = elm_widget_data_get(obj);
791 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
793 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
795 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
798 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
801 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
804 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
807 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
810 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
812 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
817 /* START - Event history list handling functions */
820 * This function is used to find if device number
821 * is found in a list of devices.
822 * The list contains devices for refeeding *UP event
824 * @ingroup Elm_Gesture_Layer
827 device_in_pending_list(const void *data1, const void *data2)
828 { /* Compare the two device numbers */
829 return (((intptr_t) data1) - ((intptr_t) data2));
835 * This functions adds device to refeed-pending device list
836 * @ingroup Elm_Gesture_Layer
839 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
841 int device = ELM_MOUSE_DEVICE;
844 case EVAS_CALLBACK_MOUSE_DOWN:
846 case EVAS_CALLBACK_MULTI_DOWN:
847 device = ((Evas_Event_Multi_Down *) event)->device;
853 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
856 return eina_list_append(list, (intptr_t*) device);
865 * This functions returns pending-device node
866 * @ingroup Elm_Gesture_Layer
869 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
871 int device = ELM_MOUSE_DEVICE;
874 case EVAS_CALLBACK_MOUSE_UP:
876 case EVAS_CALLBACK_MULTI_UP:
877 device = ((Evas_Event_Multi_Up *) event)->device;
883 return eina_list_search_unsorted_list(list, device_in_pending_list,
884 (intptr_t *) device);
890 * This function reports ABORT to all none-detected gestures
891 * Then resets test bits for all desired gesures
892 * and clears input-events history.
893 * note: if no gesture was detected, events from history list
894 * are streamed to the widget because it's unused by layer.
895 * user may cancel refeed of events by setting repeat events.
897 * @param obj The gesture-layer object.
899 * @ingroup Elm_Gesture_Layer
902 _event_history_clear(Evas_Object *obj)
904 Widget_Data *wd = elm_widget_data_get(obj);
905 if (!wd) return EINA_FALSE;
909 Evas *e = evas_object_evas_get(obj);
910 Eina_Bool gesture_found = EINA_FALSE;
911 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
916 if (p->state == ELM_GESTURE_STATE_END)
917 gesture_found = EINA_TRUE;
919 { /* Report ABORT to all gestures that still not finished */
920 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
926 _reset_states(wd); /* we are ready to start testing for gestures again */
928 /* Clear all gestures intermediate data */
929 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
930 { /* We do not clear a long-tap gesture if fingers still on surface */
931 /* and gesture timer still pending to test gesture state */
932 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
933 if ((st) && /* st not allocated if clear occurs before 1st input */
934 ((!eina_list_count(st->touched)) || (!st->timeout)))
935 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
940 ecore_timer_del(wd->dbl_timeout);
941 wd->dbl_timeout = NULL;
944 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
945 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
946 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
947 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
948 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
949 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
950 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
951 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
953 /* Disable gesture layer so refeeded events won't be consumed by it */
954 _unregister_callbacks(obj);
955 while (wd->event_history_list)
958 t = wd->event_history_list;
959 Eina_List *pending = _device_is_pending(wd->pending,
960 wd->event_history_list->event,
961 wd->event_history_list->event_type);
963 /* Refeed events if no gesture matched input */
964 if (pending || ((!gesture_found) && (!wd->repeat_events)))
966 evas_event_refeed_event(e, wd->event_history_list->event,
967 wd->event_history_list->event_type);
971 wd->pending = eina_list_remove_list(wd->pending, pending);
975 wd->pending = _add_device_pending(wd->pending,
976 wd->event_history_list->event,
977 wd->event_history_list->event_type);
981 free(wd->event_history_list->event);
982 wd->event_history_list = (Event_History *) eina_inlist_remove(
983 EINA_INLIST_GET(wd->event_history_list),
984 EINA_INLIST_GET(wd->event_history_list));
987 _register_callbacks(obj);
994 * This function copies input events.
995 * We copy event info before adding it to history.
996 * The memory is freed when we clear history.
998 * @param event the event to copy
999 * @param event_type event type to copy
1001 * @ingroup Elm_Gesture_Layer
1004 _copy_event_info(void *event, Evas_Callback_Type event_type)
1008 case EVAS_CALLBACK_MOUSE_DOWN:
1009 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1011 case EVAS_CALLBACK_MOUSE_MOVE:
1012 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1014 case EVAS_CALLBACK_MOUSE_UP:
1015 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1017 case EVAS_CALLBACK_MOUSE_WHEEL:
1018 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1020 case EVAS_CALLBACK_MULTI_DOWN:
1021 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1023 case EVAS_CALLBACK_MULTI_MOVE:
1024 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1026 case EVAS_CALLBACK_MULTI_UP:
1027 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1029 case EVAS_CALLBACK_KEY_DOWN:
1030 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1032 case EVAS_CALLBACK_KEY_UP:
1033 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1041 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1043 Widget_Data *wd = elm_widget_data_get(obj);
1045 if (!wd) return EINA_FALSE;
1047 ev = malloc(sizeof(Event_History));
1048 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1049 ev->event_type = event_type;
1050 wd->event_history_list = (Event_History *) eina_inlist_append(
1051 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1055 /* END - Event history list handling functions */
1058 _del_hook(Evas_Object *obj)
1060 Widget_Data *wd = elm_widget_data_get(obj);
1063 _event_history_clear(obj);
1064 eina_list_free(wd->pending);
1066 Pointer_Event *data;
1067 EINA_LIST_FREE(wd->touched, data)
1070 if (!elm_widget_disabled_get(obj))
1071 _unregister_callbacks(obj);
1073 /* Free all gestures internal data structures */
1075 for (i = 0; i < ELM_GESTURE_LAST; i++)
1078 if (wd->gesture[i]->data)
1079 free(wd->gesture[i]->data);
1081 free(wd->gesture[i]);
1088 compare_match_fingers(const void *data1, const void *data2)
1089 { /* Compare coords of first item in list to cur coords */
1090 const Pointer_Event *pe1 = eina_list_data_get(data1);
1091 const Pointer_Event *pe2 = data2;
1093 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1095 else if (pe1->x < pe2->x)
1099 if (pe1->x == pe2->x)
1100 return pe1->y - pe2->y;
1107 compare_pe_device(const void *data1, const void *data2)
1108 { /* Compare device of first item in list to our pe device */
1109 const Pointer_Event *pe1 = eina_list_data_get(data1);
1110 const Pointer_Event *pe2 = data2;
1112 /* Only match if last was a down event */
1113 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1114 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1118 if (pe1->device == pe2->device)
1120 else if (pe1->device < pe2->device)
1127 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1128 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1129 { /* Keep copy of pe and record it in list */
1130 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1131 memcpy(p, pe, sizeof(Pointer_Event));
1132 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1138 /* This will also update middle-point to report to user later */
1139 st->info.x = st->sum_x / st->n_taps;
1140 st->info.y = st->sum_y / st->n_taps;
1141 st->info.timestamp = pe->timestamp;
1145 pe_list = eina_list_append(pe_list, p);
1146 st->l = eina_list_append(st->l, pe_list);
1149 pe_list = eina_list_append(pe_list, p);
1157 * This function sets state a tap-gesture to END or ABORT
1159 * @param data gesture info pointer
1161 * @ingroup Elm_Gesture_Layer
1164 _tap_gesture_finish(void *data)
1165 { /* This function will test each tap gesture when timer expires */
1166 Gesture_Info *gesture = data;
1167 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1168 /* Here we check if taps-gesture was completed successfuly */
1169 /* Count how many taps were recieved on each device then */
1170 /* determine if it matches n_taps_needed defined on START */
1171 Taps_Type *st = gesture->data;
1174 EINA_LIST_FOREACH(st->l, l, pe_list)
1176 if (eina_list_count(pe_list) != st->n_taps_needed)
1177 { /* No match taps number on device, ABORT */
1178 s = ELM_GESTURE_STATE_ABORT;
1183 st->info.n = eina_list_count(st->l);
1184 _set_state(gesture, s, gesture->info, EINA_FALSE);
1185 _tap_gestures_test_reset(gesture);
1191 * when this timer expires we finish tap gestures.
1193 * @param data The gesture-layer object.
1194 * @return cancles callback for this timer.
1196 * @ingroup Elm_Gesture_Layer
1199 _multi_tap_timeout(void *data)
1201 Widget_Data *wd = elm_widget_data_get(data);
1202 if (!wd) return EINA_FALSE;
1204 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1205 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1207 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1208 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1210 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1211 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1213 _clear_if_finished(data);
1214 wd->dbl_timeout = NULL;
1215 return ECORE_CALLBACK_CANCEL;
1221 * when this timer expires we START long tap gesture
1223 * @param data The gesture-layer object.
1224 * @return cancles callback for this timer.
1226 * @ingroup Elm_Gesture_Layer
1229 _long_tap_timeout(void *data)
1231 Gesture_Info *gesture = data;
1232 Long_Tap_Type *st = gesture->data;
1235 _set_state(gesture, ELM_GESTURE_STATE_START,
1236 gesture->data, EINA_FALSE);
1238 return ECORE_CALLBACK_CANCEL;
1245 * This function checks if a tap gesture should start
1247 * @param wd Gesture Layer Widget Data.
1248 * @param pe The recent input event as stored in pe struct.
1249 * @param event_info Original input event pointer.
1250 * @param event_type Type of original input event.
1251 * @param gesture what gesture is tested
1252 * @param how many taps for this gesture (1, 2 or 3)
1254 * @return Flag to determine if we need to set a timer for finish
1256 * @ingroup Elm_Gesture_Layer
1259 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1260 void *event_info, Evas_Callback_Type event_type,
1261 Gesture_Info *gesture, int taps)
1262 { /* Here we fill Tap struct */
1263 Taps_Type *st = gesture->data;
1265 { /* Allocated once on first time */
1266 st = calloc(1, sizeof(Taps_Type));
1268 _tap_gestures_test_reset(gesture);
1271 Eina_List *pe_list = NULL;
1272 Pointer_Event *pe_down = NULL;
1273 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1274 switch (pe->event_type)
1276 case EVAS_CALLBACK_MULTI_DOWN:
1277 case EVAS_CALLBACK_MOUSE_DOWN:
1278 /* Check if got tap on same cord was tapped before */
1279 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1282 eina_list_search_unsorted(st->l, compare_pe_device, pe))
1283 { /* This device was touched in other cord before completion */
1284 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1285 &st->info, EINA_FALSE);
1286 consume_event(wd, event_info, event_type, ev_flag);
1291 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1292 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1293 { /* This is the first mouse down we got */
1294 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1295 &st->info, EINA_FALSE);
1296 consume_event(wd, event_info, event_type, ev_flag);
1298 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1305 case EVAS_CALLBACK_MULTI_UP:
1306 case EVAS_CALLBACK_MOUSE_UP:
1307 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1311 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1314 case EVAS_CALLBACK_MULTI_MOVE:
1315 case EVAS_CALLBACK_MOUSE_MOVE:
1316 /* Get first event in first list, this has to be a Mouse Down event */
1317 /* and verify that user didn't move out of this area before next tap */
1318 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1321 pe_down = eina_list_data_get(pe_list);
1322 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1324 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1325 &st->info, EINA_FALSE);
1326 consume_event(wd, event_info, event_type, ev_flag);
1342 * This function checks all click/tap and double/triple taps
1344 * @param obj The gesture-layer object.
1345 * @param pe The recent input event as stored in pe struct.
1346 * @param event_info Original input event pointer.
1347 * @param event_type Type of original input event.
1349 * @ingroup Elm_Gesture_Layer
1352 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1353 void *event_info, Evas_Callback_Type event_type)
1354 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1355 Eina_Bool need_timer = EINA_FALSE;
1356 Widget_Data *wd = elm_widget_data_get(obj);
1359 if (!pe) /* this happens when unhandled event arrived */
1360 return; /* see _make_pointer_event function */
1362 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1363 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1364 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1366 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1367 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1368 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1370 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1371 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1372 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1374 if ((need_timer) && (!wd->dbl_timeout))
1375 { /* Set a timer to finish these gestures */
1376 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1384 * This function computes center-point for long-tap gesture
1386 * @param st Long Tap gesture info pointer
1387 * @param pe The recent input event as stored in pe struct.
1389 * @ingroup Elm_Gesture_Layer
1392 _compute_taps_center(Long_Tap_Type *st,
1393 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1395 if(!eina_list_count(st->touched))
1400 Evas_Coord x = 0, y = 0;
1401 EINA_LIST_FOREACH(st->touched, l, p)
1402 { /* Accumulate all then take avarage */
1403 if (p->device == pe->device)
1404 { /* This will take care of values coming from MOVE event */
1415 *x_out = x / eina_list_count(st->touched);
1416 *y_out = y / eina_list_count(st->touched);
1422 * This function checks N long-tap gesture.
1424 * @param obj The gesture-layer object.
1425 * @param pe The recent input event as stored in pe struct.
1426 * @param event_info Original input event pointer.
1427 * @param event_type Type of original input event.
1428 * @param g_type what Gesture we are testing.
1429 * @param taps How many click/taps we test for.
1431 * @ingroup Elm_Gesture_Layer
1434 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1435 void *event_info, Evas_Callback_Type event_type,
1436 Elm_Gesture_Types g_type)
1437 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1438 Widget_Data *wd = elm_widget_data_get(obj);
1441 if (!pe) /* this happens when unhandled event arrived */
1442 return; /* see _make_pointer_event function */
1443 Gesture_Info *gesture = wd->gesture[g_type];
1444 if (!gesture) return;
1446 Long_Tap_Type *st = gesture->data;
1448 { /* Allocated once on first time */
1449 st = calloc(1, sizeof(Long_Tap_Type));
1451 _n_long_tap_test_reset(gesture);
1454 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1455 switch (pe->event_type)
1457 case EVAS_CALLBACK_MULTI_DOWN:
1458 case EVAS_CALLBACK_MOUSE_DOWN:
1459 st->touched = _add_touched_device(st->touched, pe);
1460 st->info.n = eina_list_count(st->touched);
1461 if (st->info.n > st->max_touched)
1462 st->max_touched = st->info.n;
1464 { /* User removed finger from touch, then put back - ABORT */
1465 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1466 (gesture->state == ELM_GESTURE_STATE_MOVE))
1468 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1469 &st->info, EINA_FALSE);
1470 consume_event(wd, event_info, event_type, ev_flag);
1474 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1475 { /* This is the first mouse down we got */
1476 st->info.timestamp = pe->timestamp;
1478 /* To test long tap */
1479 /* When this timer expires, gesture STARTED */
1481 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1482 _long_tap_timeout, gesture);
1485 consume_event(wd, event_info, event_type, ev_flag);
1486 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1487 st->center_x = st->info.x;
1488 st->center_y = st->info.y;
1491 case EVAS_CALLBACK_MULTI_UP:
1492 case EVAS_CALLBACK_MOUSE_UP:
1493 st->touched = _remove_touched_device(st->touched, pe);
1494 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1496 ((gesture->state == ELM_GESTURE_STATE_START) ||
1497 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1498 { /* Report END only for gesture that STARTed */
1499 if (eina_list_count(st->touched) == 0)
1500 { /* Report END only at last release event */
1501 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1502 &st->info, EINA_FALSE);
1503 consume_event(wd, event_info, event_type, ev_flag);
1507 { /* Stop test, user lifts finger before long-start */
1508 if (st->timeout) ecore_timer_del(st->timeout);
1510 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1511 &st->info, EINA_FALSE);
1512 consume_event(wd, event_info, event_type, ev_flag);
1517 case EVAS_CALLBACK_MULTI_MOVE:
1518 case EVAS_CALLBACK_MOUSE_MOVE:
1520 ((gesture->state == ELM_GESTURE_STATE_START) ||
1521 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1522 { /* Report MOVE only if STARTED */
1525 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1527 _compute_taps_center(st, &x, &y, pe);
1528 /* ABORT if user moved fingers out of tap area */
1529 #if defined(DEBUG_GESTURE_LAYER)
1530 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1532 if (!_inside(x, y, st->center_x, st->center_y))
1533 state_to_report = ELM_GESTURE_STATE_ABORT;
1535 /* Report MOVE if gesture started */
1536 ev_flag = _set_state(gesture, state_to_report,
1537 &st->info, EINA_TRUE);
1538 consume_event(wd, event_info, event_type, ev_flag);
1550 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1551 * This momentum value will be sent to widget when gesture is completed.
1553 * @param momentum pointer to buffer where we record momentum value.
1554 * @param x1 x coord where user started gesture.
1555 * @param y1 y coord where user started gesture.
1556 * @param x2 x coord where user completed gesture.
1557 * @param y2 y coord where user completed gesture.
1558 * @param t1x timestamp for X, when user started gesture.
1559 * @param t1y timestamp for Y, when user started gesture.
1560 * @param t2 timestamp when user completed gesture.
1562 * @ingroup Elm_Gesture_Layer
1565 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1566 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1569 Evas_Coord velx = 0, vely = 0, vel;
1570 Evas_Coord dx = x2 - x1;
1571 Evas_Coord dy = y2 - y1;
1575 velx = (dx * 1000) / dtx;
1578 vely = (dy * 1000) / dty;
1580 vel = sqrt((velx * velx) + (vely * vely));
1582 if ((_elm_config->thumbscroll_friction > 0.0) &&
1583 (vel > _elm_config->thumbscroll_momentum_threshold))
1584 { /* report momentum */
1585 momentum->mx = velx;
1586 momentum->my = vely;
1598 * This function is used for computing rotation angle (DEG).
1600 * @param x1 first finger x location.
1601 * @param y1 first finger y location.
1602 * @param x2 second finger x location.
1603 * @param y2 second finger y location.
1605 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1607 * @ingroup Elm_Gesture_Layer
1610 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1616 if (((int) xx) && ((int) yy))
1623 return RAD_360DEG - a;
1634 return RAD_180DEG + a;
1638 return RAD_180DEG - a;
1644 { /* Horizontal line */
1669 * This function is used for computing the magnitude and direction
1670 * of vector between two points.
1672 * @param x1 first finger x location.
1673 * @param y1 first finger y location.
1674 * @param x2 second finger x location.
1675 * @param y2 second finger y location.
1676 * @param l length computed (output)
1677 * @param a angle computed (output)
1679 * @ingroup Elm_Gesture_Layer
1682 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1683 Evas_Coord *l, double *a)
1688 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1689 *a = get_angle(x1, y1, x2, y2);
1693 _get_direction(Evas_Coord x1, Evas_Coord x2)
1705 * This function tests momentum gesture.
1706 * @param obj The gesture-layer object.
1707 * @param pe The recent input event as stored in pe struct.
1708 * @param event_info recent input event.
1709 * @param event_type recent event type.
1710 * @param g_type what Gesture we are testing.
1712 * @ingroup Elm_Gesture_Layer
1715 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1716 void *event_info, Evas_Callback_Type event_type,
1717 Elm_Gesture_Types g_type)
1719 Widget_Data *wd = elm_widget_data_get(obj);
1721 Gesture_Info *gesture = wd->gesture[g_type];
1722 if (!gesture ) return;
1724 /* When continues enable = TRUE a gesture may START on MOVE event */
1725 /* We don't allow this to happen with the if-statement below. */
1726 /* When continues enable = FALSE a gesture may START on DOWN only */
1727 /* Therefor it would NOT start on MOVE event. */
1728 /* NOTE that touched list is updated AFTER this function returns */
1729 /* so (count == 0) when we get here on first touch on surface. */
1730 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1731 return; /* Got move on mouse-over move */
1733 Momentum_Type *st = gesture->data;
1734 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1736 { /* Allocated once on first time */
1737 st = calloc(1, sizeof(Momentum_Type));
1739 _momentum_test_reset(gesture);
1745 /* First make avarage of all touched devices to determine center point */
1748 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1749 unsigned int cnt = 1; /* We start counter counting current pe event */
1750 EINA_LIST_FOREACH(wd->touched, l, p)
1751 if (p->device != pe_local.device)
1759 /* Compute avarage to get center point */
1763 /* If user added finger - reset gesture */
1764 if ((st->info.n) && (st->info.n < cnt))
1765 state_to_report = ELM_GESTURE_STATE_ABORT;
1767 if (st->info.n < cnt)
1770 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1773 case EVAS_CALLBACK_MOUSE_DOWN:
1774 case EVAS_CALLBACK_MULTI_DOWN:
1775 case EVAS_CALLBACK_MOUSE_MOVE:
1776 case EVAS_CALLBACK_MULTI_MOVE:
1779 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1780 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1781 (wd->glayer_continues_enable)) /* start also on MOVE */
1782 { /* We start on MOVE when cont-enabled only */
1783 st->line_st.x = st->line_end.x = pe_local.x;
1784 st->line_st.y = st->line_end.y = pe_local.y;
1785 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1786 st->xdir = st->ydir = 0;
1787 st->info.x2 = st->info.x1 = pe_local.x;
1788 st->info.y2 = st->info.y1 = pe_local.y;
1789 st->info.tx = st->info.ty = pe_local.timestamp;
1790 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1791 &st->info, EINA_FALSE);
1792 consume_event(wd, event_info, event_type, ev_flag);
1799 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1801 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1802 state_to_report = ELM_GESTURE_STATE_ABORT;
1804 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1805 { /* Too long of a wait, reset all values */
1806 st->line_st.x = pe_local.x;
1807 st->line_st.y = pe_local.y;
1808 st->t_st_y = st->t_st_x = pe_local.timestamp;
1809 st->info.tx = st->t_st_x;
1810 st->info.ty = st->t_st_y;
1811 st->xdir = st->ydir = 0;
1816 xdir = _get_direction(st->line_st.x, pe_local.x);
1817 ydir = _get_direction(st->line_st.y, pe_local.y);
1818 if (!xdir || (xdir == (-st->xdir)))
1820 st->line_st.x = st->line_end.x;
1821 st->info.tx = st->t_st_x = st->t_end;
1825 if (!ydir || (ydir == (-st->ydir)))
1827 st->line_st.y = st->line_end.y;
1828 st->info.ty = st->t_st_y = st->t_end;
1833 st->info.x2 = st->line_end.x = pe_local.x;
1834 st->info.y2 = st->line_end.y = pe_local.y;
1835 st->t_end = pe_local.timestamp;
1836 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1837 st->t_st_x, st->t_st_y, pe_local.timestamp);
1838 ev_flag = _set_state(gesture, state_to_report, &st->info,
1840 consume_event(wd, event_info, event_type, ev_flag);
1844 case EVAS_CALLBACK_MOUSE_UP:
1845 case EVAS_CALLBACK_MULTI_UP:
1846 st->t_up = pe_local.timestamp; /* Record recent up event time */
1847 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1848 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1851 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1852 { /* Too long of a wait, reset all values */
1853 st->line_st.x = pe_local.x;
1854 st->line_st.y = pe_local.y;
1855 st->t_st_y = st->t_st_x = pe_local.timestamp;
1856 st->xdir = st->ydir = 0;
1859 st->info.x2 = pe_local.x;
1860 st->info.y2 = pe_local.y;
1861 st->line_end.x = pe_local.x;
1862 st->line_end.y = pe_local.y;
1863 st->t_end = pe_local.timestamp;
1865 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1866 st->t_st_x, st->t_st_y, pe_local.timestamp);
1868 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
1869 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
1870 state_to_report = ELM_GESTURE_STATE_END;
1872 state_to_report = ELM_GESTURE_STATE_ABORT;
1874 ev_flag = _set_state(gesture, state_to_report, &st->info,
1876 consume_event(wd, event_info, event_type, ev_flag);
1885 compare_line_device(const void *data1, const void *data2)
1886 { /* Compare device component of line struct */
1887 const Line_Data *ln1 = data1;
1888 const int *device = data2;
1890 if (ln1->t_st) /* Compare only with lines that started */
1891 return (ln1->device - (*device));
1899 * This function construct line struct from input.
1900 * @param info pointer to store line momentum.
1901 * @param st line info to store input data.
1902 * @param pe The recent input event as stored in pe struct.
1904 * @ingroup Elm_Gesture_Layer
1907 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1908 Pointer_Event *pe, Evas_Callback_Type event_type)
1909 { /* Record events and set momentum for line pointed by st */
1915 case EVAS_CALLBACK_MOUSE_DOWN:
1916 case EVAS_CALLBACK_MOUSE_MOVE:
1917 case EVAS_CALLBACK_MULTI_DOWN:
1918 case EVAS_CALLBACK_MULTI_MOVE:
1920 { /* This happens only when line starts */
1921 st->line_st.x = pe->x;
1922 st->line_st.y = pe->y;
1923 st->t_st = pe->timestamp;
1924 st->device = pe->device;
1925 info->momentum.x1 = pe->x;
1926 info->momentum.y1 = pe->y;
1927 info->momentum.tx = pe->timestamp;
1928 info->momentum.ty = pe->timestamp;
1935 case EVAS_CALLBACK_MOUSE_UP:
1936 case EVAS_CALLBACK_MULTI_UP:
1937 /* IGNORE if line info was cleared, like long press, move */
1941 st->line_end.x = pe->x;
1942 st->line_end.y = pe->y;
1943 st->t_end = pe->timestamp;
1952 _line_data_reset(st);
1956 info->momentum.x2 = pe->x;
1957 info->momentum.y2 = pe->y;
1958 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1959 st->t_st, st->t_st, pe->timestamp);
1967 * This function test for (n) line gesture.
1968 * @param obj The gesture-layer object.
1969 * @param pe The recent input event as stored in pe struct.
1970 * @param event_info Original input event pointer.
1971 * @param event_type Type of original input event.
1972 * @param g_type what Gesture we are testing.
1974 * @ingroup Elm_Gesture_Layer
1977 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1978 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1982 Widget_Data *wd = elm_widget_data_get(obj);
1984 Gesture_Info *gesture = wd->gesture[g_type];
1985 if (!gesture ) return;
1987 /* When continues enable = TRUE a gesture may START on MOVE event */
1988 /* We don't allow this to happen with the if-statement below. */
1989 /* When continues enable = FALSE a gesture may START on DOWN only */
1990 /* Therefor it would NOT start on MOVE event. */
1991 /* NOTE that touched list is updated AFTER this function returns */
1992 /* so (count == 0) when we get here on first touch on surface. */
1993 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1994 return; /* Got move on mouse-over move */
1996 Line_Type *st = gesture->data;
1999 st = calloc(1, sizeof(Line_Type));
2003 Line_Data *line = NULL;
2004 Eina_List *list = st->list;
2005 unsigned cnt = eina_list_count(list);
2008 { /* list is not empty, locate this device on list */
2009 line = (Line_Data *) eina_list_search_unsorted(st->list,
2010 compare_line_device, &pe->device);
2014 { /* List is empty or device not found, new line-struct on START only */
2015 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2016 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2017 ((wd->glayer_continues_enable) && /* START on MOVE also */
2018 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2019 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2020 { /* Allocate new item on START only */
2021 line = calloc(1, sizeof(Line_Data));
2022 _line_data_reset(line);
2023 list = eina_list_append(list, line);
2028 if (!line) /* This may happen on MOVE that comes before DOWN */
2029 return; /* No line-struct to work with, can't continue testing */
2031 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2032 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2034 /* Get direction and magnitude of the line */
2036 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2037 &line->line_length, &angle);
2039 /* These are used later to compare lines length */
2040 Evas_Coord shortest_line_len = line->line_length;
2041 Evas_Coord longest_line_len = line->line_length;
2042 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2044 /* Now update line-state */
2046 { /* Analyze line only if line started */
2047 if (line->line_angle >= 0.0)
2048 { /* if line direction was set, we test if broke tolerance */
2049 double a = fabs(angle - line->line_angle);
2051 double d = (tan(a)) * line->line_length; /* Distance from line */
2052 #if defined(DEBUG_GESTURE_LAYER)
2053 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2055 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2056 { /* Broke tolerance: abort line and start a new one */
2057 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2058 &st->info, EINA_FALSE);
2059 consume_event(wd, event_info, event_type, ev_flag);
2063 if (wd->glayer_continues_enable)
2064 { /* We may finish line if momentum is zero */
2065 /* This is for continues-gesture */
2066 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2067 { /* Finish line on zero momentum for continues gesture */
2068 line->line_end.x = pe->x;
2069 line->line_end.y = pe->y;
2070 line->t_end = pe->timestamp;
2075 { /* Record the line angle as it broke minimum length for line */
2076 if (line->line_length >= wd->line_min_length)
2077 st->info.angle = line->line_angle = angle;
2083 if (line->line_angle < 0.0)
2084 { /* it's not a line, too short more close to a tap */
2085 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2086 &st->info, EINA_FALSE);
2087 consume_event(wd, event_info, event_type, ev_flag);
2093 /* Count how many lines already started / ended */
2096 unsigned int tm_start = pe->timestamp;
2097 unsigned int tm_end = pe->timestamp;
2100 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2101 Eina_Bool lines_parallel = EINA_TRUE;
2102 EINA_LIST_FOREACH(list, l, t_line)
2105 base_angle = t_line->line_angle;
2108 if (t_line->line_angle >= 0)
2109 { /* Compare angle only with lines with direction defined */
2110 if (fabs(base_angle - t_line->line_angle) >
2111 wd->line_angular_tolerance)
2112 lines_parallel = EINA_FALSE;
2116 if (t_line->line_length)
2117 { /* update only if this line is used */
2118 if (shortest_line_len > t_line->line_length)
2119 shortest_line_len = t_line->line_length;
2121 if (longest_line_len < t_line->line_length)
2122 longest_line_len = t_line->line_length;
2128 if (t_line->t_st < tm_start)
2129 tm_start = t_line->t_st;
2135 if (t_line->t_end < tm_end)
2136 tm_end = t_line->t_end;
2140 st->info.momentum.n = started;
2144 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2145 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2146 { /* user lift one finger then starts again without line-end - ABORT */
2147 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2149 consume_event(wd, event_info, event_type, ev_flag);
2153 if (!lines_parallel)
2154 { /* Lines are NOT at same direction, abort this gesture */
2155 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2157 consume_event(wd, event_info, event_type, ev_flag);
2162 /* We report ABORT if lines length are NOT matching when fingers are up */
2163 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2165 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2167 consume_event(wd, event_info, event_type, ev_flag);
2171 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2172 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2173 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2175 consume_event(wd, event_info, event_type, ev_flag);
2181 case EVAS_CALLBACK_MOUSE_UP:
2182 case EVAS_CALLBACK_MULTI_UP:
2183 if ((started) && (started == ended))
2185 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2186 &st->info, EINA_FALSE);
2187 consume_event(wd, event_info, event_type, ev_flag);
2192 case EVAS_CALLBACK_MOUSE_DOWN:
2193 case EVAS_CALLBACK_MULTI_DOWN:
2194 case EVAS_CALLBACK_MOUSE_MOVE:
2195 case EVAS_CALLBACK_MULTI_MOVE:
2198 if (wd->glayer_continues_enable && (started == ended))
2199 { /* For continues gesture */
2200 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2201 &st->info, EINA_FALSE);
2202 consume_event(wd, event_info, event_type, ev_flag);
2205 { /* When continues, may START on MOVE event too */
2206 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2208 /* This happens when: on n > 1 lines then one finger up */
2209 /* caused abort, then put finger down. */
2210 /* This will stop line from starting again. */
2211 /* Number of lines, MUST match touched-device in list */
2212 if ((!wd->glayer_continues_enable) &&
2213 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2214 s = ELM_GESTURE_STATE_ABORT;
2216 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2217 s = ELM_GESTURE_STATE_START;
2219 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2220 consume_event(wd, event_info, event_type, ev_flag);
2226 return; /* Unhandeld event type */
2233 * This function is used to check if rotation gesture started.
2234 * @param st Contains current rotation values from user input.
2235 * @return TRUE/FALSE if we need to set rotation START.
2237 * @ingroup Elm_Gesture_Layer
2240 rotation_broke_tolerance(Rotate_Type *st)
2242 if (st->info.base_angle < 0)
2243 return EINA_FALSE; /* Angle has to be computed first */
2245 if (st->rotate_angular_tolerance < 0)
2248 double low = st->info.base_angle - st->rotate_angular_tolerance;
2249 double high = st->info.base_angle + st->rotate_angular_tolerance;
2250 double t = st->info.angle;
2263 if (high > RAD_360DEG)
2274 #if defined(DEBUG_GESTURE_LAYER)
2275 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2277 if ((t < low) || (t > high))
2278 { /* This marks that roation action has started */
2279 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2280 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2290 * This function is used for computing the gap between fingers.
2291 * It returns the length and center point between fingers.
2293 * @param x1 first finger x location.
2294 * @param y1 first finger y location.
2295 * @param x2 second finger x location.
2296 * @param y2 second finger y location.
2297 * @param x Gets center point x cord (output)
2298 * @param y Gets center point y cord (output)
2300 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2302 * @ingroup Elm_Gesture_Layer
2305 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2306 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2308 double a, b, xx, yy, gap;
2311 gap = sqrt(xx*xx + yy*yy);
2313 /* START - Compute zoom center point */
2314 /* The triangle defined as follows:
2322 * http://en.wikipedia.org/wiki/Trigonometric_functions
2323 *************************************/
2324 if (((int) xx) && ((int) yy))
2326 double A = atan((yy / xx));
2327 #if defined(DEBUG_GESTURE_LAYER)
2328 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2330 a = (Evas_Coord) ((gap / 2) * sin(A));
2331 b = (Evas_Coord) ((gap / 2) * cos(A));
2332 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2333 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2338 { /* horiz line, take half width */
2339 #if defined(DEBUG_GESTURE_LAYER)
2340 printf("==== HORIZ ====\n");
2342 *x = (Evas_Coord) (xx / 2);
2343 *y = (Evas_Coord) (y1);
2347 { /* vert line, take half width */
2348 #if defined(DEBUG_GESTURE_LAYER)
2349 printf("==== VERT ====\n");
2351 *x = (Evas_Coord) (x1);
2352 *y = (Evas_Coord) (yy / 2);
2355 /* END - Compute zoom center point */
2357 return (Evas_Coord) gap;
2363 * This function is used for computing zoom value.
2365 * @param st Pointer to zoom data based on user input.
2366 * @param tm_end Recent input event timestamp.
2367 * @param zoom_val Current computed zoom value.
2369 * @return zoom momentum
2371 * @ingroup Elm_Gesture_Layer
2374 _zoom_momentum_get(Zoom_Type *st, unsigned int tm_end, double zoom_val)
2376 unsigned int tm_total;
2379 { /* if direction was already defined, check if changed */
2380 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2381 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2382 { /* Direction changed, reset momentum */
2384 st->dir = (-st->dir);
2388 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2392 st->m_st_tm = tm_end;
2393 st->m_base = zoom_val;
2396 tm_total = tm_end - st->m_st_tm;
2399 return (((zoom_val / st->m_base) - 1.0) * 1000) / tm_total;
2407 * This function is used for computing zoom value.
2409 * @param st Pointer to zoom data based on user input.
2410 * @param x1 first finger x location.
2411 * @param y1 first finger y location.
2412 * @param x2 second finger x location.
2413 * @param y2 second finger y location.
2414 * @param factor zoom-factor, used to determine how fast zoom works.
2416 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2418 * @ingroup Elm_Gesture_Layer
2421 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1,
2422 Evas_Coord x2, Evas_Coord y2, double zoom_finger_factor)
2425 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2426 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2428 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2429 &st->info.x, &st->info.y);
2431 st->info.radius = diam / 2;
2435 st->zoom_base = diam;
2436 return st->info.zoom;
2439 if (st->zoom_distance_tolerance)
2440 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2441 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2442 { /* avoid jump with zoom value when break tolerance */
2443 st->zoom_base -= st->zoom_distance_tolerance;
2444 st->zoom_distance_tolerance = 0;
2447 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2448 { /* avoid jump with zoom value when break tolerance */
2449 st->zoom_base += st->zoom_distance_tolerance;
2450 st->zoom_distance_tolerance = 0;
2456 /* We use factor only on the difference between gap-base */
2457 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2458 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2459 (float) st->zoom_base) * zoom_finger_factor));
2461 /* Momentum: zoom per second: */
2462 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
2470 * This function handles zoom with mouse wheel.
2471 * thats a combination of wheel + CTRL key.
2472 * @param obj The gesture-layer object.
2473 * @param event_info Original input event pointer.
2474 * @param event_type Type of original input event.
2475 * @param g_type what Gesture we are testing.
2477 * @ingroup Elm_Gesture_Layer
2480 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2481 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2483 Widget_Data *wd = elm_widget_data_get(obj);
2485 if (!wd->gesture[g_type]) return;
2487 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2488 Zoom_Type *st = gesture_zoom->data;
2489 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2491 { /* Allocated once on first time, used for zoom intermediate data */
2492 st = calloc(1, sizeof(Zoom_Type));
2493 gesture_zoom->data = st;
2494 _zoom_test_reset(gesture_zoom);
2499 case EVAS_CALLBACK_KEY_UP:
2501 Evas_Event_Key_Up *p = event_info;
2502 if ((!strcmp(p->keyname, "Control_L")) ||
2503 (!strcmp(p->keyname, "Control_R")))
2504 { /* Test if we ended a zoom gesture when releasing CTRL */
2505 if ((st->zoom_wheel) &&
2506 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2507 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2508 { /* User released CTRL after zooming */
2509 ev_flag = _set_state(gesture_zoom,
2510 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2511 consume_event(wd, event_info, event_type, ev_flag);
2519 case EVAS_CALLBACK_MOUSE_WHEEL:
2522 Elm_Gesture_State s;
2523 if (!evas_key_modifier_is_set(
2524 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2526 { /* if using wheel witout CTRL after starting zoom */
2527 if ((st->zoom_wheel) &&
2528 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2529 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2531 ev_flag = _set_state(gesture_zoom,
2532 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2533 consume_event(wd, event_info, event_type, ev_flag);
2538 return; /* Ignore mouse-wheel without control */
2541 /* Using mouse wheel with CTRL for zoom */
2542 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2543 { /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2544 we continue a zoom gesture */
2546 s = ELM_GESTURE_STATE_MOVE;
2549 { /* On first wheel event, report START */
2550 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2551 evas_object_evas_get(wd->target), "Control");
2553 s = ELM_GESTURE_STATE_START;
2554 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2555 ERR("Failed to Grabbed CTRL_L");
2556 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2557 ERR("Failed to Grabbed CTRL_R");
2560 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2561 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2562 st->info.x = st->zoom_wheel->canvas.x;
2563 st->info.y = st->zoom_wheel->canvas.y;
2565 if (st->zoom_wheel->z < 0) /* zoom in */
2566 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2568 if (st->zoom_wheel->z > 0) /* zoom out */
2569 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2571 if (st->info.zoom < 0.0)
2572 st->info.zoom = 0.0;
2574 st->info.momentum = _zoom_momentum_get(st,
2575 st->zoom_wheel->timestamp, st->info.zoom);
2577 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2578 consume_event(wd, event_info, event_type, ev_flag);
2590 * This function is used to test zoom gesture.
2591 * user may combine zoom, rotation together.
2592 * so its possible that both will be detected from input.
2593 * (both are two-finger movement-oriented gestures)
2595 * @param obj The gesture-layer object.
2596 * @param event_info Pointer to recent input event.
2597 * @param event_type Recent input event type.
2598 * @param g_type what Gesture we are testing.
2600 * @ingroup Elm_Gesture_Layer
2603 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2604 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2608 Widget_Data *wd = elm_widget_data_get(obj);
2610 if (!wd->gesture[g_type]) return;
2612 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2613 Zoom_Type *st = gesture_zoom->data;
2616 { /* Allocated once on first time, used for zoom data */
2617 st = calloc(1, sizeof(Zoom_Type));
2618 gesture_zoom->data = st;
2619 _zoom_test_reset(gesture_zoom);
2623 /* Start - new zoom testing, letting all fingers start */
2624 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2627 case EVAS_CALLBACK_MOUSE_MOVE:
2628 case EVAS_CALLBACK_MULTI_MOVE:
2629 /* if non-continues mode and gesture NOT started, ignore MOVE */
2630 if ((!wd->glayer_continues_enable) &&
2631 (!st->zoom_st.timestamp))
2634 case EVAS_CALLBACK_MOUSE_DOWN:
2635 case EVAS_CALLBACK_MULTI_DOWN:
2636 { /* Here we take care of zoom-start and zoom move */
2640 if(eina_list_count(wd->touched) > 2)
2641 { /* Process zoom only when 2 fingers on surface */
2642 ev_flag = _set_state(gesture_zoom,
2643 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2644 consume_event(wd, event_info, event_type, ev_flag);
2649 if (!st->zoom_st.timestamp)
2650 { /* Now scan touched-devices list and find other finger */
2651 EINA_LIST_FOREACH(wd->touched, l, p)
2652 { /* Device of other finger <> pe device */
2653 if (p->device != pe->device)
2657 if (!p) /* Single finger on touch */
2660 /* Record down fingers */
2661 consume_event(wd, event_info, event_type, ev_flag);
2662 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2663 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2665 /* Set mv field as well to be ready for MOVE events */
2666 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2667 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2669 /* Here we have zoom_st, zoom_st1 set, report START */
2670 /* Set zoom-base after BOTH down events recorded */
2671 /* Compute length of line between fingers zoom start */
2672 st->info.zoom = 1.0;
2673 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2674 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2675 &st->info.x, &st->info.y);
2677 st->info.radius = st->zoom_base / 2;
2679 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2680 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2681 { /* zoom started with mouse-wheel, don't report twice */
2682 ev_flag = _set_state(gesture_zoom,
2683 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2684 consume_event(wd, event_info, event_type, ev_flag);
2687 return; /* Zoom started */
2688 } /* End of ZOOM_START handling */
2691 /* if we got here, we have (exacally) two fingers on surfce */
2692 /* we also after START, report MOVE */
2693 /* First detect which finger moved */
2694 if (pe->device == st->zoom_mv.device)
2695 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2696 else if (pe->device == st->zoom_mv1.device)
2697 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2699 /* Compute change in zoom as fingers move */
2700 st->info.zoom = compute_zoom(st,
2701 st->zoom_mv.x, st->zoom_mv.y,
2702 st->zoom_mv1.x, st->zoom_mv1.y,
2703 wd->zoom_finger_factor);
2705 if (!st->zoom_distance_tolerance)
2706 { /* Zoom broke tolerance, report move */
2707 double d = st->info.zoom - st->next_step;
2711 if (d >= wd->zoom_step)
2712 { /* Report move in steps */
2713 st->next_step = st->info.zoom;
2715 ev_flag = _set_state(gesture_zoom,
2716 ELM_GESTURE_STATE_MOVE,
2717 &st->info, EINA_TRUE);
2718 consume_event(wd, event_info, event_type, ev_flag);
2720 } /* End of ZOOM_MOVE handling */
2725 case EVAS_CALLBACK_MOUSE_UP:
2726 case EVAS_CALLBACK_MULTI_UP:
2727 /* Reset timestamp of finger-up.This is used later
2728 by _zoom_test_reset() to retain finger-down data */
2729 consume_event(wd, event_info, event_type, ev_flag);
2730 if (((st->zoom_wheel) || (st->zoom_base)) &&
2731 (st->zoom_distance_tolerance == 0))
2733 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2734 &st->info, EINA_FALSE);
2735 consume_event(wd, event_info, event_type, ev_flag);
2740 /* if we got here not a ZOOM */
2741 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2742 { /* Must be != undefined, if gesture started */
2743 ev_flag = _set_state(gesture_zoom,
2744 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2745 consume_event(wd, event_info, event_type, ev_flag);
2748 _zoom_test_reset(gesture_zoom);
2758 _get_rotate_properties(Rotate_Type *st,
2759 Evas_Coord x1, Evas_Coord y1,
2760 Evas_Coord x2, Evas_Coord y2,
2763 double prev_angle = *angle;
2764 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2765 &st->info.x, &st->info.y) / 2;
2767 *angle = get_angle(x1, y1, x2, y2);
2769 if (angle == &st->info.angle)
2770 { /* Fingers are moving, compute momentum */
2771 unsigned int tm_start =
2772 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
2773 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
2774 unsigned int tm_end =
2775 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
2776 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
2778 unsigned int tm_total = tm_end - tm_start;
2780 { /* Momentum computed as:
2781 accumulated roation angle (rad) divided by time */
2783 if ((prev_angle >= RAD_270DEG) && ((*angle) < RAD_180DEG))
2784 { /* We circle passing ZERO point */
2785 m = (RAD_360DEG - prev_angle) + (*angle);
2787 else m = (*angle) - prev_angle;
2789 st->accum_momentum += m;
2791 if ((tm_end - st->prev_momentum_tm) < 100)
2792 st->prev_momentum += m;
2795 if (fabs(st->prev_momentum) < 0.002)
2796 st->accum_momentum = 0.0; /* reset momentum */
2798 st->prev_momentum = 0.0; /* Start again */
2799 st->prev_momentum_tm = tm_end;
2802 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
2806 st->info.momentum = 0;
2812 * This function is used to test rotation gesture.
2813 * user may combine zoom, rotation together.
2814 * so its possible that both will be detected from input.
2815 * (both are two-finger movement-oriented gestures)
2817 * @param obj The gesture-layer object.
2818 * @param event_info Pointer to recent input event.
2819 * @param event_type Recent input event type.
2820 * @param g_type what Gesture we are testing.
2822 * @ingroup Elm_Gesture_Layer
2825 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2826 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2831 Widget_Data *wd = elm_widget_data_get(obj);
2833 if (!wd->gesture[g_type]) return;
2835 Gesture_Info *gesture = wd->gesture[g_type];
2841 { /* Allocated once on first time */
2842 st = calloc(1, sizeof(Rotate_Type));
2844 _rotate_test_reset(gesture);
2848 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2851 case EVAS_CALLBACK_MOUSE_MOVE:
2852 case EVAS_CALLBACK_MULTI_MOVE:
2853 /* if non-continues mode and gesture NOT started, ignore MOVE */
2854 if ((!wd->glayer_continues_enable) &&
2855 (!st->rotate_st.timestamp))
2858 case EVAS_CALLBACK_MOUSE_DOWN:
2859 case EVAS_CALLBACK_MULTI_DOWN:
2860 { /* Here we take care of rotate-start and rotate move */
2864 if(eina_list_count(wd->touched) > 2)
2865 { /* Process rotate only when 2 fingers on surface */
2866 ev_flag = _set_state(gesture,
2867 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2868 consume_event(wd, event_info, event_type, ev_flag);
2873 if (!st->rotate_st.timestamp)
2874 { /* Now scan touched-devices list and find other finger */
2875 EINA_LIST_FOREACH(wd->touched, l, p)
2876 { /* Device of other finger <> pe device */
2877 if (p->device != pe->device)
2882 return; /* Single finger on touch */
2884 /* Record down fingers */
2885 consume_event(wd, event_info, event_type, ev_flag);
2886 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2887 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2889 /* Set mv field as well to be ready for MOVE events */
2890 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2891 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2893 /* Here we have rotate_st, rotate_st1 set, report START */
2894 /* Set rotate-base after BOTH down events recorded */
2895 /* Compute length of line between fingers rotate start */
2896 _get_rotate_properties(st,
2897 st->rotate_st.x, st->rotate_st.y,
2898 st->rotate_st1.x, st->rotate_st1.y,
2899 &st->info.base_angle);
2901 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2902 &st->info, EINA_FALSE);
2903 consume_event(wd, event_info, event_type, ev_flag);
2905 return; /* Rotate started */
2906 } /* End of ROTATE_START handling */
2909 /* if we got here, we have (exacally) two fingers on surfce */
2910 /* we also after START, report MOVE */
2911 /* First detect which finger moved */
2912 if (pe->device == st->rotate_mv.device)
2913 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2914 else if (pe->device == st->rotate_mv1.device)
2915 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2917 /* Compute change in rotate as fingers move */
2918 _get_rotate_properties(st,
2919 st->rotate_mv.x, st->rotate_mv.y,
2920 st->rotate_mv1.x, st->rotate_mv1.y,
2923 if (rotation_broke_tolerance(st))
2924 { /* Rotation broke tolerance, report move */
2925 double d = st->info.angle - st->next_step;
2929 if (d >= wd->rotate_step)
2930 { /* Report move in steps */
2931 st->next_step = st->info.angle;
2933 ev_flag = _set_state(gesture,
2934 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2935 consume_event(wd, event_info, event_type, ev_flag);
2937 } /* End of ROTATE_MOVE handling */
2942 case EVAS_CALLBACK_MOUSE_UP:
2943 case EVAS_CALLBACK_MULTI_UP:
2944 consume_event(wd, event_info, event_type, ev_flag);
2945 /* Reset timestamp of finger-up.This is used later
2946 by rotate_test_reset() to retain finger-down data */
2947 if (st->rotate_angular_tolerance < 0)
2949 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2950 &st->info, EINA_FALSE);
2951 consume_event(wd, event_info, event_type, ev_flag);
2956 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2957 { /* Must be != undefined, if gesture started */
2958 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2959 &st->info, EINA_FALSE);
2960 consume_event(wd, event_info, event_type, ev_flag);
2963 _rotate_test_reset(gesture);
2974 * This function is used to save input events in an abstract struct
2975 * to be used later by getsure-testing functions.
2977 * @param data The gesture-layer object.
2978 * @param event_info Pointer to recent input event.
2979 * @param event_type Recent input event type.
2980 * @param pe The abstract data-struct (output).
2982 * @ingroup Elm_Gesture_Layer
2985 _make_pointer_event(void *data, void *event_info,
2986 Evas_Callback_Type event_type, Pointer_Event *pe)
2988 Widget_Data *wd = elm_widget_data_get(data);
2989 if (!wd) return EINA_FALSE;
2991 memset(pe, '\0', sizeof(*pe));
2994 case EVAS_CALLBACK_MOUSE_DOWN:
2995 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2996 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2997 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2998 pe->device = ELM_MOUSE_DEVICE;
3001 case EVAS_CALLBACK_MOUSE_UP:
3002 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
3003 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
3004 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
3005 pe->device = ELM_MOUSE_DEVICE;
3008 case EVAS_CALLBACK_MOUSE_MOVE:
3009 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
3010 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
3011 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
3012 pe->device = ELM_MOUSE_DEVICE;
3015 case EVAS_CALLBACK_MULTI_DOWN:
3016 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
3017 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
3018 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
3019 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
3022 case EVAS_CALLBACK_MULTI_UP:
3023 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
3024 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
3025 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
3026 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
3029 case EVAS_CALLBACK_MULTI_MOVE:
3030 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
3031 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
3032 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
3033 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
3040 pe->event_type = event_type;
3047 * This function restartes line, flick, zoom and rotate gestures
3048 * when gesture-layer continues-gestures enabled.
3049 * Example of continues-gesture:
3050 * When doing a line, user stops moving finger but keeps fingers on touch.
3051 * This will cause line-end, then as user continues moving his finger
3052 * it re-starts line gesture.
3053 * When continue mode is disabled, user has to lift finger from touch
3054 * to end a gesture. Them touch-again to start a new one.
3056 * @param data The gesture-layer object.
3057 * @param wd gesture layer widget data.
3058 * @param states_reset flag that marks gestures were reset in history clear.
3060 * @ingroup Elm_Gesture_Layer
3062 void continues_gestures_restart(void *data, Eina_Bool states_reset)
3064 Widget_Data *wd = elm_widget_data_get(data);
3067 /* Run through events to restart gestures */
3069 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
3070 /* We turn-on flag for finished, aborted, not-started gestures */
3071 g = wd->gesture[ELM_GESTURE_MOMENTUM];
3072 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3073 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3076 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
3077 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3081 g = wd->gesture[ELM_GESTURE_N_LINES];
3082 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3083 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3086 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3087 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3091 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3092 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3093 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3096 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3097 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3101 g = wd->gesture[ELM_GESTURE_ZOOM];
3102 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3103 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3106 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3107 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3111 g = wd->gesture[ELM_GESTURE_ROTATE];
3112 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3113 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3116 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3117 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3125 * This function the core-function where input handling is done.
3126 * Here we get user input and stream it to gesture testing.
3127 * We notify user about any gestures with new state:
3129 * START - gesture started.
3130 * MOVE - gesture is ongoing.
3131 * END - gesture was completed.
3132 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3134 * We also check if a gesture was detected, then reset event history
3135 * If no gestures were found we reset gesture test flag
3136 * after streaming event-history to widget.
3137 * (stream to the widget all events not consumed as a gesture)
3139 * @param data The gesture-layer object.
3140 * @param event_info Pointer to recent input event.
3141 * @param event_type Recent input event type.
3143 * @ingroup Elm_Gesture_Layer
3146 _event_process(void *data, Evas_Object *obj __UNUSED__,
3147 void *event_info, Evas_Callback_Type event_type)
3150 Pointer_Event *pe = NULL;
3151 Widget_Data *wd = elm_widget_data_get(data);
3154 #if defined(DEBUG_GESTURE_LAYER)
3157 printf("Gesture | State | is tested\n");
3158 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3162 printf(" %d %d %d\n", i, g->state, g->test);
3166 /* Start testing candidate gesture from here */
3167 if (_make_pointer_event(data, event_info, event_type, &_pe))
3170 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3171 _n_long_tap_test(data, pe, event_info, event_type,
3172 ELM_GESTURE_N_LONG_TAPS);
3174 /* This takes care of single, double and tripple tap */
3175 _tap_gestures_test(data, pe, event_info, event_type);
3177 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3178 _momentum_test(data, pe, event_info, event_type,
3179 ELM_GESTURE_MOMENTUM);
3181 if (IS_TESTED(ELM_GESTURE_N_LINES))
3182 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3184 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3185 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3187 if (_elm_config->glayer_zoom_finger_enable && IS_TESTED(ELM_GESTURE_ZOOM))
3188 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3190 if (IS_TESTED(ELM_GESTURE_ZOOM))
3191 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3193 if (_elm_config->glayer_rotate_finger_enable && IS_TESTED(ELM_GESTURE_ROTATE))
3194 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3196 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3197 _event_history_add(data, event_info, event_type);
3198 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3199 (event_type == EVAS_CALLBACK_MULTI_UP))
3201 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3204 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3205 _event_history_add(data, event_info, event_type);
3209 /* we maintain list of touched devices */
3210 /* We also use move to track current device x.y pos */
3211 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3212 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3213 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3214 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3216 wd->touched = _add_touched_device(wd->touched, pe);
3218 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3219 (event_type == EVAS_CALLBACK_MULTI_UP))
3221 wd->touched = _remove_touched_device(wd->touched, pe);
3224 /* Report current states and clear history if needed */
3225 Eina_Bool states_reset = _clear_if_finished(data);
3226 if (wd->glayer_continues_enable)
3227 continues_gestures_restart(data, states_reset);
3232 * For all _mouse_* / multi_* functions wethen send this event to
3233 * _event_process function.
3235 * @param data The gesture-layer object.
3236 * @param event_info Pointer to recent input event.
3238 * @ingroup Elm_Gesture_Layer
3241 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3244 Widget_Data *wd = elm_widget_data_get(data);
3246 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3247 return; /* We only process left-click at the moment */
3249 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3253 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3256 Widget_Data *wd = elm_widget_data_get(data);
3259 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3263 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3266 Widget_Data *wd = elm_widget_data_get(data);
3269 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3273 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3276 Widget_Data *wd = elm_widget_data_get(data);
3279 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3283 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3286 Widget_Data *wd = elm_widget_data_get(data);
3289 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3290 return; /* We only process left-click at the moment */
3292 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3296 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3299 Widget_Data *wd = elm_widget_data_get(data);
3302 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3306 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3309 Widget_Data *wd = elm_widget_data_get(data);
3312 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3316 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3319 Widget_Data *wd = elm_widget_data_get(data);
3322 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3326 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3329 Widget_Data *wd = elm_widget_data_get(data);
3332 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3336 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3338 Widget_Data *wd = elm_widget_data_get(obj);
3339 if (!wd) return EINA_FALSE;
3341 return !wd->repeat_events;
3345 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3347 Widget_Data *wd = elm_widget_data_get(obj);
3350 wd->repeat_events = !r;
3354 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3356 Widget_Data *wd = elm_widget_data_get(obj);
3366 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3368 Widget_Data *wd = elm_widget_data_get(obj);
3374 wd->rotate_step = s;
3378 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3380 Widget_Data *wd = elm_widget_data_get(obj);
3381 if (!wd) return EINA_FALSE;
3386 /* if was attached before, unregister callbacks first */
3388 _unregister_callbacks(obj);
3392 _register_callbacks(obj);
3397 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3398 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3400 Widget_Data *wd = elm_widget_data_get(obj);
3404 if (!wd->gesture[idx])
3405 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3406 if (!wd->gesture[idx]) return;
3408 p = wd->gesture[idx];
3411 p->fn[cb_type].cb = cb;
3412 p->fn[cb_type].user_data = data;
3413 p->state = ELM_GESTURE_STATE_UNDEFINED;
3418 _disable_hook(Evas_Object *obj)
3420 if (elm_widget_disabled_get(obj))
3421 _unregister_callbacks(obj);
3423 _register_callbacks(obj);
3427 elm_gesture_layer_add(Evas_Object *parent)
3433 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3435 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3436 elm_widget_type_set(obj, "gesture_layer");
3437 elm_widget_sub_object_add(parent, obj);
3438 elm_widget_data_set(obj, wd);
3439 elm_widget_del_hook_set(obj, _del_hook);
3440 elm_widget_disable_hook_set(obj, _disable_hook);
3443 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3444 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3445 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3446 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3447 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3448 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3449 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3450 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3451 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3452 wd->repeat_events = EINA_TRUE;
3453 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3455 #if defined(DEBUG_GESTURE_LAYER)
3456 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3457 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);
3459 memset(wd->gesture, 0, sizeof(wd->gesture));