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
12 /* Some Trigo values */
13 #define RAD_90DEG M_PI_2
14 #define RAD_180DEG M_PI
15 #define RAD_270DEG (M_PI_2 * 3)
16 #define RAD_360DEG (M_PI * 2)
17 /* #define DEBUG_GESTURE_LAYER 1 */
20 _glayer_bufdup(void *buf, size_t size)
27 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
30 #define SET_TEST_BIT(P) do { \
31 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; \
34 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
40 * Struct holds callback information.
42 * @ingroup Elm_Gesture_Layer
46 void *user_data; /**< Holds user data to CB (like sd) */
47 Elm_Gesture_Event_Cb cb;
54 * type for callback information
56 * @ingroup Elm_Gesture_Layer
58 typedef struct _Func_Data Func_Data;
63 * @struct _Gesture_Info
64 * Struct holds gesture info
66 * @ingroup Elm_Gesture_Layer
71 void *data; /**< Holds gesture intemidiate processing data */
72 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
73 Elm_Gesture_Types g_type; /**< gesture type */
74 Elm_Gesture_State state; /**< gesture state */
75 void *info; /**< Data for the state callback */
76 Eina_Bool test; /**< if true this gesture should be tested on input */
82 * @typedef Gesture_Info
83 * Type for _Gesture_Info
85 * @ingroup Elm_Gesture_Layer
87 typedef struct _Gesture_Info Gesture_Info;
92 * @struct _Event_History
93 * Struct holds event history.
94 * These events are repeated if no gesture found.
96 * @ingroup Elm_Gesture_Layer
102 Evas_Callback_Type event_type;
108 * @typedef Event_History
109 * Type for _Event_History
111 * @ingroup Elm_Gesture_Layer
113 typedef struct _Event_History Event_History;
118 * @struct _Pointer_Event
119 * Struct holds pointer-event info
120 * This is a generic pointer event structure
122 * @ingroup Elm_Gesture_Layer
124 struct _Pointer_Event
127 unsigned int timestamp;
129 Evas_Callback_Type event_type;
135 * @typedef Pointer_Event
136 * Type for generic pointer event structure
138 * @ingroup Elm_Gesture_Layer
140 typedef struct _Pointer_Event Pointer_Event;
142 /* All *Type structs hold result for the user in 'info' field
143 * The rest is gesture processing intermediate data.
144 * NOTE: info field must be FIRST in the struct.
145 * This is used when reporting ABORT in event_history_clear() */
148 Elm_Gesture_Taps_Info info;
151 unsigned int n_taps_needed;
155 typedef struct _Taps_Type Taps_Type;
157 struct _Long_Tap_Type
159 Elm_Gesture_Taps_Info info;
162 unsigned int max_touched;
163 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
166 typedef struct _Long_Tap_Type Long_Tap_Type;
168 struct _Momentum_Type
169 { /* Fields used by _line_test() */
170 Elm_Gesture_Momentum_Info info;
171 Evas_Coord_Point line_st;
172 Evas_Coord_Point line_end;
173 unsigned int t_st_x; /* Time start on X */
174 unsigned int t_st_y; /* Time start on Y */
175 unsigned int t_end; /* Time end */
176 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 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
212 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
215 typedef struct _Zoom_Type Zoom_Type;
218 { /* Fields used by _rotation_test() */
219 Elm_Gesture_Rotate_Info info;
220 Pointer_Event rotate_st;
221 Pointer_Event rotate_mv;
222 Pointer_Event rotate_st1;
223 Pointer_Event rotate_mv1;
224 double rotate_angular_tolerance;
226 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
227 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
229 typedef struct _Rotate_Type Rotate_Type;
233 Evas_Object *target; /* Target Widget */
234 Event_History *event_history_list;
237 Evas_Coord zoom_distance_tolerance;
238 Evas_Coord line_distance_tolerance;
239 double line_angular_tolerance;
240 double zoom_wheel_factor; /* mouse wheel zoom steps */
241 double zoom_finger_factor; /* used for zoom factor */
242 double rotate_angular_tolerance;
243 unsigned int flick_time_limit_ms;
244 double long_tap_start_timeout;
245 Eina_Bool glayer_continues_enable;
250 Gesture_Info *gesture[ELM_GESTURE_LAST];
251 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
252 Eina_List *pending; /* List of devices need to refeed *UP event */
253 Eina_List *touched; /* Information of touched devices */
254 Eina_List *recent_device_event; /* Information of recent pe event of each device */
256 Eina_Bool repeat_events : 1;
258 typedef struct _Widget_Data Widget_Data;
260 static const char *widtype = NULL;
261 static void _del_hook(Evas_Object *obj);
263 static Eina_Bool _event_history_clear(Evas_Object *obj);
264 static void _reset_states(Widget_Data *wd);
265 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
266 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
267 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
268 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
269 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
270 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
271 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
273 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
274 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
275 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
277 /* START - Functions to manage touched-device list */
280 * This function is used to find if device is touched
282 * @ingroup Elm_Gesture_Layer
285 compare_device(const void *data1, const void *data2)
286 { /* Compare the two device numbers */
287 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
293 * Remove Pointer Event from touched device list
294 * @param list Pointer to touched device list.
295 * @param Pointer_Event Pointer to PE.
297 * @ingroup Elm_Gesture_Layer
300 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
302 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
306 return eina_list_remove(list, p);
315 * Recoed Pointer Event in touched device list
316 * Note: This fuction allocates memory for PE event
317 * This memory is released in _remove_touched_device()
318 * @param list Pointer to touched device list.
319 * @param Pointer_Event Pointer to PE.
321 * @ingroup Elm_Gesture_Layer
324 _add_touched_device(Eina_List *list, Pointer_Event *pe)
326 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
328 { /* We like to track device touch-position, overwrite info */
329 memcpy(p, pe, sizeof(Pointer_Event));
333 p = malloc(sizeof(Pointer_Event));
334 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
335 return eina_list_append(list, p);
337 /* END - Functions to manage touched-device list */
339 /* START - Functions to manage recent device event list */
340 /* This list holds the recent-event for each device */
341 /* it will hold a single recent-event for each device */
342 /* We are using those PE events of this list to */
343 /* send them later to test funcs to restart gestures */
344 /* We only keep DOWN, MOVE events in this list. */
345 /* So when no touch this list is empty. */
349 * Recoed Pointer Event in touched device list
350 * Note: This fuction allocates memory for PE event
351 * This memory is released here when device untouched
353 * @param list Pointer to touched device list.
354 * @param Pointer_Event Pointer to PE.
356 * @ingroup Elm_Gesture_Layer
359 _add_recent_device_event(Eina_List *list, Pointer_Event *pe)
361 void *data = eina_list_search_sorted(list, compare_device, pe);
363 Pointer_Event *p = NULL;
364 if(data) /* First remove recent event for this device */
365 l = eina_list_remove(list, data);
368 switch(pe->event_type)
370 case EVAS_CALLBACK_MOUSE_DOWN:
371 case EVAS_CALLBACK_MOUSE_MOVE:
372 case EVAS_CALLBACK_MULTI_DOWN:
373 case EVAS_CALLBACK_MULTI_MOVE:
374 p = malloc(sizeof(Pointer_Event));
375 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in here or on cleanup */
376 l = eina_list_sorted_insert(l, compare_device, p);
379 /* Kept those cases for referance */
380 case EVAS_CALLBACK_MOUSE_IN:
381 case EVAS_CALLBACK_MOUSE_OUT:
382 case EVAS_CALLBACK_MOUSE_WHEEL:
383 case EVAS_CALLBACK_MOUSE_UP:
384 case EVAS_CALLBACK_MULTI_UP:
385 case EVAS_CALLBACK_KEY_DOWN:
386 case EVAS_CALLBACK_KEY_UP:
395 /* END - Functions to manage recent device event list */
401 * @param event_info pointer to event.
403 * @ingroup Elm_Gesture_Layer
405 static Evas_Event_Flags
406 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
410 case EVAS_CALLBACK_MOUSE_IN:
411 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
412 case EVAS_CALLBACK_MOUSE_OUT:
413 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
414 case EVAS_CALLBACK_MOUSE_DOWN:
415 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
416 case EVAS_CALLBACK_MOUSE_MOVE:
417 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
418 case EVAS_CALLBACK_MOUSE_UP:
419 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
420 case EVAS_CALLBACK_MOUSE_WHEEL:
421 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
422 case EVAS_CALLBACK_MULTI_DOWN:
423 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
424 case EVAS_CALLBACK_MULTI_MOVE:
425 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
426 case EVAS_CALLBACK_MULTI_UP:
427 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
428 case EVAS_CALLBACK_KEY_DOWN:
429 return ((Evas_Event_Key_Down *) event_info)->event_flags;
430 case EVAS_CALLBACK_KEY_UP:
431 return ((Evas_Event_Key_Up *) event_info)->event_flags;
433 return EVAS_EVENT_FLAG_NONE;
440 * Sets event flag to value returned from user callback
441 * @param wd Widget Data
442 * @param event_info pointer to event.
443 * @param event_type what type was ev (mouse down, etc...)
444 * @param ev_flags event flags
446 * @ingroup Elm_Gesture_Layer
449 consume_event(Widget_Data *wd, void *event_info,
450 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
451 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
452 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
453 /* should not refeed this event. */
455 return; /* This happens when restarting gestures */
457 if ((ev_flags) || (!wd->repeat_events))
461 case EVAS_CALLBACK_MOUSE_DOWN:
462 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
464 case EVAS_CALLBACK_MOUSE_MOVE:
465 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
467 case EVAS_CALLBACK_MOUSE_UP:
468 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
470 case EVAS_CALLBACK_MOUSE_WHEEL:
471 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
473 case EVAS_CALLBACK_MULTI_DOWN:
474 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
476 case EVAS_CALLBACK_MULTI_MOVE:
477 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
479 case EVAS_CALLBACK_MULTI_UP:
480 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
482 case EVAS_CALLBACK_KEY_DOWN:
483 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
485 case EVAS_CALLBACK_KEY_UP:
486 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
497 * Report current state of a gesture by calling user callback.
498 * @param gesture what gesture state we report.
499 * @param info inforamtion for user callback
501 * @ingroup Elm_Gesture_Layer
503 static Evas_Event_Flags
504 _report_state(Gesture_Info *gesture, void *info)
505 { /* We report current state (START, MOVE, END, ABORT), once */
506 #if defined(DEBUG_GESTURE_LAYER)
507 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
510 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
511 (gesture->fn[gesture->state].cb))
512 { /* Fill state-info struct and send ptr to user callback */
513 return gesture->fn[gesture->state].cb(
514 gesture->fn[gesture->state].user_data, info);
517 return EVAS_EVENT_FLAG_NONE;
523 * Update state for a given gesture.
524 * We may update gesture state to:
525 * UNDEFINED - current input did not start gesure yet.
526 * START - gesture started according to input.
527 * MOVE - gusture in progress.
528 * END - gesture completed according to input.
529 * ABORT - input does not matches gesure.
530 * note that we may move from UNDEFINED to ABORT
531 * because we may detect that gesture will not START
532 * with a given input.
534 * @param g given gesture to change state.
535 * @param s gesure new state.
536 * @param info buffer to be sent to user callback on report_state.
537 * @param force makes report_state to report the new-state even
538 * if its same as current state. Works for MOVE - gesture in progress.
540 * @ingroup Elm_Gesture_Layer
542 static Evas_Event_Flags
543 _set_state(Gesture_Info *g, Elm_Gesture_State s,
544 void *info, Eina_Bool force)
546 Elm_Gesture_State old_state;
547 if ((g->state == s) && (!force))
548 return EVAS_EVENT_FLAG_NONE;
550 old_state = g->state;
553 g->info = info; /* Information for user callback */
554 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
555 (g->state == ELM_GESTURE_STATE_END))
556 g->test = EINA_FALSE;
558 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
559 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
560 (s == ELM_GESTURE_STATE_ABORT))))
561 return _report_state(g, g->info);
563 return EVAS_EVENT_FLAG_NONE;
569 * This resets all gesture states and sets test-bit.
570 * this is used for restarting gestures to listen to input.
571 * happens after we complete a gesture or no gesture was detected.
572 * @param wd Widget data of the gesture-layer object.
574 * @ingroup Elm_Gesture_Layer
577 _reset_states(Widget_Data *wd)
581 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
586 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
595 * if gesture was NOT detected AND we only have gestures in ABORT state
596 * we clear history immediately to be ready for input.
598 * @param obj The gesture-layer object.
599 * @return TRUE on event history_clear
601 * @ingroup Elm_Gesture_Layer
604 _clear_if_finished(Evas_Object *obj)
606 Widget_Data *wd = elm_widget_data_get(obj);
607 if (!wd) return EINA_FALSE;
610 /* Clear history if all we have aborted gestures */
611 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
612 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
613 { /* If no gesture started and all we have aborted gestures, reset all */
614 Gesture_Info *p = wd->gesture[i];
615 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
617 if ((p->state == ELM_GESTURE_STATE_START) ||
618 (p->state == ELM_GESTURE_STATE_MOVE))
619 reset_s = EINA_FALSE;
621 all_undefined = EINA_FALSE;
625 if (reset_s && (!all_undefined))
626 return _event_history_clear(obj);
632 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
634 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
650 /* All *test_reset() funcs are called to clear
651 * gesture intermediate data.
652 * This happens when we need to reset our tests.
653 * for example when gesture is detected or all ABORTed. */
655 _tap_gestures_test_reset(Gesture_Info *gesture)
660 Widget_Data *wd = elm_widget_data_get(gesture->obj);
661 wd->dbl_timeout = NULL;
668 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
669 EINA_LIST_FREE(data, pe)
672 memset(gesture->data, 0, sizeof(Taps_Type));
675 /* All *test_reset() funcs are called to clear
676 * gesture intermediate data.
677 * This happens when we need to reset our tests.
678 * for example when gesture is detected or all ABORTed. */
680 _n_long_tap_test_reset(Gesture_Info *gesture)
688 Long_Tap_Type *st = gesture->data;
691 EINA_LIST_FOREACH(st->touched, l, p)
694 eina_list_free(st->touched);
695 if (st->timeout) ecore_timer_del(st->timeout);
696 memset(gesture->data, 0, sizeof(Long_Tap_Type));
700 _momentum_test_reset(Gesture_Info *gesture)
708 memset(gesture->data, 0, sizeof(Momentum_Type));
712 _line_data_reset(Line_Data *st)
717 memset(st, 0, sizeof(Line_Data));
718 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
722 _line_test_reset(Gesture_Info *gesture)
730 Line_Type *st = gesture->data;
731 Eina_List *list = st->list;
734 EINA_LIST_FOREACH(list, l, t_line)
737 eina_list_free(list);
742 _zoom_test_reset(Gesture_Info *gesture)
750 Widget_Data *wd = elm_widget_data_get(gesture->obj);
751 Zoom_Type *st = gesture->data;
752 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
753 evas_object_evas_get(wd->target), "Control");
754 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
755 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
757 memset(st, 0, sizeof(Zoom_Type));
758 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
763 _rotate_test_reset(Gesture_Info *gesture)
771 Widget_Data *wd = elm_widget_data_get(gesture->obj);
772 Rotate_Type *st = gesture->data;
774 memset(st, 0, sizeof(Rotate_Type));
775 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
776 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
783 * We register callbacks when gesture layer is attached to an object
784 * or when its enabled after disable.
786 * @param obj The gesture-layer object.
788 * @ingroup Elm_Gesture_Layer
791 _register_callbacks(Evas_Object *obj)
793 Widget_Data *wd = elm_widget_data_get(obj);
798 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
800 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
802 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
805 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
808 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
810 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
812 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
815 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
817 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
825 * We unregister callbacks when gesture layer is disabled.
827 * @param obj The gesture-layer object.
829 * @ingroup Elm_Gesture_Layer
832 _unregister_callbacks(Evas_Object *obj)
834 Widget_Data *wd = elm_widget_data_get(obj);
839 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
841 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
843 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
846 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
849 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
852 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
855 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
858 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
860 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
865 /* START - Event history list handling functions */
868 * This function is used to find if device number
869 * is found in a list of devices.
870 * The list contains devices for refeeding *UP event
872 * @ingroup Elm_Gesture_Layer
875 device_in_pending_list(const void *data1, const void *data2)
876 { /* Compare the two device numbers */
877 return (((intptr_t) data1) - ((intptr_t) data2));
883 * This functions adds device to refeed-pending device list
884 * @ingroup Elm_Gesture_Layer
887 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
889 int device = ELM_MOUSE_DEVICE;
892 case EVAS_CALLBACK_MOUSE_DOWN:
894 case EVAS_CALLBACK_MULTI_DOWN:
895 device = ((Evas_Event_Multi_Down *) event)->device;
901 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
904 return eina_list_append(list, (intptr_t*) device);
913 * This functions returns pending-device node
914 * @ingroup Elm_Gesture_Layer
917 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
919 int device = ELM_MOUSE_DEVICE;
922 case EVAS_CALLBACK_MOUSE_UP:
924 case EVAS_CALLBACK_MULTI_UP:
925 device = ((Evas_Event_Multi_Up *) event)->device;
931 return eina_list_search_unsorted_list(list, device_in_pending_list,
932 (intptr_t *) device);
938 * This function reports ABORT to all none-detected gestures
939 * Then resets test bits for all desired gesures
940 * and clears input-events history.
941 * note: if no gesture was detected, events from history list
942 * are streamed to the widget because it's unused by layer.
943 * user may cancel refeed of events by setting repeat events.
945 * @param obj The gesture-layer object.
947 * @ingroup Elm_Gesture_Layer
950 _event_history_clear(Evas_Object *obj)
952 Widget_Data *wd = elm_widget_data_get(obj);
953 if (!wd) return EINA_FALSE;
957 Evas *e = evas_object_evas_get(obj);
958 Eina_Bool gesture_found = EINA_FALSE;
959 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
964 if (p->state == ELM_GESTURE_STATE_END)
965 gesture_found = EINA_TRUE;
967 { /* Report ABORT to all gestures that still not finished */
968 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
974 _reset_states(wd); /* we are ready to start testing for gestures again */
976 /* Clear all gestures intermediate data */
977 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
978 { /* We do not clear a long-tap gesture if fingers still on surface */
979 /* and gesture timer still pending to test gesture state */
980 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
981 if ((st) && /* st not allocated if clear occurs before 1st input */
982 ((!eina_list_count(st->touched)) || (!st->timeout)))
983 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
988 ecore_timer_del(wd->dbl_timeout);
989 wd->dbl_timeout = NULL;
992 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
993 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
994 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
995 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
996 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
997 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
998 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
999 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
1001 /* Disable gesture layer so refeeded events won't be consumed by it */
1002 _unregister_callbacks(obj);
1003 while (wd->event_history_list)
1006 t = wd->event_history_list;
1007 Eina_List *pending = _device_is_pending(wd->pending,
1008 wd->event_history_list->event,
1009 wd->event_history_list->event_type);
1011 /* Refeed events if no gesture matched input */
1012 if (pending || ((!gesture_found) && (!wd->repeat_events)))
1014 evas_event_refeed_event(e, wd->event_history_list->event,
1015 wd->event_history_list->event_type);
1019 wd->pending = eina_list_remove_list(wd->pending, pending);
1020 int device = ELM_MOUSE_DEVICE;
1021 if (wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
1022 device = ((Evas_Event_Multi_Up *)
1023 (wd->event_history_list->event))->device;
1026 wd->pending = _add_device_pending(wd->pending,
1027 wd->event_history_list->event,
1028 wd->event_history_list->event_type);
1031 free(wd->event_history_list->event);
1032 wd->event_history_list = (Event_History *) eina_inlist_remove(
1033 EINA_INLIST_GET(wd->event_history_list),
1034 EINA_INLIST_GET(wd->event_history_list));
1037 _register_callbacks(obj);
1044 * This function copies input events.
1045 * We copy event info before adding it to history.
1046 * The memory is freed when we clear history.
1048 * @param event the event to copy
1049 * @param event_type event type to copy
1051 * @ingroup Elm_Gesture_Layer
1054 _copy_event_info(void *event, Evas_Callback_Type event_type)
1058 case EVAS_CALLBACK_MOUSE_DOWN:
1059 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1061 case EVAS_CALLBACK_MOUSE_MOVE:
1062 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1064 case EVAS_CALLBACK_MOUSE_UP:
1065 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1067 case EVAS_CALLBACK_MOUSE_WHEEL:
1068 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1070 case EVAS_CALLBACK_MULTI_DOWN:
1071 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1073 case EVAS_CALLBACK_MULTI_MOVE:
1074 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1076 case EVAS_CALLBACK_MULTI_UP:
1077 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1079 case EVAS_CALLBACK_KEY_DOWN:
1080 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1082 case EVAS_CALLBACK_KEY_UP:
1083 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1091 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1093 Widget_Data *wd = elm_widget_data_get(obj);
1095 if (!wd) return EINA_FALSE;
1097 ev = malloc(sizeof(Event_History));
1098 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1099 ev->event_type = event_type;
1100 wd->event_history_list = (Event_History *) eina_inlist_append(
1101 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1105 /* END - Event history list handling functions */
1108 _del_hook(Evas_Object *obj)
1110 Widget_Data *wd = elm_widget_data_get(obj);
1113 _event_history_clear(obj);
1114 eina_list_free(wd->pending);
1116 Pointer_Event *data;
1117 EINA_LIST_FREE(wd->touched, data)
1120 EINA_LIST_FREE(wd->recent_device_event, data)
1123 if (!elm_widget_disabled_get(obj))
1124 _unregister_callbacks(obj);
1126 /* Free all gestures internal data structures */
1128 for (i = 0; i < ELM_GESTURE_LAST; i++)
1131 if (wd->gesture[i]->data)
1132 free(wd->gesture[i]->data);
1134 free(wd->gesture[i]);
1141 compare_match_fingers(const void *data1, const void *data2)
1142 { /* Compare coords of first item in list to cur coords */
1143 const Pointer_Event *pe1 = eina_list_data_get(data1);
1144 const Pointer_Event *pe2 = data2;
1146 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1148 else if (pe1->x < pe2->x)
1152 if (pe1->x == pe2->x)
1153 return pe1->y - pe2->y;
1160 compare_pe_device(const void *data1, const void *data2)
1161 { /* Compare coords of first item in list to cur coords */
1162 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1163 const Pointer_Event *pe2 = data2;
1165 /* Only match if last was a down event */
1166 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1167 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1171 if (pe1->device == pe2->device)
1173 else if (pe1->device < pe2->device)
1180 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1181 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1182 { /* Keep copy of pe and record it in list */
1183 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1184 memcpy(p, pe, sizeof(Pointer_Event));
1185 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1191 /* This will also update middle-point to report to user later */
1192 st->info.x = st->sum_x / st->n_taps;
1193 st->info.y = st->sum_y / st->n_taps;
1194 st->info.timestamp = pe->timestamp;
1198 pe_list = eina_list_append(pe_list, p);
1199 st->l = eina_list_append(st->l, pe_list);
1202 pe_list = eina_list_append(pe_list, p);
1210 * This function sets state a tap-gesture to END or ABORT
1212 * @param data gesture info pointer
1214 * @ingroup Elm_Gesture_Layer
1217 _tap_gesture_finish(void *data)
1218 { /* This function will test each tap gesture when timer expires */
1219 Gesture_Info *gesture = data;
1220 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1221 /* Here we check if taps-gesture was completed successfuly */
1222 /* Count how many taps were recieved on each device then */
1223 /* determine if it matches n_taps_needed defined on START */
1224 Taps_Type *st = gesture->data;
1227 EINA_LIST_FOREACH(st->l, l, pe_list)
1229 if (eina_list_count(pe_list) != st->n_taps_needed)
1230 { /* No match taps number on device, ABORT */
1231 s = ELM_GESTURE_STATE_ABORT;
1236 st->info.n = eina_list_count(st->l);
1237 _set_state(gesture, s, gesture->info, EINA_FALSE);
1238 _tap_gestures_test_reset(gesture);
1244 * when this timer expires we finish tap gestures.
1246 * @param data The gesture-layer object.
1247 * @return cancles callback for this timer.
1249 * @ingroup Elm_Gesture_Layer
1252 _multi_tap_timeout(void *data)
1254 Widget_Data *wd = elm_widget_data_get(data);
1255 if (!wd) return EINA_FALSE;
1257 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1258 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1260 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1261 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1263 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1264 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1266 _clear_if_finished(data);
1267 wd->dbl_timeout = NULL;
1268 return ECORE_CALLBACK_CANCEL;
1274 * when this timer expires we START long tap gesture
1276 * @param data The gesture-layer object.
1277 * @return cancles callback for this timer.
1279 * @ingroup Elm_Gesture_Layer
1282 _long_tap_timeout(void *data)
1284 Gesture_Info *gesture = data;
1285 Long_Tap_Type *st = gesture->data;
1288 _set_state(gesture, ELM_GESTURE_STATE_START,
1289 gesture->data, EINA_FALSE);
1291 return ECORE_CALLBACK_CANCEL;
1298 * This function checks if a tap gesture should start
1300 * @param wd Gesture Layer Widget Data.
1301 * @param pe The recent input event as stored in pe struct.
1302 * @param event_info Original input event pointer.
1303 * @param event_type Type of original input event.
1304 * @param gesture what gesture is tested
1305 * @param how many taps for this gesture (1, 2 or 3)
1307 * @return Flag to determine if we need to set a timer for finish
1309 * @ingroup Elm_Gesture_Layer
1312 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1313 void *event_info, Evas_Callback_Type event_type,
1314 Gesture_Info *gesture, int taps)
1315 { /* Here we fill Tap struct */
1316 Taps_Type *st = gesture->data;
1318 { /* Allocated once on first time */
1319 st = calloc(1, sizeof(Taps_Type));
1321 _tap_gestures_test_reset(gesture);
1324 Eina_List *pe_list = NULL;
1325 Pointer_Event *pe_down = NULL;
1326 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1327 switch (pe->event_type)
1329 case EVAS_CALLBACK_MULTI_DOWN:
1330 case EVAS_CALLBACK_MOUSE_DOWN:
1331 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1332 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1333 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1334 { /* This is the first mouse down we got */
1335 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1336 &st->info, EINA_FALSE);
1337 consume_event(wd, event_info, event_type, ev_flag);
1339 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1346 case EVAS_CALLBACK_MULTI_UP:
1347 case EVAS_CALLBACK_MOUSE_UP:
1348 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1352 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1355 case EVAS_CALLBACK_MULTI_MOVE:
1356 case EVAS_CALLBACK_MOUSE_MOVE:
1357 /* Get first event in first list, this has to be a Mouse Down event */
1358 /* and verify that user didn't move out of this area before next tap */
1359 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1362 pe_down = eina_list_data_get(pe_list);
1363 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1365 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1366 &st->info, EINA_FALSE);
1367 consume_event(wd, event_info, event_type, ev_flag);
1383 * This function checks all click/tap and double/triple taps
1385 * @param obj The gesture-layer object.
1386 * @param pe The recent input event as stored in pe struct.
1387 * @param event_info Original input event pointer.
1388 * @param event_type Type of original input event.
1390 * @ingroup Elm_Gesture_Layer
1393 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1394 void *event_info, Evas_Callback_Type event_type)
1395 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1396 Eina_Bool need_timer = EINA_FALSE;
1397 Widget_Data *wd = elm_widget_data_get(obj);
1400 if (!pe) /* this happens when unhandled event arrived */
1401 return; /* see _make_pointer_event function */
1403 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1404 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1405 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1407 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1408 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1409 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1411 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1412 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1413 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1415 if ((need_timer) && (!wd->dbl_timeout))
1416 { /* Set a timer to finish these gestures */
1417 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1425 * This function computes center-point for long-tap gesture
1427 * @param st Long Tap gesture info pointer
1428 * @param pe The recent input event as stored in pe struct.
1430 * @ingroup Elm_Gesture_Layer
1433 _compute_taps_center(Long_Tap_Type *st,
1434 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1436 if(!eina_list_count(st->touched))
1441 Evas_Coord x = 0, y = 0;
1442 EINA_LIST_FOREACH(st->touched, l, p)
1443 { /* Accumulate all then take avarage */
1444 if (p->device == pe->device)
1445 { /* This will take care of values coming from MOVE event */
1456 *x_out = x / eina_list_count(st->touched);
1457 *y_out = y / eina_list_count(st->touched);
1463 * This function checks N long-tap gesture.
1465 * @param obj The gesture-layer object.
1466 * @param pe The recent input event as stored in pe struct.
1467 * @param event_info Original input event pointer.
1468 * @param event_type Type of original input event.
1469 * @param g_type what Gesture we are testing.
1470 * @param taps How many click/taps we test for.
1472 * @ingroup Elm_Gesture_Layer
1475 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1476 void *event_info, Evas_Callback_Type event_type,
1477 Elm_Gesture_Types g_type)
1478 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1479 Widget_Data *wd = elm_widget_data_get(obj);
1482 if (!pe) /* this happens when unhandled event arrived */
1483 return; /* see _make_pointer_event function */
1484 Gesture_Info *gesture = wd->gesture[g_type];
1485 if (!gesture) return;
1487 Long_Tap_Type *st = gesture->data;
1489 { /* Allocated once on first time */
1490 st = calloc(1, sizeof(Long_Tap_Type));
1492 _n_long_tap_test_reset(gesture);
1495 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1496 switch (pe->event_type)
1498 case EVAS_CALLBACK_MULTI_DOWN:
1499 case EVAS_CALLBACK_MOUSE_DOWN:
1500 st->touched = _add_touched_device(st->touched, pe);
1501 st->info.n = eina_list_count(st->touched);
1502 if (st->info.n > st->max_touched)
1503 st->max_touched = st->info.n;
1505 { /* User removed finger from touch, then put back - ABORT */
1506 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1507 (gesture->state == ELM_GESTURE_STATE_MOVE))
1509 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1510 &st->info, EINA_FALSE);
1511 consume_event(wd, event_info, event_type, ev_flag);
1515 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1516 { /* This is the first mouse down we got */
1517 st->info.timestamp = pe->timestamp;
1519 /* To test long tap */
1520 /* When this timer expires, gesture STARTED */
1522 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1523 _long_tap_timeout, gesture);
1526 consume_event(wd, event_info, event_type, ev_flag);
1527 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1528 st->center_x = st->info.x;
1529 st->center_y = st->info.y;
1532 case EVAS_CALLBACK_MULTI_UP:
1533 case EVAS_CALLBACK_MOUSE_UP:
1534 st->touched = _remove_touched_device(st->touched, pe);
1535 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1537 ((gesture->state == ELM_GESTURE_STATE_START) ||
1538 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1539 { /* Report END only for gesture that STARTed */
1540 if (eina_list_count(st->touched) == 0)
1541 { /* Report END only at last release event */
1542 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1543 &st->info, EINA_FALSE);
1544 consume_event(wd, event_info, event_type, ev_flag);
1548 { /* Stop test, user lifts finger before long-start */
1549 if (st->timeout) ecore_timer_del(st->timeout);
1551 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1552 &st->info, EINA_FALSE);
1553 consume_event(wd, event_info, event_type, ev_flag);
1558 case EVAS_CALLBACK_MULTI_MOVE:
1559 case EVAS_CALLBACK_MOUSE_MOVE:
1561 ((gesture->state == ELM_GESTURE_STATE_START) ||
1562 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1563 { /* Report MOVE only if STARTED */
1566 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1568 _compute_taps_center(st, &x, &y, pe);
1569 /* ABORT if user moved fingers out of tap area */
1570 #if defined(DEBUG_GESTURE_LAYER)
1571 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1573 if (!_inside(x, y, st->center_x, st->center_y))
1574 state_to_report = ELM_GESTURE_STATE_ABORT;
1576 /* Report MOVE if gesture started */
1577 ev_flag = _set_state(gesture, state_to_report,
1578 &st->info, EINA_TRUE);
1579 consume_event(wd, event_info, event_type, ev_flag);
1591 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1592 * This momentum value will be sent to widget when gesture is completed.
1594 * @param momentum pointer to buffer where we record momentum value.
1595 * @param x1 x coord where user started gesture.
1596 * @param y1 y coord where user started gesture.
1597 * @param x2 x coord where user completed gesture.
1598 * @param y2 y coord where user completed gesture.
1599 * @param t1x timestamp for X, when user started gesture.
1600 * @param t1y timestamp for Y, when user started gesture.
1601 * @param t2 timestamp when user completed gesture.
1603 * @ingroup Elm_Gesture_Layer
1606 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1607 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1610 Evas_Coord velx = 0, vely = 0, vel;
1611 Evas_Coord dx = x2 - x1;
1612 Evas_Coord dy = y2 - y1;
1616 velx = (dx * 1000) / dtx;
1619 vely = (dy * 1000) / dty;
1621 vel = sqrt((velx * velx) + (vely * vely));
1623 if ((_elm_config->thumbscroll_friction > 0.0) &&
1624 (vel > _elm_config->thumbscroll_momentum_threshold))
1625 { /* report momentum */
1626 momentum->mx = velx;
1627 momentum->my = vely;
1639 * This function is used for computing rotation angle (DEG).
1641 * @param x1 first finger x location.
1642 * @param y1 first finger y location.
1643 * @param x2 second finger x location.
1644 * @param y2 second finger y location.
1646 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1648 * @ingroup Elm_Gesture_Layer
1651 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1657 if (((int) xx) && ((int) yy))
1664 return RAD_360DEG - a;
1675 return RAD_180DEG + a;
1679 return RAD_180DEG - a;
1685 { /* Horizontal line */
1710 * This function is used for computing the magnitude and direction
1711 * of vector between two points.
1713 * @param x1 first finger x location.
1714 * @param y1 first finger y location.
1715 * @param x2 second finger x location.
1716 * @param y2 second finger y location.
1717 * @param l length computed (output)
1718 * @param a angle computed (output)
1720 * @ingroup Elm_Gesture_Layer
1723 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1724 Evas_Coord *l, double *a)
1729 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1730 *a = get_angle(x1, y1, x2, y2);
1734 _get_direction(Evas_Coord x1, Evas_Coord x2)
1746 * This function tests momentum gesture.
1747 * @param obj The gesture-layer object.
1748 * @param pe The recent input event as stored in pe struct.
1749 * @param event_info recent input event.
1750 * @param event_type recent event type.
1751 * @param g_type what Gesture we are testing.
1753 * @ingroup Elm_Gesture_Layer
1756 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1757 void *event_info, Evas_Callback_Type event_type,
1758 Elm_Gesture_Types g_type)
1760 Widget_Data *wd = elm_widget_data_get(obj);
1762 Gesture_Info *gesture = wd->gesture[g_type];
1763 if (!gesture ) return;
1765 Momentum_Type *st = gesture->data;
1766 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1768 { /* Allocated once on first time */
1769 st = calloc(1, sizeof(Momentum_Type));
1771 _momentum_test_reset(gesture);
1777 /* First make avarage of all touched devices to determine center point */
1780 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1781 int cnt = 1; /* We start counter counting current pe event */
1782 EINA_LIST_FOREACH(wd->touched, l, p)
1783 if (p->device != pe_local.device)
1791 /* Compute avarage to get center point */
1795 /* If user added finger - reset gesture */
1796 if ((st->n_fingers) && (st->n_fingers < cnt))
1797 state_to_report = ELM_GESTURE_STATE_ABORT;
1799 st->n_fingers = cnt;
1801 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1804 case EVAS_CALLBACK_MOUSE_DOWN:
1805 case EVAS_CALLBACK_MULTI_DOWN:
1806 case EVAS_CALLBACK_MOUSE_MOVE:
1807 case EVAS_CALLBACK_MULTI_MOVE:
1810 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1811 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1812 (wd->glayer_continues_enable)) /* start also on MOVE */
1813 { /* We start on MOVE when cont-enabled only */
1814 st->line_st.x = st->line_end.x = pe_local.x;
1815 st->line_st.y = st->line_end.y = pe_local.y;
1816 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1817 st->xdir = st->ydir = 0;
1818 st->info.x2 = st->info.x1 = pe_local.x;
1819 st->info.y2 = st->info.y1 = pe_local.y;
1820 st->info.tx = st->info.ty = pe_local.timestamp;
1821 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1822 &st->info, EINA_FALSE);
1823 consume_event(wd, event_info, event_type, ev_flag);
1830 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1832 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1833 state_to_report = ELM_GESTURE_STATE_ABORT;
1835 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1836 { /* Too long of a wait, reset all values */
1837 st->line_st.x = pe_local.x;
1838 st->line_st.y = pe_local.y;
1839 st->t_st_y = st->t_st_x = pe_local.timestamp;
1840 st->info.tx = st->t_st_x;
1841 st->info.ty = st->t_st_y;
1842 st->xdir = st->ydir = 0;
1847 xdir = _get_direction(st->line_st.x, pe_local.x);
1848 ydir = _get_direction(st->line_st.y, pe_local.y);
1849 if (!xdir || (xdir == (-st->xdir)))
1851 st->line_st.x = st->line_end.x;
1852 st->info.tx = st->t_st_x = st->t_end;
1856 if (!ydir || (ydir == (-st->ydir)))
1858 st->line_st.y = st->line_end.y;
1859 st->info.ty = st->t_st_y = st->t_end;
1864 st->info.x2 = st->line_end.x = pe_local.x;
1865 st->info.y2 = st->line_end.y = pe_local.y;
1866 st->t_end = pe_local.timestamp;
1867 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1868 st->t_st_x, st->t_st_y, pe_local.timestamp);
1869 ev_flag = _set_state(gesture, state_to_report, &st->info,
1871 consume_event(wd, event_info, event_type, ev_flag);
1875 case EVAS_CALLBACK_MOUSE_UP:
1876 case EVAS_CALLBACK_MULTI_UP:
1877 st->t_up = pe_local.timestamp; /* Record recent up event time */
1878 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1879 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1882 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1883 { /* Too long of a wait, reset all values */
1884 st->line_st.x = pe_local.x;
1885 st->line_st.y = pe_local.y;
1886 st->t_st_y = st->t_st_x = pe_local.timestamp;
1887 st->xdir = st->ydir = 0;
1890 st->info.x2 = pe_local.x;
1891 st->info.y2 = pe_local.y;
1892 st->line_end.x = pe_local.x;
1893 st->line_end.y = pe_local.y;
1894 st->t_end = pe_local.timestamp;
1896 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1897 st->t_st_x, st->t_st_y, pe_local.timestamp);
1899 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1901 consume_event(wd, event_info, event_type, ev_flag);
1910 compare_line_device(const void *data1, const void *data2)
1911 { /* Compare device component of line struct */
1912 const Line_Data *ln1 = data1;
1913 const int *device = data2;
1915 if (ln1->t_st) /* Compare only with lines that started */
1916 return (ln1->device - (*device));
1924 * This function construct line struct from input.
1925 * @param info pointer to store line momentum.
1926 * @param st line info to store input data.
1927 * @param pe The recent input event as stored in pe struct.
1929 * @ingroup Elm_Gesture_Layer
1932 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1933 Pointer_Event *pe, Evas_Callback_Type event_type)
1934 { /* Record events and set momentum for line pointed by st */
1940 case EVAS_CALLBACK_MOUSE_DOWN:
1941 case EVAS_CALLBACK_MOUSE_MOVE:
1942 case EVAS_CALLBACK_MULTI_DOWN:
1943 case EVAS_CALLBACK_MULTI_MOVE:
1945 { /* This happens only when line starts */
1946 st->line_st.x = pe->x;
1947 st->line_st.y = pe->y;
1948 st->t_st = pe->timestamp;
1949 st->device = pe->device;
1950 info->momentum.x1 = pe->x;
1951 info->momentum.y1 = pe->y;
1952 info->momentum.tx = pe->timestamp;
1953 info->momentum.ty = pe->timestamp;
1960 case EVAS_CALLBACK_MOUSE_UP:
1961 case EVAS_CALLBACK_MULTI_UP:
1962 /* IGNORE if line info was cleared, like long press, move */
1966 st->line_end.x = pe->x;
1967 st->line_end.y = pe->y;
1968 st->t_end = pe->timestamp;
1977 _line_data_reset(st);
1981 info->momentum.x2 = pe->x;
1982 info->momentum.y2 = pe->y;
1983 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1984 st->t_st, st->t_st, pe->timestamp);
1992 * This function test for (n) line gesture.
1993 * @param obj The gesture-layer object.
1994 * @param pe The recent input event as stored in pe struct.
1995 * @param event_info Original input event pointer.
1996 * @param event_type Type of original input event.
1997 * @param g_type what Gesture we are testing.
1999 * @ingroup Elm_Gesture_Layer
2002 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2003 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2007 Widget_Data *wd = elm_widget_data_get(obj);
2009 Gesture_Info *gesture = wd->gesture[g_type];
2010 if (!gesture ) return;
2012 Line_Type *st = gesture->data;
2015 st = calloc(1, sizeof(Line_Type));
2019 Line_Data *line = NULL;
2020 Eina_List *list = st->list;
2021 unsigned cnt = eina_list_count(list);
2024 { /* list is not empty, locate this device on list */
2025 line = (Line_Data *) eina_list_search_unsorted(st->list,
2026 compare_line_device, &pe->device);
2030 { /* List is empty or device not found, new line-struct on START only */
2031 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2032 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2033 ((wd->glayer_continues_enable) && /* START on MOVE also */
2034 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2035 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2036 { /* Allocate new item on START only */
2037 line = calloc(1, sizeof(Line_Data));
2038 _line_data_reset(line);
2039 list = eina_list_append(list, line);
2044 if (!line) /* This may happen on MOVE that comes before DOWN */
2045 return; /* No line-struct to work with, can't continue testing */
2047 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2048 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2050 /* Get direction and magnitude of the line */
2052 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2053 &line->line_length, &angle);
2055 /* These are used later to compare lines length */
2056 Evas_Coord shortest_line_len = line->line_length;
2057 Evas_Coord longest_line_len = line->line_length;
2058 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2060 /* Now update line-state */
2062 { /* Analyze line only if line started */
2063 if (line->line_angle >= 0.0)
2064 { /* if line direction was set, we test if broke tolerance */
2065 double a = fabs(angle - line->line_angle);
2067 double d = (tan(a)) * line->line_length; /* Distance from line */
2068 #if defined(DEBUG_GESTURE_LAYER)
2069 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2071 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2072 { /* Broke tolerance: abort line and start a new one */
2073 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2074 &st->info, EINA_FALSE);
2075 consume_event(wd, event_info, event_type, ev_flag);
2079 if (wd->glayer_continues_enable)
2080 { /* We may finish line if momentum is zero */
2081 /* This is for continues-gesture */
2082 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2083 { /* Finish line on zero momentum for continues gesture */
2084 line->line_end.x = pe->x;
2085 line->line_end.y = pe->y;
2086 line->t_end = pe->timestamp;
2091 { /* Record the line angle as it broke minimum length for line */
2092 if (line->line_length >= wd->line_min_length)
2093 st->info.angle = line->line_angle = angle;
2099 if (line->line_angle < 0.0)
2100 { /* it's not a line, too short more close to a tap */
2101 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2102 &st->info, EINA_FALSE);
2103 consume_event(wd, event_info, event_type, ev_flag);
2109 /* Count how many lines already started / ended */
2112 unsigned int tm_start = pe->timestamp;
2113 unsigned int tm_end = pe->timestamp;
2116 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2117 Eina_Bool lines_parallel = EINA_TRUE;
2118 EINA_LIST_FOREACH(list, l, t_line)
2121 base_angle = t_line->line_angle;
2124 if (t_line->line_angle >= 0)
2125 { /* Compare angle only with lines with direction defined */
2126 if (fabs(base_angle - t_line->line_angle) >
2127 wd->line_angular_tolerance)
2128 lines_parallel = EINA_FALSE;
2132 if (t_line->line_length)
2133 { /* update only if this line is used */
2134 if (shortest_line_len > t_line->line_length)
2135 shortest_line_len = t_line->line_length;
2137 if (longest_line_len < t_line->line_length)
2138 longest_line_len = t_line->line_length;
2144 if (t_line->t_st < tm_start)
2145 tm_start = t_line->t_st;
2151 if (t_line->t_end < tm_end)
2152 tm_end = t_line->t_end;
2156 st->info.n = started;
2160 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2161 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2162 { /* user lift one finger then starts again without line-end - ABORT */
2163 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2165 consume_event(wd, event_info, event_type, ev_flag);
2169 if (!lines_parallel)
2170 { /* Lines are NOT at same direction, abort this gesture */
2171 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2173 consume_event(wd, event_info, event_type, ev_flag);
2178 /* We report ABORT if lines length are NOT matching when fingers are up */
2179 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2181 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2183 consume_event(wd, event_info, event_type, ev_flag);
2187 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2188 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2189 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2191 consume_event(wd, event_info, event_type, ev_flag);
2197 case EVAS_CALLBACK_MOUSE_UP:
2198 case EVAS_CALLBACK_MULTI_UP:
2199 if ((started) && (started == ended))
2201 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2202 &st->info, EINA_FALSE);
2203 consume_event(wd, event_info, event_type, ev_flag);
2208 case EVAS_CALLBACK_MOUSE_DOWN:
2209 case EVAS_CALLBACK_MULTI_DOWN:
2210 case EVAS_CALLBACK_MOUSE_MOVE:
2211 case EVAS_CALLBACK_MULTI_MOVE:
2214 if (wd->glayer_continues_enable && (started == ended))
2215 { /* For continues gesture */
2216 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2217 &st->info, EINA_FALSE);
2218 consume_event(wd, event_info, event_type, ev_flag);
2221 { /* When continues, may START on MOVE event too */
2222 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2224 /* This happens when: on n > 1 lines then one finger up */
2225 /* caused abort, then put finger down. */
2226 /* This will stop line from starting again. */
2227 /* Number of lines, MUST match touched-device in list */
2228 if ((!wd->glayer_continues_enable) &&
2229 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2230 s = ELM_GESTURE_STATE_ABORT;
2232 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2233 s = ELM_GESTURE_STATE_START;
2235 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2236 consume_event(wd, event_info, event_type, ev_flag);
2242 return; /* Unhandeld event type */
2249 * This function is used to check if rotation gesture started.
2250 * @param st Contains current rotation values from user input.
2251 * @return TRUE/FALSE if we need to set rotation START.
2253 * @ingroup Elm_Gesture_Layer
2256 rotation_broke_tolerance(Rotate_Type *st)
2258 if (st->info.base_angle < 0)
2259 return EINA_FALSE; /* Angle has to be computed first */
2261 if (st->rotate_angular_tolerance < 0)
2264 double low = st->info.base_angle - st->rotate_angular_tolerance;
2265 double high = st->info.base_angle + st->rotate_angular_tolerance;
2266 double t = st->info.angle;
2279 if (high > RAD_360DEG)
2290 #if defined(DEBUG_GESTURE_LAYER)
2291 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2293 if ((t < low) || (t > high))
2294 { /* This marks that roation action has started */
2295 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2296 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2306 * This function is used for computing the gap between fingers.
2307 * It returns the length and center point between fingers.
2309 * @param x1 first finger x location.
2310 * @param y1 first finger y location.
2311 * @param x2 second finger x location.
2312 * @param y2 second finger y location.
2313 * @param x Gets center point x cord (output)
2314 * @param y Gets center point y cord (output)
2316 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2318 * @ingroup Elm_Gesture_Layer
2321 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2322 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2324 double a, b, xx, yy, gap;
2327 gap = sqrt(xx*xx + yy*yy);
2329 /* START - Compute zoom center point */
2330 /* The triangle defined as follows:
2338 * http://en.wikipedia.org/wiki/Trigonometric_functions
2339 *************************************/
2340 if (((int) xx) && ((int) yy))
2342 double A = atan((yy / xx));
2343 #if defined(DEBUG_GESTURE_LAYER)
2344 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2346 a = (Evas_Coord) ((gap / 2) * sin(A));
2347 b = (Evas_Coord) ((gap / 2) * cos(A));
2348 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2349 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2354 { /* horiz line, take half width */
2355 #if defined(DEBUG_GESTURE_LAYER)
2356 printf("==== HORIZ ====\n");
2358 *x = (Evas_Coord) (xx / 2);
2359 *y = (Evas_Coord) (y1);
2363 { /* vert line, take half width */
2364 #if defined(DEBUG_GESTURE_LAYER)
2365 printf("==== VERT ====\n");
2367 *x = (Evas_Coord) (x1);
2368 *y = (Evas_Coord) (yy / 2);
2371 /* END - Compute zoom center point */
2373 return (Evas_Coord) gap;
2379 * This function is used for computing zoom value.
2381 * @param st Pointer to zoom data based on user input.
2382 * @param x1 first finger x location.
2383 * @param y1 first finger y location.
2384 * @param x2 second finger x location.
2385 * @param y2 second finger y location.
2386 * @param factor zoom-factor, used to determine how fast zoom works.
2388 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2390 * @ingroup Elm_Gesture_Layer
2392 /* FIXME change float to double */
2394 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2395 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2398 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2399 &st->info.x, &st->info.y);
2401 st->info.radius = diam / 2;
2405 st->zoom_base = diam;
2406 return st->info.zoom;
2409 if (st->zoom_distance_tolerance)
2410 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2411 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2412 { /* avoid jump with zoom value when break tolerance */
2413 st->zoom_base -= st->zoom_distance_tolerance;
2414 st->zoom_distance_tolerance = 0;
2417 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2418 { /* avoid jump with zoom value when break tolerance */
2419 st->zoom_base += st->zoom_distance_tolerance;
2420 st->zoom_distance_tolerance = 0;
2426 /* We use factor only on the difference between gap-base */
2427 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2428 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2429 (float) st->zoom_base) * zoom_finger_factor));
2432 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2433 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2444 * This function handles zoom with mouse wheel.
2445 * thats a combination of wheel + CTRL key.
2446 * @param obj The gesture-layer object.
2447 * @param event_info Original input event pointer.
2448 * @param event_type Type of original input event.
2449 * @param g_type what Gesture we are testing.
2451 * @ingroup Elm_Gesture_Layer
2454 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2455 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2457 Widget_Data *wd = elm_widget_data_get(obj);
2459 if (!wd->gesture[g_type]) return;
2461 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2462 Zoom_Type *st = gesture_zoom->data;
2463 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2465 { /* Allocated once on first time, used for zoom intermediate data */
2466 st = calloc(1, sizeof(Zoom_Type));
2467 gesture_zoom->data = st;
2468 _zoom_test_reset(gesture_zoom);
2473 case EVAS_CALLBACK_KEY_UP:
2475 Evas_Event_Key_Up *p = event_info;
2476 if ((!strcmp(p->keyname, "Control_L")) ||
2477 (!strcmp(p->keyname, "Control_R")))
2478 { /* Test if we ended a zoom gesture when releasing CTRL */
2479 if ((st->zoom_wheel) &&
2480 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2481 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2482 { /* User released CTRL after zooming */
2483 ev_flag = _set_state(gesture_zoom,
2484 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2485 consume_event(wd, event_info, event_type, ev_flag);
2493 case EVAS_CALLBACK_MOUSE_WHEEL:
2496 Elm_Gesture_State s;
2497 if (!evas_key_modifier_is_set(
2498 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2500 { /* if using wheel witout CTRL after starting zoom */
2501 if ((st->zoom_wheel) &&
2502 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2503 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2505 ev_flag = _set_state(gesture_zoom,
2506 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2507 consume_event(wd, event_info, event_type, ev_flag);
2512 return; /* Ignore mouse-wheel without control */
2515 /* Using mouse wheel with CTRL for zoom */
2516 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2517 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2518 we continue a zoom gesture */
2520 s = ELM_GESTURE_STATE_MOVE;
2523 { /* On first wheel event, report START */
2524 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2525 evas_object_evas_get(wd->target), "Control");
2527 s = ELM_GESTURE_STATE_START;
2528 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2529 ERR("Failed to Grabbed CTRL_L");
2530 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2531 ERR("Failed to Grabbed CTRL_R");
2534 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2535 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2536 st->info.x = st->zoom_wheel->canvas.x;
2537 st->info.y = st->zoom_wheel->canvas.y;
2539 if (st->zoom_wheel->z < 0) /* zoom in */
2540 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2542 if (st->zoom_wheel->z > 0) /* zoom out */
2543 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2545 if (st->info.zoom < 0.0)
2546 st->info.zoom = 0.0;
2548 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2549 consume_event(wd, event_info, event_type, ev_flag);
2561 * This function is used to test zoom gesture.
2562 * user may combine zoom, rotation together.
2563 * so its possible that both will be detected from input.
2564 * (both are two-finger movement-oriented gestures)
2566 * @param obj The gesture-layer object.
2567 * @param event_info Pointer to recent input event.
2568 * @param event_type Recent input event type.
2569 * @param g_type what Gesture we are testing.
2571 * @ingroup Elm_Gesture_Layer
2574 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2575 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2579 Widget_Data *wd = elm_widget_data_get(obj);
2581 if (!wd->gesture[g_type]) return;
2583 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2584 Zoom_Type *st = gesture_zoom->data;
2587 { /* Allocated once on first time, used for zoom data */
2588 st = calloc(1, sizeof(Zoom_Type));
2589 gesture_zoom->data = st;
2590 _zoom_test_reset(gesture_zoom);
2594 /* Start - new zoom testing, letting all fingers start */
2595 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2598 case EVAS_CALLBACK_MOUSE_MOVE:
2599 case EVAS_CALLBACK_MULTI_MOVE:
2600 /* if non-continues mode and gesture NOT started, ignore MOVE */
2601 if ((!wd->glayer_continues_enable) &&
2602 (!st->zoom_st.timestamp))
2605 case EVAS_CALLBACK_MOUSE_DOWN:
2606 case EVAS_CALLBACK_MULTI_DOWN:
2607 { /* Here we take care of zoom-start and zoom move */
2611 if(eina_list_count(wd->touched) > 2)
2612 { /* Process zoom only when 2 fingers on surface */
2613 ev_flag = _set_state(gesture_zoom,
2614 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2615 consume_event(wd, event_info, event_type, ev_flag);
2620 if (!st->zoom_st.timestamp)
2621 { /* Now scan touched-devices list and find other finger */
2622 EINA_LIST_FOREACH(wd->touched, l, p)
2623 { /* Device of other finger <> pe device */
2624 if (p->device != pe->device)
2628 if (!p) /* Single finger on touch */
2631 /* Record down fingers */
2632 consume_event(wd, event_info, event_type, ev_flag);
2633 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2634 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2636 /* Set mv field as well to be ready for MOVE events */
2637 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2638 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2640 /* Here we have zoom_st, zoom_st1 set, report START */
2641 /* Set zoom-base after BOTH down events recorded */
2642 /* Compute length of line between fingers zoom start */
2643 st->info.zoom = 1.0;
2644 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2645 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2646 &st->info.x, &st->info.y);
2648 st->info.radius = st->zoom_base / 2;
2650 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2651 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2652 { /* zoom started with mouse-wheel, don't report twice */
2653 ev_flag = _set_state(gesture_zoom,
2654 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2655 consume_event(wd, event_info, event_type, ev_flag);
2658 return; /* Zoom started */
2659 } /* End of ZOOM_START handling */
2662 /* if we got here, we have (exacally) two fingers on surfce */
2663 /* we also after START, report MOVE */
2664 /* First detect which finger moved */
2665 if (pe->device == st->zoom_mv.device)
2666 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2667 else if (pe->device == st->zoom_mv1.device)
2668 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2670 /* Compute change in zoom as fingers move */
2671 st->info.zoom = compute_zoom(st,
2672 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2673 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2674 wd->zoom_finger_factor);
2676 if (!st->zoom_distance_tolerance)
2677 { /* Zoom broke tolerance, report move */
2678 double d = st->info.zoom - st->next_step;
2682 if (d >= wd->zoom_step)
2683 { /* Report move in steps */
2684 st->next_step = st->info.zoom;
2686 ev_flag = _set_state(gesture_zoom,
2687 ELM_GESTURE_STATE_MOVE,
2688 &st->info, EINA_TRUE);
2689 consume_event(wd, event_info, event_type, ev_flag);
2691 } /* End of ZOOM_MOVE handling */
2696 case EVAS_CALLBACK_MOUSE_UP:
2697 case EVAS_CALLBACK_MULTI_UP:
2698 /* Reset timestamp of finger-up.This is used later
2699 by _zoom_test_reset() to retain finger-down data */
2700 consume_event(wd, event_info, event_type, ev_flag);
2701 if (((st->zoom_wheel) || (st->zoom_base)) &&
2702 (st->zoom_distance_tolerance == 0))
2704 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2705 &st->info, EINA_FALSE);
2706 consume_event(wd, event_info, event_type, ev_flag);
2711 /* if we got here not a ZOOM */
2712 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2713 { /* Must be != undefined, if gesture started */
2714 ev_flag = _set_state(gesture_zoom,
2715 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2716 consume_event(wd, event_info, event_type, ev_flag);
2719 _zoom_test_reset(gesture_zoom);
2729 _get_rotate_properties(Rotate_Type *st,
2730 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2731 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2734 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2735 &st->info.x, &st->info.y) / 2;
2737 *angle = get_angle(x1, y1, x2, y2);
2738 #if 0 /* (NOT YET SUPPORTED) */
2739 if (angle == &st->info.angle)
2740 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2741 st->info.momentum = (((*angle) - st->info.base_angle) /
2742 (fabs(tm2 - tm1))) * 1000;
2745 st->info.momentum = 0;
2755 * This function is used to test rotation gesture.
2756 * user may combine zoom, rotation together.
2757 * so its possible that both will be detected from input.
2758 * (both are two-finger movement-oriented gestures)
2760 * @param obj The gesture-layer object.
2761 * @param event_info Pointer to recent input event.
2762 * @param event_type Recent input event type.
2763 * @param g_type what Gesture we are testing.
2765 * @ingroup Elm_Gesture_Layer
2768 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2769 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2774 Widget_Data *wd = elm_widget_data_get(obj);
2776 if (!wd->gesture[g_type]) return;
2778 Gesture_Info *gesture = wd->gesture[g_type];
2779 Rotate_Type *st = gesture->data;
2784 { /* Allocated once on first time */
2785 st = calloc(1, sizeof(Rotate_Type));
2787 _rotate_test_reset(gesture);
2791 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2794 case EVAS_CALLBACK_MOUSE_MOVE:
2795 case EVAS_CALLBACK_MULTI_MOVE:
2796 /* if non-continues mode and gesture NOT started, ignore MOVE */
2797 if ((!wd->glayer_continues_enable) &&
2798 (!st->rotate_st.timestamp))
2801 case EVAS_CALLBACK_MOUSE_DOWN:
2802 case EVAS_CALLBACK_MULTI_DOWN:
2803 { /* Here we take care of rotate-start and rotate move */
2807 if(eina_list_count(wd->touched) > 2)
2808 { /* Process rotate only when 2 fingers on surface */
2809 ev_flag = _set_state(gesture,
2810 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2811 consume_event(wd, event_info, event_type, ev_flag);
2816 if (!st->rotate_st.timestamp)
2817 { /* Now scan touched-devices list and find other finger */
2818 EINA_LIST_FOREACH(wd->touched, l, p)
2819 { /* Device of other finger <> pe device */
2820 if (p->device != pe->device)
2825 return; /* Single finger on touch */
2827 /* Record down fingers */
2828 consume_event(wd, event_info, event_type, ev_flag);
2829 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2830 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2832 /* Set mv field as well to be ready for MOVE events */
2833 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2834 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2836 /* Here we have rotate_st, rotate_st1 set, report START */
2837 /* Set rotate-base after BOTH down events recorded */
2838 /* Compute length of line between fingers rotate start */
2839 _get_rotate_properties(st,
2840 st->rotate_st.x, st->rotate_st.y,
2841 st->rotate_st.timestamp,
2842 st->rotate_st1.x, st->rotate_st1.y,
2843 st->rotate_st1.timestamp, &st->info.base_angle);
2845 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2846 &st->info, EINA_FALSE);
2847 consume_event(wd, event_info, event_type, ev_flag);
2849 return; /* Rotate started */
2850 } /* End of ROTATE_START handling */
2853 /* if we got here, we have (exacally) two fingers on surfce */
2854 /* we also after START, report MOVE */
2855 /* First detect which finger moved */
2856 if (pe->device == st->rotate_mv.device)
2857 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2858 else if (pe->device == st->rotate_mv1.device)
2859 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2861 /* Compute change in rotate as fingers move */
2862 _get_rotate_properties(st,
2863 st->rotate_mv.x, st->rotate_mv.y,
2864 st->rotate_mv.timestamp,
2865 st->rotate_mv1.x, st->rotate_mv1.y,
2866 st->rotate_mv1.timestamp, &st->info.angle);
2868 if (rotation_broke_tolerance(st))
2869 { /* Rotation broke tolerance, report move */
2870 double d = st->info.angle - st->next_step;
2874 if (d >= wd->rotate_step)
2875 { /* Report move in steps */
2876 st->next_step = st->info.angle;
2878 ev_flag = _set_state(gesture,
2879 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2880 consume_event(wd, event_info, event_type, ev_flag);
2882 } /* End of ROTATE_MOVE handling */
2887 case EVAS_CALLBACK_MOUSE_UP:
2888 case EVAS_CALLBACK_MULTI_UP:
2889 consume_event(wd, event_info, event_type, ev_flag);
2890 /* Reset timestamp of finger-up.This is used later
2891 by rotate_test_reset() to retain finger-down data */
2892 if (st->rotate_angular_tolerance < 0)
2894 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2895 &st->info, EINA_FALSE);
2896 consume_event(wd, event_info, event_type, ev_flag);
2901 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2902 { /* Must be != undefined, if gesture started */
2903 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2904 &st->info, EINA_FALSE);
2905 consume_event(wd, event_info, event_type, ev_flag);
2908 _rotate_test_reset(gesture);
2919 * This function is used to save input events in an abstract struct
2920 * to be used later by getsure-testing functions.
2922 * @param data The gesture-layer object.
2923 * @param event_info Pointer to recent input event.
2924 * @param event_type Recent input event type.
2925 * @param pe The abstract data-struct (output).
2927 * @ingroup Elm_Gesture_Layer
2930 _make_pointer_event(void *data, void *event_info,
2931 Evas_Callback_Type event_type, Pointer_Event *pe)
2933 Widget_Data *wd = elm_widget_data_get(data);
2934 if (!wd) return EINA_FALSE;
2936 memset(pe, '\0', sizeof(*pe));
2939 case EVAS_CALLBACK_MOUSE_DOWN:
2940 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2941 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2942 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2943 pe->device = ELM_MOUSE_DEVICE;
2946 case EVAS_CALLBACK_MOUSE_UP:
2947 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2948 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2949 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2950 pe->device = ELM_MOUSE_DEVICE;
2953 case EVAS_CALLBACK_MOUSE_MOVE:
2954 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2955 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2956 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2957 pe->device = ELM_MOUSE_DEVICE;
2960 case EVAS_CALLBACK_MULTI_DOWN:
2961 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2962 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2963 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2964 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2967 case EVAS_CALLBACK_MULTI_UP:
2968 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2969 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2970 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2971 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2974 case EVAS_CALLBACK_MULTI_MOVE:
2975 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2976 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2977 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2978 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2985 pe->event_type = event_type;
2992 * This function restartes line, flick, zoom and rotate gestures
2993 * when gesture-layer continues-gestures enabled.
2994 * Example of continues-gesture:
2995 * When doing a line, user stops moving finger but keeps fingers on touch.
2996 * This will cause line-end, then as user continues moving his finger
2997 * it re-starts line gesture.
2998 * When continue mode is disabled, user has to lift finger from touch
2999 * to end a gesture. Them touch-again to start a new one.
3001 * @param data The gesture-layer object.
3002 * @param wd gesture layer widget data.
3003 * @param states_reset flag that marks gestures were reset in history clear.
3005 * @ingroup Elm_Gesture_Layer
3007 void continues_gestures_restart(void *data, Eina_Bool states_reset)
3009 Widget_Data *wd = elm_widget_data_get(data);
3012 /* Run through events to restart gestures */
3014 Eina_Bool n_lines, n_flicks, zoom, rotate;
3015 /* We turn-on flag for finished, aborted, not-started gestures */
3016 g = wd->gesture[ELM_GESTURE_N_LINES];
3017 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3018 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3021 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3022 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3026 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3027 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3028 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3031 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3032 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3036 g = wd->gesture[ELM_GESTURE_ZOOM];
3037 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3038 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3041 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3042 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3046 g = wd->gesture[ELM_GESTURE_ROTATE];
3047 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3048 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3051 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3052 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3060 * This function the core-function where input handling is done.
3061 * Here we get user input and stream it to gesture testing.
3062 * We notify user about any gestures with new state:
3064 * START - gesture started.
3065 * MOVE - gesture is ongoing.
3066 * END - gesture was completed.
3067 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3069 * We also check if a gesture was detected, then reset event history
3070 * If no gestures were found we reset gesture test flag
3071 * after streaming event-history to widget.
3072 * (stream to the widget all events not consumed as a gesture)
3074 * @param data The gesture-layer object.
3075 * @param event_info Pointer to recent input event.
3076 * @param event_type Recent input event type.
3078 * @ingroup Elm_Gesture_Layer
3081 _event_process(void *data, Evas_Object *obj __UNUSED__,
3082 void *event_info, Evas_Callback_Type event_type)
3085 Pointer_Event *pe = NULL;
3086 Widget_Data *wd = elm_widget_data_get(data);
3089 #if defined(DEBUG_GESTURE_LAYER)
3092 printf("Gesture | State | is tested\n");
3093 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3097 printf(" %d %d %d\n", i, g->state, g->test);
3101 /* Start testing candidate gesture from here */
3102 if (_make_pointer_event(data, event_info, event_type, &_pe))
3105 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3106 _n_long_tap_test(data, pe, event_info, event_type,
3107 ELM_GESTURE_N_LONG_TAPS);
3109 /* This takes care of single, double and tripple tap */
3110 _tap_gestures_test(data, pe, event_info, event_type);
3112 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3113 _momentum_test(data, pe, event_info, event_type,
3114 ELM_GESTURE_MOMENTUM);
3116 if (IS_TESTED(ELM_GESTURE_N_LINES))
3117 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3119 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3120 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3122 if (IS_TESTED(ELM_GESTURE_ZOOM))
3123 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3125 if (IS_TESTED(ELM_GESTURE_ZOOM))
3126 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3128 if (IS_TESTED(ELM_GESTURE_ROTATE))
3129 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3131 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3132 _event_history_add(data, event_info, event_type);
3133 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3134 (event_type == EVAS_CALLBACK_MULTI_UP))
3136 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3139 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3140 _event_history_add(data, event_info, event_type);
3144 /* Log event to restart gestures */
3145 wd->recent_device_event = _add_recent_device_event(wd->recent_device_event, &_pe);
3147 /* we maintain list of touched devices */
3148 /* We also use move to track current device x.y pos */
3149 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3150 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3151 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3152 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3154 wd->touched = _add_touched_device(wd->touched, pe);
3156 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3157 (event_type == EVAS_CALLBACK_MULTI_UP))
3159 wd->touched = _remove_touched_device(wd->touched, pe);
3162 /* Report current states and clear history if needed */
3163 Eina_Bool states_reset = _clear_if_finished(data);
3164 if (wd->glayer_continues_enable)
3165 continues_gestures_restart(data, states_reset);
3170 * For all _mouse_* / multi_* functions wethen send this event to
3171 * _event_process function.
3173 * @param data The gesture-layer object.
3174 * @param event_info Pointer to recent input event.
3176 * @ingroup Elm_Gesture_Layer
3179 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3182 Widget_Data *wd = elm_widget_data_get(data);
3184 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3185 return; /* We only process left-click at the moment */
3187 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3191 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3194 Widget_Data *wd = elm_widget_data_get(data);
3197 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3201 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3204 Widget_Data *wd = elm_widget_data_get(data);
3207 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3211 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3214 Widget_Data *wd = elm_widget_data_get(data);
3217 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3221 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3224 Widget_Data *wd = elm_widget_data_get(data);
3227 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3228 return; /* We only process left-click at the moment */
3230 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3234 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3237 Widget_Data *wd = elm_widget_data_get(data);
3240 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3244 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3247 Widget_Data *wd = elm_widget_data_get(data);
3250 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3254 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3257 Widget_Data *wd = elm_widget_data_get(data);
3260 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3264 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3267 Widget_Data *wd = elm_widget_data_get(data);
3270 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3274 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3276 Widget_Data *wd = elm_widget_data_get(obj);
3277 if (!wd) return EINA_FALSE;
3279 return !wd->repeat_events;
3283 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3285 Widget_Data *wd = elm_widget_data_get(obj);
3288 wd->repeat_events = !r;
3292 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3294 Widget_Data *wd = elm_widget_data_get(obj);
3304 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3306 Widget_Data *wd = elm_widget_data_get(obj);
3312 wd->rotate_step = s;
3316 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3318 Widget_Data *wd = elm_widget_data_get(obj);
3319 if (!wd) return EINA_FALSE;
3324 /* if was attached before, unregister callbacks first */
3326 _unregister_callbacks(obj);
3330 _register_callbacks(obj);
3335 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3336 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3338 Widget_Data *wd = elm_widget_data_get(obj);
3342 if (!wd->gesture[idx])
3343 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3344 if (!wd->gesture[idx]) return;
3346 p = wd->gesture[idx];
3349 p->fn[cb_type].cb = cb;
3350 p->fn[cb_type].user_data = data;
3351 p->state = ELM_GESTURE_STATE_UNDEFINED;
3356 _disable_hook(Evas_Object *obj)
3358 if (elm_widget_disabled_get(obj))
3359 _unregister_callbacks(obj);
3361 _register_callbacks(obj);
3365 elm_gesture_layer_add(Evas_Object *parent)
3371 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3373 wd = ELM_NEW(Widget_Data);
3374 e = evas_object_evas_get(parent);
3375 if (!e) return NULL;
3376 obj = elm_widget_add(e);
3377 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3378 elm_widget_type_set(obj, "gesture_layer");
3379 elm_widget_sub_object_add(parent, obj);
3380 elm_widget_data_set(obj, wd);
3381 elm_widget_del_hook_set(obj, _del_hook);
3382 elm_widget_disable_hook_set(obj, _disable_hook);
3385 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3386 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3387 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3388 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3389 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3390 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3391 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3392 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3393 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3394 wd->repeat_events = EINA_TRUE;
3395 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3397 #if defined(DEBUG_GESTURE_LAYER)
3398 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3399 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);
3401 memset(wd->gesture, 0, sizeof(wd->gesture));