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
11 /* Some Trigo values */
12 #define RAD_90DEG M_PI_2
13 #define RAD_180DEG M_PI
14 #define RAD_270DEG (M_PI_2 * 3)
15 #define RAD_360DEG (M_PI * 2)
16 /* #define DEBUG_GESTURE_LAYER 1 */
19 _glayer_bufdup(void *buf, size_t size)
26 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
29 #define SET_TEST_BIT(P) do { \
30 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; \
33 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
39 * Struct holds callback information.
41 * @ingroup Elm_Gesture_Layer
45 void *user_data; /**< Holds user data to CB (like sd) */
46 Elm_Gesture_Event_Cb cb;
53 * type for callback information
55 * @ingroup Elm_Gesture_Layer
57 typedef struct _Func_Data Func_Data;
62 * @struct _Gesture_Info
63 * Struct holds gesture info
65 * @ingroup Elm_Gesture_Layer
70 void *data; /**< Holds gesture intemidiate processing data */
71 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
72 Elm_Gesture_Types g_type; /**< gesture type */
73 Elm_Gesture_State state; /**< gesture state */
74 void *info; /**< Data for the state callback */
75 Eina_Bool test; /**< if true this gesture should be tested on input */
81 * @typedef Gesture_Info
82 * Type for _Gesture_Info
84 * @ingroup Elm_Gesture_Layer
86 typedef struct _Gesture_Info Gesture_Info;
91 * @struct _Event_History
92 * Struct holds event history.
93 * These events are repeated if no gesture found.
95 * @ingroup Elm_Gesture_Layer
101 Evas_Callback_Type event_type;
107 * @typedef Event_History
108 * Type for _Event_History
110 * @ingroup Elm_Gesture_Layer
112 typedef struct _Event_History Event_History;
117 * @struct _Pointer_Event
118 * Struct holds pointer-event info
119 * This is a generic pointer event structure
121 * @ingroup Elm_Gesture_Layer
123 struct _Pointer_Event
126 unsigned int timestamp;
128 Evas_Callback_Type event_type;
134 * @typedef Pointer_Event
135 * Type for generic pointer event structure
137 * @ingroup Elm_Gesture_Layer
139 typedef struct _Pointer_Event Pointer_Event;
141 /* All *Type structs hold result for the user in 'info' field
142 * The rest is gesture processing intermediate data.
143 * NOTE: info field must be FIRST in the struct.
144 * This is used when reporting ABORT in event_history_clear() */
147 Elm_Gesture_Taps_Info info;
150 unsigned int n_taps_needed;
154 typedef struct _Taps_Type Taps_Type;
156 struct _Long_Tap_Type
158 Elm_Gesture_Taps_Info info;
159 unsigned int center_x;
160 unsigned int center_y;
162 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
165 typedef struct _Long_Tap_Type Long_Tap_Type;
167 struct _Momentum_Type
168 { /* Fields used by _line_test() */
169 Elm_Gesture_Momentum_Info info;
170 Evas_Coord_Point line_st;
171 Evas_Coord_Point line_end;
172 unsigned int t_st_x; /* Time start on X */
173 unsigned int t_st_y; /* Time start on Y */
174 unsigned int t_end; /* Time end */
177 typedef struct _Momentum_Type Momentum_Type;
181 Evas_Coord_Point line_st;
182 Evas_Coord_Point line_end;
183 Evas_Coord line_length;
184 unsigned int t_st; /* Time start */
185 unsigned int t_end; /* Time end */
187 double line_angle; /* Current angle of line */
189 typedef struct _Line_Data Line_Data;
192 { /* Fields used by _line_test() */
193 Elm_Gesture_Line_Info info;
194 Eina_List *list; /* List of Line_Data */
196 typedef struct _Line_Type Line_Type;
199 { /* Fields used by _zoom_test() */
200 Elm_Gesture_Zoom_Info info;
201 Pointer_Event zoom_st;
202 Pointer_Event zoom_mv;
203 Pointer_Event zoom_st1;
204 Pointer_Event zoom_mv1;
205 Evas_Event_Mouse_Wheel *zoom_wheel;
206 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
207 Evas_Coord zoom_distance_tolerance;
208 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
209 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
212 typedef struct _Zoom_Type Zoom_Type;
215 { /* Fields used by _rotation_test() */
216 Elm_Gesture_Rotate_Info info;
217 Pointer_Event rotate_st;
218 Pointer_Event rotate_mv;
219 Pointer_Event rotate_st1;
220 Pointer_Event rotate_mv1;
221 double rotate_angular_tolerance;
223 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
224 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
226 typedef struct _Rotate_Type Rotate_Type;
230 Evas_Object *target; /* Target Widget */
231 Event_History *event_history_list;
234 Evas_Coord zoom_distance_tolerance;
235 Evas_Coord line_distance_tolerance;
236 double line_angular_tolerance;
237 double zoom_wheel_factor; /* mouse wheel zoom steps */
238 double zoom_finger_factor; /* used for zoom factor */
239 double rotate_angular_tolerance;
240 unsigned int flick_time_limit_ms;
241 double long_tap_start_timeout;
242 Eina_Bool glayer_continues_enable;
247 Gesture_Info *gesture[ELM_GESTURE_LAST];
248 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
249 Eina_List *pending; /* List of devices need to refeed *UP event */
250 Eina_List *touched; /* Information of touched devices */
251 Eina_List *recent_device_event; /* Information of recent pe event of each device */
253 Eina_Bool repeat_events : 1;
255 typedef struct _Widget_Data Widget_Data;
257 static const char *widtype = NULL;
258 static void _del_hook(Evas_Object *obj);
260 static Eina_Bool _event_history_clear(Evas_Object *obj);
261 static void _reset_states(Widget_Data *wd);
262 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
263 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
264 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
265 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
266 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
267 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
268 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
270 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
271 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
272 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
274 /* START - Functions to manage touched-device list */
277 * This function is used to find if device is touched
279 * @ingroup Elm_Gesture_Layer
282 compare_device(const void *data1, const void *data2)
283 { /* Compare the two device numbers */
284 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
290 * Remove Pointer Event from touched device list
291 * @param list Pointer to touched device list.
292 * @param Pointer_Event Pointer to PE.
294 * @ingroup Elm_Gesture_Layer
297 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
299 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
303 return eina_list_remove(list, p);
312 * Recoed Pointer Event in touched device list
313 * Note: This fuction allocates memory for PE event
314 * This memory is released in _remove_touched_device()
315 * @param list Pointer to touched device list.
316 * @param Pointer_Event Pointer to PE.
318 * @ingroup Elm_Gesture_Layer
321 _add_touched_device(Eina_List *list, Pointer_Event *pe)
323 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
325 { /* We like to track device touch-position, overwrite info */
326 memcpy(p, pe, sizeof(Pointer_Event));
330 p = malloc(sizeof(Pointer_Event));
331 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
332 return eina_list_append(list, p);
334 /* END - Functions to manage touched-device list */
336 /* START - Functions to manage recent device event list */
337 /* This list holds the recent-event for each device */
338 /* it will hold a single recent-event for each device */
339 /* We are using those PE events of this list to */
340 /* send them later to test funcs to restart gestures */
341 /* We only keep DOWN, MOVE events in this list. */
342 /* So when no touch this list is empty. */
346 * Recoed Pointer Event in touched device list
347 * Note: This fuction allocates memory for PE event
348 * This memory is released here when device untouched
350 * @param list Pointer to touched device list.
351 * @param Pointer_Event Pointer to PE.
353 * @ingroup Elm_Gesture_Layer
356 _add_recent_device_event(Eina_List *list, Pointer_Event *pe)
358 void *data = eina_list_search_sorted(list, compare_device, pe);
360 Pointer_Event *p = NULL;
361 if(data) /* First remove recent event for this device */
362 l = eina_list_remove(list, data);
365 switch(pe->event_type)
367 case EVAS_CALLBACK_MOUSE_DOWN:
368 case EVAS_CALLBACK_MOUSE_MOVE:
369 case EVAS_CALLBACK_MULTI_DOWN:
370 case EVAS_CALLBACK_MULTI_MOVE:
371 p = malloc(sizeof(Pointer_Event));
372 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in here or on cleanup */
373 l = eina_list_sorted_insert(l, compare_device, p);
376 /* Kept those cases for referance */
377 case EVAS_CALLBACK_MOUSE_IN:
378 case EVAS_CALLBACK_MOUSE_OUT:
379 case EVAS_CALLBACK_MOUSE_WHEEL:
380 case EVAS_CALLBACK_MOUSE_UP:
381 case EVAS_CALLBACK_MULTI_UP:
382 case EVAS_CALLBACK_KEY_DOWN:
383 case EVAS_CALLBACK_KEY_UP:
392 /* END - Functions to manage recent device event list */
398 * @param event_info pointer to event.
400 * @ingroup Elm_Gesture_Layer
402 static Evas_Event_Flags
403 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
407 case EVAS_CALLBACK_MOUSE_IN:
408 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
409 case EVAS_CALLBACK_MOUSE_OUT:
410 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
411 case EVAS_CALLBACK_MOUSE_DOWN:
412 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
413 case EVAS_CALLBACK_MOUSE_MOVE:
414 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
415 case EVAS_CALLBACK_MOUSE_UP:
416 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
417 case EVAS_CALLBACK_MOUSE_WHEEL:
418 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
419 case EVAS_CALLBACK_MULTI_DOWN:
420 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
421 case EVAS_CALLBACK_MULTI_MOVE:
422 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
423 case EVAS_CALLBACK_MULTI_UP:
424 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
425 case EVAS_CALLBACK_KEY_DOWN:
426 return ((Evas_Event_Key_Down *) event_info)->event_flags;
427 case EVAS_CALLBACK_KEY_UP:
428 return ((Evas_Event_Key_Up *) event_info)->event_flags;
430 return EVAS_EVENT_FLAG_NONE;
437 * Sets event flag to value returned from user callback
438 * @param wd Widget Data
439 * @param event_info pointer to event.
440 * @param event_type what type was ev (mouse down, etc...)
441 * @param ev_flags event flags
443 * @ingroup Elm_Gesture_Layer
446 consume_event(Widget_Data *wd, void *event_info,
447 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
448 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
449 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
450 /* should not refeed this event. */
452 return; /* This happens when restarting gestures */
454 if ((ev_flags) || (!wd->repeat_events))
458 case EVAS_CALLBACK_MOUSE_DOWN:
459 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
461 case EVAS_CALLBACK_MOUSE_MOVE:
462 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
464 case EVAS_CALLBACK_MOUSE_UP:
465 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
467 case EVAS_CALLBACK_MOUSE_WHEEL:
468 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
470 case EVAS_CALLBACK_MULTI_DOWN:
471 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
473 case EVAS_CALLBACK_MULTI_MOVE:
474 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
476 case EVAS_CALLBACK_MULTI_UP:
477 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
479 case EVAS_CALLBACK_KEY_DOWN:
480 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
482 case EVAS_CALLBACK_KEY_UP:
483 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
494 * Report current state of a gesture by calling user callback.
495 * @param gesture what gesture state we report.
496 * @param info inforamtion for user callback
498 * @ingroup Elm_Gesture_Layer
500 static Evas_Event_Flags
501 _report_state(Gesture_Info *gesture, void *info)
502 { /* We report current state (START, MOVE, END, ABORT), once */
503 #if defined(DEBUG_GESTURE_LAYER)
504 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
507 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
508 (gesture->fn[gesture->state].cb))
509 { /* Fill state-info struct and send ptr to user callback */
510 return gesture->fn[gesture->state].cb(
511 gesture->fn[gesture->state].user_data, info);
514 return EVAS_EVENT_FLAG_NONE;
520 * Update state for a given gesture.
521 * We may update gesture state to:
522 * UNDEFINED - current input did not start gesure yet.
523 * START - gesture started according to input.
524 * MOVE - gusture in progress.
525 * END - gesture completed according to input.
526 * ABORT - input does not matches gesure.
527 * note that we may move from UNDEFINED to ABORT
528 * because we may detect that gesture will not START
529 * with a given input.
531 * @param g given gesture to change state.
532 * @param s gesure new state.
533 * @param info buffer to be sent to user callback on report_state.
534 * @param force makes report_state to report the new-state even
535 * if its same as current state. Works for MOVE - gesture in progress.
537 * @ingroup Elm_Gesture_Layer
539 static Evas_Event_Flags
540 _set_state(Gesture_Info *g, Elm_Gesture_State s,
541 void *info, Eina_Bool force)
543 Elm_Gesture_State old_state;
544 if ((g->state == s) && (!force))
545 return EVAS_EVENT_FLAG_NONE;
547 old_state = g->state;
550 g->info = info; /* Information for user callback */
551 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
552 (g->state == ELM_GESTURE_STATE_END))
553 g->test = EINA_FALSE;
555 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
556 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
557 (s == ELM_GESTURE_STATE_ABORT))))
558 return _report_state(g, g->info);
560 return EVAS_EVENT_FLAG_NONE;
566 * This resets all gesture states and sets test-bit.
567 * this is used for restarting gestures to listen to input.
568 * happens after we complete a gesture or no gesture was detected.
569 * @param wd Widget data of the gesture-layer object.
571 * @ingroup Elm_Gesture_Layer
574 _reset_states(Widget_Data *wd)
578 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
583 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
592 * if gesture was NOT detected AND we only have gestures in ABORT state
593 * we clear history immediately to be ready for input.
595 * @param obj The gesture-layer object.
596 * @return TRUE on event history_clear
598 * @ingroup Elm_Gesture_Layer
601 _clear_if_finished(Evas_Object *obj)
603 Widget_Data *wd = elm_widget_data_get(obj);
604 if (!wd) return EINA_FALSE;
607 /* Clear history if all we have aborted gestures */
608 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
609 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
610 { /* If no gesture started and all we have aborted gestures, reset all */
611 Gesture_Info *p = wd->gesture[i];
612 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
614 if ((p->state == ELM_GESTURE_STATE_START) ||
615 (p->state == ELM_GESTURE_STATE_MOVE))
616 reset_s = EINA_FALSE;
618 all_undefined = EINA_FALSE;
622 if (reset_s && (!all_undefined))
623 return _event_history_clear(obj);
629 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
631 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
647 /* All *test_reset() funcs are called to clear
648 * gesture intermediate data.
649 * This happens when we need to reset our tests.
650 * for example when gesture is detected or all ABORTed. */
652 _tap_gestures_test_reset(Gesture_Info *gesture)
657 Widget_Data *wd = elm_widget_data_get(gesture->obj);
658 wd->dbl_timeout = NULL;
665 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
666 EINA_LIST_FREE(data, pe)
669 memset(gesture->data, 0, sizeof(Taps_Type));
672 /* All *test_reset() funcs are called to clear
673 * gesture intermediate data.
674 * This happens when we need to reset our tests.
675 * for example when gesture is detected or all ABORTed. */
677 _n_long_tap_test_reset(Gesture_Info *gesture)
685 Long_Tap_Type *st = gesture->data;
688 EINA_LIST_FOREACH(st->touched, l, p)
691 eina_list_free(st->touched);
692 if (st->timeout) ecore_timer_del(st->timeout);
693 memset(gesture->data, 0, sizeof(Long_Tap_Type));
697 _momentum_test_reset(Gesture_Info *gesture)
705 memset(gesture->data, 0, sizeof(Momentum_Type));
709 _line_data_reset(Line_Data *st)
714 memset(st, 0, sizeof(Line_Data));
715 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
719 _line_test_reset(Gesture_Info *gesture)
727 Line_Type *st = gesture->data;
728 Eina_List *list = st->list;
731 EINA_LIST_FOREACH(list, l, t_line)
734 eina_list_free(list);
739 _zoom_test_reset(Gesture_Info *gesture)
747 Widget_Data *wd = elm_widget_data_get(gesture->obj);
748 Zoom_Type *st = gesture->data;
749 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
750 evas_object_evas_get(wd->target), "Control");
751 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
752 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
754 memset(st, 0, sizeof(Zoom_Type));
755 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
760 _rotate_test_reset(Gesture_Info *gesture)
768 Widget_Data *wd = elm_widget_data_get(gesture->obj);
769 Rotate_Type *st = gesture->data;
771 memset(st, 0, sizeof(Rotate_Type));
772 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
773 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
780 * We register callbacks when gesture layer is attached to an object
781 * or when its enabled after disable.
783 * @param obj The gesture-layer object.
785 * @ingroup Elm_Gesture_Layer
788 _register_callbacks(Evas_Object *obj)
790 Widget_Data *wd = elm_widget_data_get(obj);
795 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
797 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
799 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
802 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
805 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
807 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
809 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
812 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
814 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
822 * We unregister callbacks when gesture layer is disabled.
824 * @param obj The gesture-layer object.
826 * @ingroup Elm_Gesture_Layer
829 _unregister_callbacks(Evas_Object *obj)
831 Widget_Data *wd = elm_widget_data_get(obj);
836 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
838 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
840 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
843 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
846 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
849 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
852 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
855 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
857 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
862 /* START - Event history list handling functions */
865 * This function is used to find if device number
866 * is found in a list of devices.
867 * The list contains devices for refeeding *UP event
869 * @ingroup Elm_Gesture_Layer
872 device_in_pending_list(const void *data1, const void *data2)
873 { /* Compare the two device numbers */
874 return (((intptr_t) data1) - ((intptr_t) data2));
880 * This functions adds device to refeed-pending device list
881 * @ingroup Elm_Gesture_Layer
884 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
886 int device = ELM_MOUSE_DEVICE;
889 case EVAS_CALLBACK_MOUSE_DOWN:
891 case EVAS_CALLBACK_MULTI_DOWN:
892 device = ((Evas_Event_Multi_Down *) event)->device;
898 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
901 return eina_list_append(list, (intptr_t*) device);
910 * This functions returns pending-device node
911 * @ingroup Elm_Gesture_Layer
914 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
916 int device = ELM_MOUSE_DEVICE;
919 case EVAS_CALLBACK_MOUSE_UP:
921 case EVAS_CALLBACK_MULTI_UP:
922 device = ((Evas_Event_Multi_Up *) event)->device;
928 return eina_list_search_unsorted_list(list, device_in_pending_list,
929 (intptr_t *) device);
935 * This function reports ABORT to all none-detected gestures
936 * Then resets test bits for all desired gesures
937 * and clears input-events history.
938 * note: if no gesture was detected, events from history list
939 * are streamed to the widget because it's unused by layer.
940 * user may cancel refeed of events by setting repeat events.
942 * @param obj The gesture-layer object.
944 * @ingroup Elm_Gesture_Layer
947 _event_history_clear(Evas_Object *obj)
949 Widget_Data *wd = elm_widget_data_get(obj);
950 if (!wd) return EINA_FALSE;
954 Evas *e = evas_object_evas_get(obj);
955 Eina_Bool gesture_found = EINA_FALSE;
956 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
961 if (p->state == ELM_GESTURE_STATE_END)
962 gesture_found = EINA_TRUE;
964 { /* Report ABORT to all gestures that still not finished */
965 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
971 _reset_states(wd); /* we are ready to start testing for gestures again */
973 /* Clear all gestures intermediate data */
974 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
975 { /* We do not clear a long-tap gesture if fingers still on surface */
976 /* and gesture timer still pending to test gesture state */
977 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
978 if ((st) && /* st not allocated if clear occurs before 1st input */
979 ((!eina_list_count(st->touched)) || (!st->timeout)))
980 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
985 ecore_timer_del(wd->dbl_timeout);
986 wd->dbl_timeout = NULL;
989 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
990 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
991 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
992 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
993 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
994 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
995 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
996 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
998 /* Disable gesture layer so refeeded events won't be consumed by it */
999 _unregister_callbacks(obj);
1000 while (wd->event_history_list)
1003 t = wd->event_history_list;
1004 Eina_List *pending = _device_is_pending(wd->pending,
1005 wd->event_history_list->event,
1006 wd->event_history_list->event_type);
1008 /* Refeed events if no gesture matched input */
1009 if (pending || ((!gesture_found) && (!wd->repeat_events)))
1011 evas_event_refeed_event(e, wd->event_history_list->event,
1012 wd->event_history_list->event_type);
1016 wd->pending = eina_list_remove_list(wd->pending, pending);
1017 int device = ELM_MOUSE_DEVICE;
1018 if (wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
1019 device = ((Evas_Event_Multi_Up *)
1020 (wd->event_history_list->event))->device;
1023 wd->pending = _add_device_pending(wd->pending,
1024 wd->event_history_list->event,
1025 wd->event_history_list->event_type);
1028 free(wd->event_history_list->event);
1029 wd->event_history_list = (Event_History *) eina_inlist_remove(
1030 EINA_INLIST_GET(wd->event_history_list),
1031 EINA_INLIST_GET(wd->event_history_list));
1034 _register_callbacks(obj);
1041 * This function copies input events.
1042 * We copy event info before adding it to history.
1043 * The memory is freed when we clear history.
1045 * @param event the event to copy
1046 * @param event_type event type to copy
1048 * @ingroup Elm_Gesture_Layer
1051 _copy_event_info(void *event, Evas_Callback_Type event_type)
1055 case EVAS_CALLBACK_MOUSE_DOWN:
1056 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1058 case EVAS_CALLBACK_MOUSE_MOVE:
1059 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1061 case EVAS_CALLBACK_MOUSE_UP:
1062 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1064 case EVAS_CALLBACK_MOUSE_WHEEL:
1065 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1067 case EVAS_CALLBACK_MULTI_DOWN:
1068 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1070 case EVAS_CALLBACK_MULTI_MOVE:
1071 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1073 case EVAS_CALLBACK_MULTI_UP:
1074 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1076 case EVAS_CALLBACK_KEY_DOWN:
1077 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1079 case EVAS_CALLBACK_KEY_UP:
1080 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1088 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1090 Widget_Data *wd = elm_widget_data_get(obj);
1092 if (!wd) return EINA_FALSE;
1094 ev = malloc(sizeof(Event_History));
1095 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1096 ev->event_type = event_type;
1097 wd->event_history_list = (Event_History *) eina_inlist_append(
1098 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1102 /* END - Event history list handling functions */
1105 _del_hook(Evas_Object *obj)
1107 Widget_Data *wd = elm_widget_data_get(obj);
1110 _event_history_clear(obj);
1111 eina_list_free(wd->pending);
1113 Pointer_Event *data;
1114 EINA_LIST_FREE(wd->touched, data)
1117 EINA_LIST_FREE(wd->recent_device_event, data)
1120 if (!elm_widget_disabled_get(obj))
1121 _unregister_callbacks(obj);
1123 /* Free all gestures internal data structures */
1125 for (i = 0; i < ELM_GESTURE_LAST; i++)
1128 if (wd->gesture[i]->data)
1129 free(wd->gesture[i]->data);
1131 free(wd->gesture[i]);
1138 compare_match_fingers(const void *data1, const void *data2)
1139 { /* Compare coords of first item in list to cur coords */
1140 const Pointer_Event *pe1 = eina_list_data_get(data1);
1141 const Pointer_Event *pe2 = data2;
1143 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1145 else if (pe1->x < pe2->x)
1149 if (pe1->x == pe2->x)
1150 return pe1->y - pe2->y;
1157 compare_pe_device(const void *data1, const void *data2)
1158 { /* Compare coords of first item in list to cur coords */
1159 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1160 const Pointer_Event *pe2 = data2;
1162 /* Only match if last was a down event */
1163 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1164 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1168 if (pe1->device == pe2->device)
1170 else if (pe1->device < pe2->device)
1177 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1178 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1179 { /* Keep copy of pe and record it in list */
1180 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1181 memcpy(p, pe, sizeof(Pointer_Event));
1182 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1188 /* This will also update middle-point to report to user later */
1189 st->info.x = st->sum_x / st->n_taps;
1190 st->info.y = st->sum_y / st->n_taps;
1191 st->info.timestamp = pe->timestamp;
1195 pe_list = eina_list_append(pe_list, p);
1196 st->l = eina_list_append(st->l, pe_list);
1199 pe_list = eina_list_append(pe_list, p);
1207 * This function sets state a tap-gesture to END or ABORT
1209 * @param data gesture info pointer
1211 * @ingroup Elm_Gesture_Layer
1214 _tap_gesture_finish(void *data)
1215 { /* This function will test each tap gesture when timer expires */
1216 Gesture_Info *gesture = data;
1217 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1218 /* Here we check if taps-gesture was completed successfuly */
1219 /* Count how many taps were recieved on each device then */
1220 /* determine if it matches n_taps_needed defined on START */
1221 Taps_Type *st = gesture->data;
1224 EINA_LIST_FOREACH(st->l, l, pe_list)
1226 if (eina_list_count(pe_list) != st->n_taps_needed)
1227 { /* No match taps number on device, ABORT */
1228 s = ELM_GESTURE_STATE_ABORT;
1233 st->info.n = eina_list_count(st->l);
1234 _set_state(gesture, s, gesture->info, EINA_FALSE);
1235 _tap_gestures_test_reset(gesture);
1241 * when this timer expires we finish tap gestures.
1243 * @param data The gesture-layer object.
1244 * @return cancles callback for this timer.
1246 * @ingroup Elm_Gesture_Layer
1249 _multi_tap_timeout(void *data)
1251 Widget_Data *wd = elm_widget_data_get(data);
1252 if (!wd) return EINA_FALSE;
1254 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1255 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1257 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1258 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1260 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1261 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1263 _clear_if_finished(data);
1264 wd->dbl_timeout = NULL;
1265 return ECORE_CALLBACK_CANCEL;
1271 * when this timer expires we START long tap gesture
1273 * @param data The gesture-layer object.
1274 * @return cancles callback for this timer.
1276 * @ingroup Elm_Gesture_Layer
1279 _long_tap_timeout(void *data)
1281 Gesture_Info *gesture = data;
1282 Long_Tap_Type *st = gesture->data;
1285 _set_state(gesture, ELM_GESTURE_STATE_START,
1286 gesture->data, EINA_FALSE);
1288 return ECORE_CALLBACK_CANCEL;
1295 * This function checks if a tap gesture should start
1297 * @param wd Gesture Layer Widget Data.
1298 * @param pe The recent input event as stored in pe struct.
1299 * @param event_info Original input event pointer.
1300 * @param event_type Type of original input event.
1301 * @param gesture what gesture is tested
1302 * @param how many taps for this gesture (1, 2 or 3)
1304 * @return Flag to determine if we need to set a timer for finish
1306 * @ingroup Elm_Gesture_Layer
1309 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1310 void *event_info, Evas_Callback_Type event_type,
1311 Gesture_Info *gesture, int taps)
1312 { /* Here we fill Tap struct */
1313 Taps_Type *st = gesture->data;
1315 { /* Allocated once on first time */
1316 st = calloc(1, sizeof(Taps_Type));
1318 _tap_gestures_test_reset(gesture);
1321 Eina_List *pe_list = NULL;
1322 Pointer_Event *pe_down = NULL;
1323 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1324 switch (pe->event_type)
1326 case EVAS_CALLBACK_MULTI_DOWN:
1327 case EVAS_CALLBACK_MOUSE_DOWN:
1328 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1329 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1330 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1331 { /* This is the first mouse down we got */
1332 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1333 &st->info, EINA_FALSE);
1334 consume_event(wd, event_info, event_type, ev_flag);
1336 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1343 case EVAS_CALLBACK_MULTI_UP:
1344 case EVAS_CALLBACK_MOUSE_UP:
1345 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1349 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1352 case EVAS_CALLBACK_MULTI_MOVE:
1353 case EVAS_CALLBACK_MOUSE_MOVE:
1354 /* Get first event in first list, this has to be a Mouse Down event */
1355 /* and verify that user didn't move out of this area before next tap */
1356 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1359 pe_down = eina_list_data_get(pe_list);
1360 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1362 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1363 &st->info, EINA_FALSE);
1364 consume_event(wd, event_info, event_type, ev_flag);
1380 * This function checks all click/tap and double/triple taps
1382 * @param obj The gesture-layer object.
1383 * @param pe The recent input event as stored in pe struct.
1384 * @param event_info Original input event pointer.
1385 * @param event_type Type of original input event.
1387 * @ingroup Elm_Gesture_Layer
1390 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1391 void *event_info, Evas_Callback_Type event_type)
1392 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1393 Eina_Bool need_timer = EINA_FALSE;
1394 Widget_Data *wd = elm_widget_data_get(obj);
1397 if (!pe) /* this happens when unhandled event arrived */
1398 return; /* see _make_pointer_event function */
1400 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1401 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1402 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1404 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1405 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1406 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1408 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1409 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1410 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1412 if ((need_timer) && (!wd->dbl_timeout))
1413 { /* Set a timer to finish these gestures */
1414 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1422 * This function computes center-point for long-tap gesture
1424 * @param st Long Tap gesture info pointer
1425 * @param pe The recent input event as stored in pe struct.
1427 * @ingroup Elm_Gesture_Layer
1430 _compute_taps_center(Long_Tap_Type *st, Pointer_Event *pe)
1432 if(!eina_list_count(st->touched))
1437 Evas_Coord x = 0, y = 0;
1438 EINA_LIST_FOREACH(st->touched, l, p)
1439 { /* Accumulate all then take avarage */
1440 if (p->device == pe->device)
1441 { /* This will take care of values coming from MOVE event */
1452 st->info.x = x / eina_list_count(st->touched);
1453 st->info.y = y / eina_list_count(st->touched);
1459 * This function checks N long-tap gesture.
1461 * @param obj The gesture-layer object.
1462 * @param pe The recent input event as stored in pe struct.
1463 * @param event_info Original input event pointer.
1464 * @param event_type Type of original input event.
1465 * @param g_type what Gesture we are testing.
1466 * @param taps How many click/taps we test for.
1468 * @ingroup Elm_Gesture_Layer
1471 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1472 void *event_info, Evas_Callback_Type event_type,
1473 Elm_Gesture_Types g_type)
1474 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1475 Widget_Data *wd = elm_widget_data_get(obj);
1478 if (!pe) /* this happens when unhandled event arrived */
1479 return; /* see _make_pointer_event function */
1481 Gesture_Info *gesture = wd->gesture[g_type];
1482 if (!gesture ) return;
1484 Long_Tap_Type *st = gesture->data;
1486 { /* Allocated once on first time */
1487 st = calloc(1, sizeof(Long_Tap_Type));
1489 _n_long_tap_test_reset(gesture);
1492 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1493 switch (pe->event_type)
1495 case EVAS_CALLBACK_MULTI_DOWN:
1496 case EVAS_CALLBACK_MOUSE_DOWN:
1497 st->touched = _add_touched_device(st->touched, pe);
1498 st->info.n = eina_list_count(st->touched);
1499 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1500 { /* This is the first mouse down we got */
1501 st->info.timestamp = pe->timestamp;
1503 /* To test long tap */
1504 /* When this timer expires, gesture STARTED */
1506 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1507 _long_tap_timeout, gesture);
1510 consume_event(wd, event_info, event_type, ev_flag);
1511 _compute_taps_center(st, pe);
1514 case EVAS_CALLBACK_MULTI_UP:
1515 case EVAS_CALLBACK_MOUSE_UP:
1516 st->touched = _remove_touched_device(st->touched, pe);
1518 ((gesture->state == ELM_GESTURE_STATE_START) ||
1519 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1520 { /* Report END only for gesture that STARTed */
1521 if (eina_list_count(st->touched) == 0)
1522 { /* Report END only at last release event */
1523 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1524 &st->info, EINA_FALSE);
1525 consume_event(wd, event_info, event_type, ev_flag);
1529 { /* Stop test, user lifts finger before long-start */
1530 if (st->timeout) ecore_timer_del(st->timeout);
1532 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1533 &st->info, EINA_FALSE);
1534 consume_event(wd, event_info, event_type, ev_flag);
1539 case EVAS_CALLBACK_MULTI_MOVE:
1540 case EVAS_CALLBACK_MOUSE_MOVE:
1542 ((gesture->state == ELM_GESTURE_STATE_START) ||
1543 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1544 { /* Report MOVE only if STARTED */
1545 _compute_taps_center(st, pe);
1546 /* Report MOVE if gesture started */
1547 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1548 &st->info, EINA_TRUE);
1549 consume_event(wd, event_info, event_type, ev_flag);
1561 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1562 * This momentum value will be sent to widget when gesture is completed.
1564 * @param momentum pointer to buffer where we record momentum value.
1565 * @param x1 x coord where user started gesture.
1566 * @param y1 y coord where user started gesture.
1567 * @param x2 x coord where user completed gesture.
1568 * @param y2 y coord where user completed gesture.
1569 * @param t1x timestamp for X, when user started gesture.
1570 * @param t1y timestamp for Y, when user started gesture.
1571 * @param t2 timestamp when user completed gesture.
1573 * @ingroup Elm_Gesture_Layer
1576 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1577 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1580 Evas_Coord velx = 0, vely = 0, vel;
1581 Evas_Coord dx = x2 - x1;
1582 Evas_Coord dy = y2 - y1;
1586 velx = (dx * 1000) / dtx;
1589 vely = (dy * 1000) / dty;
1591 vel = sqrt((velx * velx) + (vely * vely));
1593 if ((_elm_config->thumbscroll_friction > 0.0) &&
1594 (vel > _elm_config->thumbscroll_momentum_threshold))
1595 { /* report momentum */
1596 momentum->mx = velx;
1597 momentum->my = vely;
1609 * This function is used for computing rotation angle (DEG).
1611 * @param x1 first finger x location.
1612 * @param y1 first finger y location.
1613 * @param x2 second finger x location.
1614 * @param y2 second finger y location.
1616 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1618 * @ingroup Elm_Gesture_Layer
1621 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1627 if (((int) xx) && ((int) yy))
1634 return RAD_360DEG - a;
1645 return RAD_180DEG + a;
1649 return RAD_180DEG - a;
1655 { /* Horizontal line */
1680 * This function is used for computing the magnitude and direction
1681 * of vector between two points.
1683 * @param x1 first finger x location.
1684 * @param y1 first finger y location.
1685 * @param x2 second finger x location.
1686 * @param y2 second finger y location.
1687 * @param l length computed (output)
1688 * @param a angle computed (output)
1690 * @ingroup Elm_Gesture_Layer
1693 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1694 Evas_Coord *l, double *a)
1699 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1700 *a = get_angle(x1, y1, x2, y2);
1704 _get_direction(Evas_Coord x1, Evas_Coord x2)
1716 * This function tests momentum gesture.
1717 * @param obj The gesture-layer object.
1718 * @param pe The recent input event as stored in pe struct.
1719 * @param event_info recent input event.
1720 * @param event_type recent event type.
1721 * @param g_type what Gesture we are testing.
1723 * @ingroup Elm_Gesture_Layer
1726 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1727 void *event_info, Evas_Callback_Type event_type,
1728 Elm_Gesture_Types g_type)
1730 Widget_Data *wd = elm_widget_data_get(obj);
1732 Gesture_Info *gesture = wd->gesture[g_type];
1733 if (!gesture ) return;
1735 Momentum_Type *st = gesture->data;
1736 Elm_Gesture_State state_to_report;
1738 { /* Allocated once on first time */
1739 st = calloc(1, sizeof(Momentum_Type));
1741 _momentum_test_reset(gesture);
1747 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1750 case EVAS_CALLBACK_MOUSE_DOWN:
1751 case EVAS_CALLBACK_MOUSE_MOVE:
1754 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1755 (wd->glayer_continues_enable)) /* start also on MOVE */
1756 { /* We start on MOVE when cont-enabled only */
1757 st->line_st.x = st->line_end.x = pe->x;
1758 st->line_st.y = st->line_end.y = pe->y;
1759 st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1760 st->xdir = st->ydir = 0;
1761 st->info.x2 = st->info.x1 = pe->x;
1762 st->info.y2 = st->info.y1 = pe->y;
1763 st->info.tx = st->info.ty = pe->timestamp;
1764 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1765 &st->info, EINA_FALSE);
1766 consume_event(wd, event_info, event_type, ev_flag);
1773 state_to_report = ELM_GESTURE_STATE_MOVE;
1774 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1775 { /* Too long of a wait, reset all values */
1776 st->line_st.x = pe->x;
1777 st->line_st.y = pe->y;
1778 st->t_st_y = st->t_st_x = pe->timestamp;
1779 st->info.tx = st->t_st_x;
1780 st->info.ty = st->t_st_y;
1781 st->xdir = st->ydir = 0;
1786 xdir = _get_direction(st->line_st.x, pe->x);
1787 ydir = _get_direction(st->line_st.y, pe->y);
1788 if (!xdir || (xdir == (-st->xdir)))
1790 st->line_st.x = st->line_end.x;
1791 st->info.tx = st->t_st_x = st->t_end;
1795 if (!ydir || (ydir == (-st->ydir)))
1797 st->line_st.y = st->line_end.y;
1798 st->info.ty = st->t_st_y = st->t_end;
1803 st->info.x2 = st->line_end.x = pe->x;
1804 st->info.y2 = st->line_end.y = pe->y;
1805 st->t_end = pe->timestamp;
1806 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1807 st->t_st_x, st->t_st_y, pe->timestamp);
1808 ev_flag = _set_state(gesture, state_to_report, &st->info,
1810 consume_event(wd, event_info, event_type, ev_flag);
1814 case EVAS_CALLBACK_MOUSE_UP:
1815 /* IGNORE if line info was cleared, like long press, move */
1818 state_to_report = ELM_GESTURE_STATE_END;
1820 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1821 { /* Too long of a wait, reset all values */
1822 st->line_st.x = pe->x;
1823 st->line_st.y = pe->y;
1824 st->t_st_y = st->t_st_x = pe->timestamp;
1825 st->xdir = st->ydir = 0;
1828 st->info.x2 = pe->x;
1829 st->info.y2 = pe->y;
1830 st->line_end.x = pe->x;
1831 st->line_end.y = pe->y;
1832 st->t_end = pe->timestamp;
1834 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1835 st->t_st_x, st->t_st_y, pe->timestamp);
1837 ev_flag = _set_state(gesture, state_to_report, &st->info,
1839 consume_event(wd, event_info, event_type, ev_flag);
1843 case EVAS_CALLBACK_MULTI_UP:
1844 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1846 consume_event(wd, event_info, event_type, ev_flag);
1855 compare_line_device(const void *data1, const void *data2)
1856 { /* Compare device component of line struct */
1857 const Line_Data *ln1 = data1;
1858 const int *device = data2;
1860 if (ln1->t_st) /* Compare only with lines that started */
1861 return (ln1->device - (*device));
1869 * This function construct line struct from input.
1870 * @param info pointer to store line momentum.
1871 * @param st line info to store input data.
1872 * @param pe The recent input event as stored in pe struct.
1874 * @ingroup Elm_Gesture_Layer
1877 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1878 Pointer_Event *pe, Evas_Callback_Type event_type)
1879 { /* Record events and set momentum for line pointed by st */
1885 case EVAS_CALLBACK_MOUSE_DOWN:
1886 case EVAS_CALLBACK_MOUSE_MOVE:
1887 case EVAS_CALLBACK_MULTI_DOWN:
1888 case EVAS_CALLBACK_MULTI_MOVE:
1890 { /* This happens only when line starts */
1891 st->line_st.x = pe->x;
1892 st->line_st.y = pe->y;
1893 st->t_st = pe->timestamp;
1894 st->device = pe->device;
1895 info->momentum.x1 = pe->x;
1896 info->momentum.y1 = pe->y;
1897 info->momentum.tx = pe->timestamp;
1898 info->momentum.ty = pe->timestamp;
1905 case EVAS_CALLBACK_MOUSE_UP:
1906 case EVAS_CALLBACK_MULTI_UP:
1907 /* IGNORE if line info was cleared, like long press, move */
1911 st->line_end.x = pe->x;
1912 st->line_end.y = pe->y;
1913 st->t_end = pe->timestamp;
1922 _line_data_reset(st);
1926 info->momentum.x2 = pe->x;
1927 info->momentum.y2 = pe->y;
1928 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1929 st->t_st, st->t_st, pe->timestamp);
1937 * This function test for (n) line gesture.
1938 * @param obj The gesture-layer object.
1939 * @param pe The recent input event as stored in pe struct.
1940 * @param event_info Original input event pointer.
1941 * @param event_type Type of original input event.
1942 * @param g_type what Gesture we are testing.
1944 * @ingroup Elm_Gesture_Layer
1947 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1948 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1952 Widget_Data *wd = elm_widget_data_get(obj);
1954 Gesture_Info *gesture = wd->gesture[g_type];
1955 if (!gesture ) return;
1957 Line_Type *st = gesture->data;
1960 st = calloc(1, sizeof(Line_Type));
1964 Line_Data *line = NULL;
1965 Eina_List *list = st->list;
1966 unsigned cnt = eina_list_count(list);
1969 { /* list is not empty, locate this device on list */
1970 line = (Line_Data *) eina_list_search_unsorted(st->list,
1971 compare_line_device, &pe->device);
1975 { /* List is empty or device not found, new line-struct on START only */
1976 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1977 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1978 ((wd->glayer_continues_enable) && /* START on MOVE also */
1979 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1980 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
1981 { /* Allocate new item on START only */
1982 line = calloc(1, sizeof(Line_Data));
1983 _line_data_reset(line);
1984 list = eina_list_append(list, line);
1989 if (!line) /* This may happen on MOVE that comes before DOWN */
1990 return; /* No line-struct to work with, can't continue testing */
1992 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
1993 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1995 /* Get direction and magnitude of the line */
1997 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1998 &line->line_length, &angle);
2000 /* These are used later to compare lines length */
2001 Evas_Coord shortest_line_len = line->line_length;
2002 Evas_Coord longest_line_len = line->line_length;
2003 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2005 /* Now update line-state */
2007 { /* Analyze line only if line started */
2008 if (line->line_angle >= 0.0)
2009 { /* if line direction was set, we test if broke tolerance */
2010 double a = fabs(angle - line->line_angle);
2012 double d = (tan(a)) * line->line_length; /* Distance from line */
2013 #if defined(DEBUG_GESTURE_LAYER)
2014 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2016 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2017 { /* Broke tolerance: abort line and start a new one */
2018 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2019 &st->info, EINA_FALSE);
2020 consume_event(wd, event_info, event_type, ev_flag);
2024 if (wd->glayer_continues_enable)
2025 { /* We may finish line if momentum is zero */
2026 /* This is for continues-gesture */
2027 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2028 { /* Finish line on zero momentum for continues gesture */
2029 line->line_end.x = pe->x;
2030 line->line_end.y = pe->y;
2031 line->t_end = pe->timestamp;
2036 { /* Record the line angle as it broke minimum length for line */
2037 if (line->line_length >= wd->line_min_length)
2038 st->info.angle = line->line_angle = angle;
2044 if (line->line_angle < 0.0)
2045 { /* it's not a line, too short more close to a tap */
2046 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2047 &st->info, EINA_FALSE);
2048 consume_event(wd, event_info, event_type, ev_flag);
2054 /* Count how many lines already started / ended */
2057 unsigned int tm_start = pe->timestamp;
2058 unsigned int tm_end = pe->timestamp;
2061 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2062 Eina_Bool lines_parallel = EINA_TRUE;
2063 EINA_LIST_FOREACH(list, l, t_line)
2066 base_angle = t_line->line_angle;
2069 if (t_line->line_angle >= 0)
2070 { /* Compare angle only with lines with direction defined */
2071 if (fabs(base_angle - t_line->line_angle) >
2072 wd->line_angular_tolerance)
2073 lines_parallel = EINA_FALSE;
2077 if (t_line->line_length)
2078 { /* update only if this line is used */
2079 if (shortest_line_len > t_line->line_length)
2080 shortest_line_len = t_line->line_length;
2082 if (longest_line_len < t_line->line_length)
2083 longest_line_len = t_line->line_length;
2089 if (t_line->t_st < tm_start)
2090 tm_start = t_line->t_st;
2096 if (t_line->t_end < tm_end)
2097 tm_end = t_line->t_end;
2101 st->info.n = started;
2105 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2106 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2107 { /* user lift one finger then starts again without line-end - ABORT */
2108 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2110 consume_event(wd, event_info, event_type, ev_flag);
2114 if (!lines_parallel)
2115 { /* Lines are NOT at same direction, abort this gesture */
2116 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2118 consume_event(wd, event_info, event_type, ev_flag);
2123 /* We report ABORT if lines length are NOT matching when fingers are up */
2124 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2126 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2128 consume_event(wd, event_info, event_type, ev_flag);
2132 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2133 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2134 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2136 consume_event(wd, event_info, event_type, ev_flag);
2142 case EVAS_CALLBACK_MOUSE_UP:
2143 case EVAS_CALLBACK_MULTI_UP:
2144 if ((started) && (started == ended))
2146 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2147 &st->info, EINA_FALSE);
2148 consume_event(wd, event_info, event_type, ev_flag);
2153 case EVAS_CALLBACK_MOUSE_DOWN:
2154 case EVAS_CALLBACK_MULTI_DOWN:
2155 case EVAS_CALLBACK_MOUSE_MOVE:
2156 case EVAS_CALLBACK_MULTI_MOVE:
2159 if (wd->glayer_continues_enable && (started == ended))
2160 { /* For continues gesture */
2161 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2162 &st->info, EINA_FALSE);
2163 consume_event(wd, event_info, event_type, ev_flag);
2166 { /* When continues, may START on MOVE event too */
2167 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2169 /* This happens when: on n > 1 lines then one finger up */
2170 /* caused abort, then put finger down. */
2171 /* This will stop line from starting again. */
2172 /* Number of lines, MUST match touched-device in list */
2173 if ((!wd->glayer_continues_enable) &&
2174 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2175 s = ELM_GESTURE_STATE_ABORT;
2177 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2178 s = ELM_GESTURE_STATE_START;
2180 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2181 consume_event(wd, event_info, event_type, ev_flag);
2187 return; /* Unhandeld event type */
2194 * This function is used to check if rotation gesture started.
2195 * @param st Contains current rotation values from user input.
2196 * @return TRUE/FALSE if we need to set rotation START.
2198 * @ingroup Elm_Gesture_Layer
2201 rotation_broke_tolerance(Rotate_Type *st)
2203 if (st->info.base_angle < 0)
2204 return EINA_FALSE; /* Angle has to be computed first */
2206 if (st->rotate_angular_tolerance < 0)
2209 double low = st->info.base_angle - st->rotate_angular_tolerance;
2210 double high = st->info.base_angle + st->rotate_angular_tolerance;
2211 double t = st->info.angle;
2224 if (high > RAD_360DEG)
2235 #if defined(DEBUG_GESTURE_LAYER)
2236 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2238 if ((t < low) || (t > high))
2239 { /* This marks that roation action has started */
2240 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2241 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2251 * This function is used for computing the gap between fingers.
2252 * It returns the length and center point between fingers.
2254 * @param x1 first finger x location.
2255 * @param y1 first finger y location.
2256 * @param x2 second finger x location.
2257 * @param y2 second finger y location.
2258 * @param x Gets center point x cord (output)
2259 * @param y Gets center point y cord (output)
2261 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2263 * @ingroup Elm_Gesture_Layer
2266 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2267 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2269 double a, b, xx, yy, gap;
2272 gap = sqrt(xx*xx + yy*yy);
2274 /* START - Compute zoom center point */
2275 /* The triangle defined as follows:
2283 * http://en.wikipedia.org/wiki/Trigonometric_functions
2284 *************************************/
2285 if (((int) xx) && ((int) yy))
2287 double A = atan((yy / xx));
2288 #if defined(DEBUG_GESTURE_LAYER)
2289 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2291 a = (Evas_Coord) ((gap / 2) * sin(A));
2292 b = (Evas_Coord) ((gap / 2) * cos(A));
2293 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2294 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2299 { /* horiz line, take half width */
2300 #if defined(DEBUG_GESTURE_LAYER)
2301 printf("==== HORIZ ====\n");
2303 *x = (Evas_Coord) (xx / 2);
2304 *y = (Evas_Coord) (y1);
2308 { /* vert line, take half width */
2309 #if defined(DEBUG_GESTURE_LAYER)
2310 printf("==== VERT ====\n");
2312 *x = (Evas_Coord) (x1);
2313 *y = (Evas_Coord) (yy / 2);
2316 /* END - Compute zoom center point */
2318 return (Evas_Coord) gap;
2324 * This function is used for computing zoom value.
2326 * @param st Pointer to zoom data based on user input.
2327 * @param x1 first finger x location.
2328 * @param y1 first finger y location.
2329 * @param x2 second finger x location.
2330 * @param y2 second finger y location.
2331 * @param factor zoom-factor, used to determine how fast zoom works.
2333 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2335 * @ingroup Elm_Gesture_Layer
2337 /* FIXME change float to double */
2339 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2340 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2343 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2344 &st->info.x, &st->info.y);
2346 st->info.radius = diam / 2;
2350 st->zoom_base = diam;
2351 return st->info.zoom;
2354 if (st->zoom_distance_tolerance)
2355 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2356 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2357 { /* avoid jump with zoom value when break tolerance */
2358 st->zoom_base -= st->zoom_distance_tolerance;
2359 st->zoom_distance_tolerance = 0;
2362 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2363 { /* avoid jump with zoom value when break tolerance */
2364 st->zoom_base += st->zoom_distance_tolerance;
2365 st->zoom_distance_tolerance = 0;
2371 /* We use factor only on the difference between gap-base */
2372 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2373 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2374 (float) st->zoom_base) * zoom_finger_factor));
2377 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2378 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2389 * This function handles zoom with mouse wheel.
2390 * thats a combination of wheel + CTRL key.
2391 * @param obj The gesture-layer object.
2392 * @param event_info Original input event pointer.
2393 * @param event_type Type of original input event.
2394 * @param g_type what Gesture we are testing.
2396 * @ingroup Elm_Gesture_Layer
2399 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2400 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2402 Widget_Data *wd = elm_widget_data_get(obj);
2404 if (!wd->gesture[g_type]) return;
2406 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2407 Zoom_Type *st = gesture_zoom->data;
2408 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2410 { /* Allocated once on first time, used for zoom intermediate data */
2411 st = calloc(1, sizeof(Zoom_Type));
2412 gesture_zoom->data = st;
2413 _zoom_test_reset(gesture_zoom);
2418 case EVAS_CALLBACK_KEY_UP:
2420 Evas_Event_Key_Up *p = event_info;
2421 if ((!strcmp(p->keyname, "Control_L")) ||
2422 (!strcmp(p->keyname, "Control_R")))
2423 { /* Test if we ended a zoom gesture when releasing CTRL */
2424 if ((st->zoom_wheel) &&
2425 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2426 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2427 { /* User released CTRL after zooming */
2428 ev_flag = _set_state(gesture_zoom,
2429 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2430 consume_event(wd, event_info, event_type, ev_flag);
2438 case EVAS_CALLBACK_MOUSE_WHEEL:
2441 Elm_Gesture_State s;
2442 if (!evas_key_modifier_is_set(
2443 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2445 { /* if using wheel witout CTRL after starting zoom */
2446 if ((st->zoom_wheel) &&
2447 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2448 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2450 ev_flag = _set_state(gesture_zoom,
2451 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2452 consume_event(wd, event_info, event_type, ev_flag);
2457 return; /* Ignore mouse-wheel without control */
2460 /* Using mouse wheel with CTRL for zoom */
2461 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2462 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2463 we continue a zoom gesture */
2465 s = ELM_GESTURE_STATE_MOVE;
2468 { /* On first wheel event, report START */
2469 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2470 evas_object_evas_get(wd->target), "Control");
2472 s = ELM_GESTURE_STATE_START;
2473 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2474 ERR("Failed to Grabbed CTRL_L");
2475 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2476 ERR("Failed to Grabbed CTRL_R");
2479 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2480 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2481 st->info.x = st->zoom_wheel->canvas.x;
2482 st->info.y = st->zoom_wheel->canvas.y;
2484 if (st->zoom_wheel->z < 0) /* zoom in */
2485 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2487 if (st->zoom_wheel->z > 0) /* zoom out */
2488 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2490 if (st->info.zoom < 0.0)
2491 st->info.zoom = 0.0;
2493 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2494 consume_event(wd, event_info, event_type, ev_flag);
2506 * This function is used to test zoom gesture.
2507 * user may combine zoom, rotation together.
2508 * so its possible that both will be detected from input.
2509 * (both are two-finger movement-oriented gestures)
2511 * @param obj The gesture-layer object.
2512 * @param event_info Pointer to recent input event.
2513 * @param event_type Recent input event type.
2514 * @param g_type what Gesture we are testing.
2516 * @ingroup Elm_Gesture_Layer
2519 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2520 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2524 Widget_Data *wd = elm_widget_data_get(obj);
2526 if (!wd->gesture[g_type]) return;
2528 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2529 Zoom_Type *st = gesture_zoom->data;
2532 { /* Allocated once on first time, used for zoom data */
2533 st = calloc(1, sizeof(Zoom_Type));
2534 gesture_zoom->data = st;
2535 _zoom_test_reset(gesture_zoom);
2539 /* Start - new zoom testing, letting all fingers start */
2540 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2543 case EVAS_CALLBACK_MOUSE_MOVE:
2544 case EVAS_CALLBACK_MULTI_MOVE:
2545 /* if non-continues mode and gesture NOT started, ignore MOVE */
2546 if ((!wd->glayer_continues_enable) &&
2547 (!st->zoom_st.timestamp))
2550 case EVAS_CALLBACK_MOUSE_DOWN:
2551 case EVAS_CALLBACK_MULTI_DOWN:
2552 { /* Here we take care of zoom-start and zoom move */
2556 if(eina_list_count(wd->touched) > 2)
2557 { /* Process zoom only when 2 fingers on surface */
2558 ev_flag = _set_state(gesture_zoom,
2559 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2560 consume_event(wd, event_info, event_type, ev_flag);
2565 if (!st->zoom_st.timestamp)
2566 { /* Now scan touched-devices list and find other finger */
2567 EINA_LIST_FOREACH(wd->touched, l, p)
2568 { /* Device of other finger <> pe device */
2569 if (p->device != pe->device)
2573 if (!p) /* Single finger on touch */
2576 /* Record down fingers */
2577 consume_event(wd, event_info, event_type, ev_flag);
2578 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2579 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2581 /* Set mv field as well to be ready for MOVE events */
2582 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2583 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2585 /* Here we have zoom_st, zoom_st1 set, report START */
2586 /* Set zoom-base after BOTH down events recorded */
2587 /* Compute length of line between fingers zoom start */
2588 st->info.zoom = 1.0;
2589 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2590 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2591 &st->info.x, &st->info.y);
2593 st->info.radius = st->zoom_base / 2;
2595 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2596 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2597 { /* zoom started with mouse-wheel, don't report twice */
2598 ev_flag = _set_state(gesture_zoom,
2599 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2600 consume_event(wd, event_info, event_type, ev_flag);
2603 return; /* Zoom started */
2604 } /* End of ZOOM_START handling */
2607 /* if we got here, we have (exacally) two fingers on surfce */
2608 /* we also after START, report MOVE */
2609 /* First detect which finger moved */
2610 if (pe->device == st->zoom_mv.device)
2611 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2612 else if (pe->device == st->zoom_mv1.device)
2613 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2615 /* Compute change in zoom as fingers move */
2616 st->info.zoom = compute_zoom(st,
2617 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2618 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2619 wd->zoom_finger_factor);
2621 if (!st->zoom_distance_tolerance)
2622 { /* Zoom broke tolerance, report move */
2623 double d = st->info.zoom - st->next_step;
2627 if (d >= wd->zoom_step)
2628 { /* Report move in steps */
2629 st->next_step = st->info.zoom;
2631 ev_flag = _set_state(gesture_zoom,
2632 ELM_GESTURE_STATE_MOVE,
2633 &st->info, EINA_TRUE);
2634 consume_event(wd, event_info, event_type, ev_flag);
2636 } /* End of ZOOM_MOVE handling */
2641 case EVAS_CALLBACK_MOUSE_UP:
2642 case EVAS_CALLBACK_MULTI_UP:
2643 /* Reset timestamp of finger-up.This is used later
2644 by _zoom_test_reset() to retain finger-down data */
2645 consume_event(wd, event_info, event_type, ev_flag);
2646 if (((st->zoom_wheel) || (st->zoom_base)) &&
2647 (st->zoom_distance_tolerance == 0))
2649 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2650 &st->info, EINA_FALSE);
2651 consume_event(wd, event_info, event_type, ev_flag);
2656 /* if we got here not a ZOOM */
2657 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2658 { /* Must be != undefined, if gesture started */
2659 ev_flag = _set_state(gesture_zoom,
2660 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2661 consume_event(wd, event_info, event_type, ev_flag);
2664 _zoom_test_reset(gesture_zoom);
2674 _get_rotate_properties(Rotate_Type *st,
2675 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2676 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2679 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2680 &st->info.x, &st->info.y) / 2;
2682 *angle = get_angle(x1, y1, x2, y2);
2683 #if 0 /* (NOT YET SUPPORTED) */
2684 if (angle == &st->info.angle)
2685 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2686 st->info.momentum = (((*angle) - st->info.base_angle) /
2687 (fabs(tm2 - tm1))) * 1000;
2690 st->info.momentum = 0;
2700 * This function is used to test rotation gesture.
2701 * user may combine zoom, rotation together.
2702 * so its possible that both will be detected from input.
2703 * (both are two-finger movement-oriented gestures)
2705 * @param obj The gesture-layer object.
2706 * @param event_info Pointer to recent input event.
2707 * @param event_type Recent input event type.
2708 * @param g_type what Gesture we are testing.
2710 * @ingroup Elm_Gesture_Layer
2713 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2714 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2719 Widget_Data *wd = elm_widget_data_get(obj);
2721 if (!wd->gesture[g_type]) return;
2723 Gesture_Info *gesture = wd->gesture[g_type];
2724 Rotate_Type *st = gesture->data;
2729 { /* Allocated once on first time */
2730 st = calloc(1, sizeof(Rotate_Type));
2732 _rotate_test_reset(gesture);
2736 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2739 case EVAS_CALLBACK_MOUSE_MOVE:
2740 case EVAS_CALLBACK_MULTI_MOVE:
2741 /* if non-continues mode and gesture NOT started, ignore MOVE */
2742 if ((!wd->glayer_continues_enable) &&
2743 (!st->rotate_st.timestamp))
2746 case EVAS_CALLBACK_MOUSE_DOWN:
2747 case EVAS_CALLBACK_MULTI_DOWN:
2748 { /* Here we take care of rotate-start and rotate move */
2752 if(eina_list_count(wd->touched) > 2)
2753 { /* Process rotate only when 2 fingers on surface */
2754 ev_flag = _set_state(gesture,
2755 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2756 consume_event(wd, event_info, event_type, ev_flag);
2761 if (!st->rotate_st.timestamp)
2762 { /* Now scan touched-devices list and find other finger */
2763 EINA_LIST_FOREACH(wd->touched, l, p)
2764 { /* Device of other finger <> pe device */
2765 if (p->device != pe->device)
2770 return; /* Single finger on touch */
2772 /* Record down fingers */
2773 consume_event(wd, event_info, event_type, ev_flag);
2774 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2775 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2777 /* Set mv field as well to be ready for MOVE events */
2778 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2779 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2781 /* Here we have rotate_st, rotate_st1 set, report START */
2782 /* Set rotate-base after BOTH down events recorded */
2783 /* Compute length of line between fingers rotate start */
2784 _get_rotate_properties(st,
2785 st->rotate_st.x, st->rotate_st.y,
2786 st->rotate_st.timestamp,
2787 st->rotate_st1.x, st->rotate_st1.y,
2788 st->rotate_st1.timestamp, &st->info.base_angle);
2790 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2791 &st->info, EINA_FALSE);
2792 consume_event(wd, event_info, event_type, ev_flag);
2794 return; /* Rotate started */
2795 } /* End of ROTATE_START handling */
2798 /* if we got here, we have (exacally) two fingers on surfce */
2799 /* we also after START, report MOVE */
2800 /* First detect which finger moved */
2801 if (pe->device == st->rotate_mv.device)
2802 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2803 else if (pe->device == st->rotate_mv1.device)
2804 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2806 /* Compute change in rotate as fingers move */
2807 _get_rotate_properties(st,
2808 st->rotate_mv.x, st->rotate_mv.y,
2809 st->rotate_mv.timestamp,
2810 st->rotate_mv1.x, st->rotate_mv1.y,
2811 st->rotate_mv1.timestamp, &st->info.angle);
2813 if (rotation_broke_tolerance(st))
2814 { /* Rotation broke tolerance, report move */
2815 double d = st->info.angle - st->next_step;
2819 if (d >= wd->rotate_step)
2820 { /* Report move in steps */
2821 st->next_step = st->info.angle;
2823 ev_flag = _set_state(gesture,
2824 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2825 consume_event(wd, event_info, event_type, ev_flag);
2827 } /* End of ROTATE_MOVE handling */
2832 case EVAS_CALLBACK_MOUSE_UP:
2833 case EVAS_CALLBACK_MULTI_UP:
2834 consume_event(wd, event_info, event_type, ev_flag);
2835 /* Reset timestamp of finger-up.This is used later
2836 by rotate_test_reset() to retain finger-down data */
2837 if (st->rotate_angular_tolerance < 0)
2839 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2840 &st->info, EINA_FALSE);
2841 consume_event(wd, event_info, event_type, ev_flag);
2846 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2847 { /* Must be != undefined, if gesture started */
2848 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2849 &st->info, EINA_FALSE);
2850 consume_event(wd, event_info, event_type, ev_flag);
2853 _rotate_test_reset(gesture);
2864 * This function is used to save input events in an abstract struct
2865 * to be used later by getsure-testing functions.
2867 * @param data The gesture-layer object.
2868 * @param event_info Pointer to recent input event.
2869 * @param event_type Recent input event type.
2870 * @param pe The abstract data-struct (output).
2872 * @ingroup Elm_Gesture_Layer
2875 _make_pointer_event(void *data, void *event_info,
2876 Evas_Callback_Type event_type, Pointer_Event *pe)
2878 Widget_Data *wd = elm_widget_data_get(data);
2879 if (!wd) return EINA_FALSE;
2883 case EVAS_CALLBACK_MOUSE_DOWN:
2884 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2885 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2886 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2887 pe->device = ELM_MOUSE_DEVICE;
2890 case EVAS_CALLBACK_MOUSE_UP:
2891 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2892 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2893 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2894 pe->device = ELM_MOUSE_DEVICE;
2897 case EVAS_CALLBACK_MOUSE_MOVE:
2898 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2899 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2900 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2901 pe->device = ELM_MOUSE_DEVICE;
2904 case EVAS_CALLBACK_MULTI_DOWN:
2905 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2906 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2907 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2908 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2911 case EVAS_CALLBACK_MULTI_UP:
2912 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2913 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2914 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2915 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2918 case EVAS_CALLBACK_MULTI_MOVE:
2919 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2920 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2921 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2922 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2929 pe->event_type = event_type;
2936 * This function restartes line, flick, zoom and rotate gestures
2937 * when gesture-layer continues-gestures enabled.
2938 * Example of continues-gesture:
2939 * When doing a line, user stops moving finger but keeps fingers on touch.
2940 * This will cause line-end, then as user continues moving his finger
2941 * it re-starts line gesture.
2942 * When continue mode is disabled, user has to lift finger from touch
2943 * to end a gesture. Them touch-again to start a new one.
2945 * @param data The gesture-layer object.
2946 * @param wd gesture layer widget data.
2947 * @param states_reset flag that marks gestures were reset in history clear.
2949 * @ingroup Elm_Gesture_Layer
2951 void continues_gestures_restart(void *data, Eina_Bool states_reset)
2953 Widget_Data *wd = elm_widget_data_get(data);
2956 /* Run through events to restart gestures */
2958 Eina_Bool n_lines, n_flicks, zoom, rotate;
2959 /* We turn-on flag for finished, aborted, not-started gestures */
2960 g = wd->gesture[ELM_GESTURE_N_LINES];
2961 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2962 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2965 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
2966 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2970 g = wd->gesture[ELM_GESTURE_N_FLICKS];
2971 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2972 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2975 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
2976 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2980 g = wd->gesture[ELM_GESTURE_ZOOM];
2981 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2982 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2985 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
2986 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2990 g = wd->gesture[ELM_GESTURE_ROTATE];
2991 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2992 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2995 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
2996 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3004 * This function the core-function where input handling is done.
3005 * Here we get user input and stream it to gesture testing.
3006 * We notify user about any gestures with new state:
3008 * START - gesture started.
3009 * MOVE - gesture is ongoing.
3010 * END - gesture was completed.
3011 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3013 * We also check if a gesture was detected, then reset event history
3014 * If no gestures were found we reset gesture test flag
3015 * after streaming event-history to widget.
3016 * (stream to the widget all events not consumed as a gesture)
3018 * @param data The gesture-layer object.
3019 * @param event_info Pointer to recent input event.
3020 * @param event_type Recent input event type.
3022 * @ingroup Elm_Gesture_Layer
3025 _event_process(void *data, Evas_Object *obj __UNUSED__,
3026 void *event_info, Evas_Callback_Type event_type)
3029 Pointer_Event *pe = NULL;
3030 Widget_Data *wd = elm_widget_data_get(data);
3033 #if defined(DEBUG_GESTURE_LAYER)
3036 printf("Gesture | State | is tested\n");
3037 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3041 printf(" %d %d %d\n", i, g->state, g->test);
3045 /* Start testing candidate gesture from here */
3046 if (_make_pointer_event(data, event_info, event_type, &_pe))
3049 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3050 _n_long_tap_test(data, pe, event_info, event_type,
3051 ELM_GESTURE_N_LONG_TAPS);
3053 /* This takes care of single, double and tripple tap */
3054 _tap_gestures_test(data, pe, event_info, event_type);
3056 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3057 _momentum_test(data, pe, event_info, event_type,
3058 ELM_GESTURE_MOMENTUM);
3060 if (IS_TESTED(ELM_GESTURE_N_LINES))
3061 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3063 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3064 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3066 if (IS_TESTED(ELM_GESTURE_ZOOM))
3067 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3069 if (IS_TESTED(ELM_GESTURE_ZOOM))
3070 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3072 if (IS_TESTED(ELM_GESTURE_ROTATE))
3073 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3075 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3076 _event_history_add(data, event_info, event_type);
3077 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3078 (event_type == EVAS_CALLBACK_MULTI_UP))
3080 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3083 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3084 _event_history_add(data, event_info, event_type);
3088 /* Log event to restart gestures */
3089 wd->recent_device_event = _add_recent_device_event(wd->recent_device_event, &_pe);
3091 /* we maintain list of touched devices */
3092 /* We also use move to track current device x.y pos */
3093 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3094 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3095 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3096 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3098 wd->touched = _add_touched_device(wd->touched, pe);
3100 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3101 (event_type == EVAS_CALLBACK_MULTI_UP))
3103 wd->touched = _remove_touched_device(wd->touched, pe);
3106 /* Report current states and clear history if needed */
3107 Eina_Bool states_reset = _clear_if_finished(data);
3108 if (wd->glayer_continues_enable)
3109 continues_gestures_restart(data, states_reset);
3114 * For all _mouse_* / multi_* functions wethen send this event to
3115 * _event_process function.
3117 * @param data The gesture-layer object.
3118 * @param event_info Pointer to recent input event.
3120 * @ingroup Elm_Gesture_Layer
3123 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3126 Widget_Data *wd = elm_widget_data_get(data);
3128 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3129 return; /* We only process left-click at the moment */
3131 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3135 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3138 Widget_Data *wd = elm_widget_data_get(data);
3141 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3145 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3148 Widget_Data *wd = elm_widget_data_get(data);
3151 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3155 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3158 Widget_Data *wd = elm_widget_data_get(data);
3161 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3165 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3168 Widget_Data *wd = elm_widget_data_get(data);
3171 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3172 return; /* We only process left-click at the moment */
3174 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3178 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3181 Widget_Data *wd = elm_widget_data_get(data);
3184 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3188 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3191 Widget_Data *wd = elm_widget_data_get(data);
3194 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3198 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3201 Widget_Data *wd = elm_widget_data_get(data);
3204 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3208 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3211 Widget_Data *wd = elm_widget_data_get(data);
3214 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3218 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3220 Widget_Data *wd = elm_widget_data_get(obj);
3221 if (!wd) return EINA_FALSE;
3223 return !wd->repeat_events;
3227 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3229 Widget_Data *wd = elm_widget_data_get(obj);
3232 wd->repeat_events = !r;
3236 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3238 Widget_Data *wd = elm_widget_data_get(obj);
3248 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3250 Widget_Data *wd = elm_widget_data_get(obj);
3256 wd->rotate_step = s;
3260 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3262 Widget_Data *wd = elm_widget_data_get(obj);
3263 if (!wd) return EINA_FALSE;
3268 /* if was attached before, unregister callbacks first */
3270 _unregister_callbacks(obj);
3274 _register_callbacks(obj);
3279 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3280 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3282 Widget_Data *wd = elm_widget_data_get(obj);
3286 if (!wd->gesture[idx])
3287 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3288 if (!wd->gesture[idx]) return;
3290 p = wd->gesture[idx];
3293 p->fn[cb_type].cb = cb;
3294 p->fn[cb_type].user_data = data;
3295 p->state = ELM_GESTURE_STATE_UNDEFINED;
3300 _disable_hook(Evas_Object *obj)
3302 if (elm_widget_disabled_get(obj))
3303 _unregister_callbacks(obj);
3305 _register_callbacks(obj);
3309 elm_gesture_layer_add(Evas_Object *parent)
3315 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3317 wd = ELM_NEW(Widget_Data);
3318 e = evas_object_evas_get(parent);
3319 if (!e) return NULL;
3320 obj = elm_widget_add(e);
3321 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3322 elm_widget_type_set(obj, "gesture_layer");
3323 elm_widget_sub_object_add(parent, obj);
3324 elm_widget_data_set(obj, wd);
3325 elm_widget_del_hook_set(obj, _del_hook);
3326 elm_widget_disable_hook_set(obj, _disable_hook);
3329 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3330 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3331 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3332 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3333 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3334 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3335 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3336 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3337 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3338 wd->repeat_events = EINA_TRUE;
3339 wd->glayer_continues_enable = EINA_FALSE;//_elm_config->glayer_continues_enable;
3341 #if defined(DEBUG_GESTURE_LAYER)
3342 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3343 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);
3345 memset(wd->gesture, 0, sizeof(wd->gesture));