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;
160 unsigned int center_x;
161 unsigned int center_y;
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, Pointer_Event *pe)
1435 if(!eina_list_count(st->touched))
1440 Evas_Coord x = 0, y = 0;
1441 EINA_LIST_FOREACH(st->touched, l, p)
1442 { /* Accumulate all then take avarage */
1443 if (p->device == pe->device)
1444 { /* This will take care of values coming from MOVE event */
1455 st->info.x = x / eina_list_count(st->touched);
1456 st->info.y = y / eina_list_count(st->touched);
1462 * This function checks N long-tap gesture.
1464 * @param obj The gesture-layer object.
1465 * @param pe The recent input event as stored in pe struct.
1466 * @param event_info Original input event pointer.
1467 * @param event_type Type of original input event.
1468 * @param g_type what Gesture we are testing.
1469 * @param taps How many click/taps we test for.
1471 * @ingroup Elm_Gesture_Layer
1474 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1475 void *event_info, Evas_Callback_Type event_type,
1476 Elm_Gesture_Types g_type)
1477 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1478 Widget_Data *wd = elm_widget_data_get(obj);
1481 if (!pe) /* this happens when unhandled event arrived */
1482 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 ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1503 { /* This is the first mouse down we got */
1504 st->info.timestamp = pe->timestamp;
1506 /* To test long tap */
1507 /* When this timer expires, gesture STARTED */
1509 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1510 _long_tap_timeout, gesture);
1513 consume_event(wd, event_info, event_type, ev_flag);
1514 _compute_taps_center(st, pe);
1517 case EVAS_CALLBACK_MULTI_UP:
1518 case EVAS_CALLBACK_MOUSE_UP:
1519 st->touched = _remove_touched_device(st->touched, pe);
1521 ((gesture->state == ELM_GESTURE_STATE_START) ||
1522 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1523 { /* Report END only for gesture that STARTed */
1524 if (eina_list_count(st->touched) == 0)
1525 { /* Report END only at last release event */
1526 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1527 &st->info, EINA_FALSE);
1528 consume_event(wd, event_info, event_type, ev_flag);
1532 { /* Stop test, user lifts finger before long-start */
1533 if (st->timeout) ecore_timer_del(st->timeout);
1535 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1536 &st->info, EINA_FALSE);
1537 consume_event(wd, event_info, event_type, ev_flag);
1542 case EVAS_CALLBACK_MULTI_MOVE:
1543 case EVAS_CALLBACK_MOUSE_MOVE:
1545 ((gesture->state == ELM_GESTURE_STATE_START) ||
1546 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1547 { /* Report MOVE only if STARTED */
1548 _compute_taps_center(st, pe);
1549 /* Report MOVE if gesture started */
1550 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1551 &st->info, EINA_TRUE);
1552 consume_event(wd, event_info, event_type, ev_flag);
1564 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1565 * This momentum value will be sent to widget when gesture is completed.
1567 * @param momentum pointer to buffer where we record momentum value.
1568 * @param x1 x coord where user started gesture.
1569 * @param y1 y coord where user started gesture.
1570 * @param x2 x coord where user completed gesture.
1571 * @param y2 y coord where user completed gesture.
1572 * @param t1x timestamp for X, when user started gesture.
1573 * @param t1y timestamp for Y, when user started gesture.
1574 * @param t2 timestamp when user completed gesture.
1576 * @ingroup Elm_Gesture_Layer
1579 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1580 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1583 Evas_Coord velx = 0, vely = 0, vel;
1584 Evas_Coord dx = x2 - x1;
1585 Evas_Coord dy = y2 - y1;
1589 velx = (dx * 1000) / dtx;
1592 vely = (dy * 1000) / dty;
1594 vel = sqrt((velx * velx) + (vely * vely));
1596 if ((_elm_config->thumbscroll_friction > 0.0) &&
1597 (vel > _elm_config->thumbscroll_momentum_threshold))
1598 { /* report momentum */
1599 momentum->mx = velx;
1600 momentum->my = vely;
1612 * This function is used for computing rotation angle (DEG).
1614 * @param x1 first finger x location.
1615 * @param y1 first finger y location.
1616 * @param x2 second finger x location.
1617 * @param y2 second finger y location.
1619 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1621 * @ingroup Elm_Gesture_Layer
1624 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1630 if (((int) xx) && ((int) yy))
1637 return RAD_360DEG - a;
1648 return RAD_180DEG + a;
1652 return RAD_180DEG - a;
1658 { /* Horizontal line */
1683 * This function is used for computing the magnitude and direction
1684 * of vector between two points.
1686 * @param x1 first finger x location.
1687 * @param y1 first finger y location.
1688 * @param x2 second finger x location.
1689 * @param y2 second finger y location.
1690 * @param l length computed (output)
1691 * @param a angle computed (output)
1693 * @ingroup Elm_Gesture_Layer
1696 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1697 Evas_Coord *l, double *a)
1702 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1703 *a = get_angle(x1, y1, x2, y2);
1707 _get_direction(Evas_Coord x1, Evas_Coord x2)
1719 * This function tests momentum gesture.
1720 * @param obj The gesture-layer object.
1721 * @param pe The recent input event as stored in pe struct.
1722 * @param event_info recent input event.
1723 * @param event_type recent event type.
1724 * @param g_type what Gesture we are testing.
1726 * @ingroup Elm_Gesture_Layer
1729 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1730 void *event_info, Evas_Callback_Type event_type,
1731 Elm_Gesture_Types g_type)
1733 Widget_Data *wd = elm_widget_data_get(obj);
1735 Gesture_Info *gesture = wd->gesture[g_type];
1736 if (!gesture ) return;
1738 Momentum_Type *st = gesture->data;
1739 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1741 { /* Allocated once on first time */
1742 st = calloc(1, sizeof(Momentum_Type));
1744 _momentum_test_reset(gesture);
1750 /* First make avarage of all touched devices to determine center point */
1753 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1754 int cnt = 1; /* We start counter counting current pe event */
1755 EINA_LIST_FOREACH(wd->touched, l, p)
1756 if (p->device != pe_local.device)
1764 /* Compute avarage to get center point */
1768 /* If user added finger - reset gesture */
1769 if ((st->n_fingers) && (st->n_fingers < cnt))
1770 state_to_report = ELM_GESTURE_STATE_ABORT;
1772 st->n_fingers = cnt;
1774 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1777 case EVAS_CALLBACK_MOUSE_DOWN:
1778 case EVAS_CALLBACK_MULTI_DOWN:
1779 case EVAS_CALLBACK_MOUSE_MOVE:
1780 case EVAS_CALLBACK_MULTI_MOVE:
1783 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1784 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1785 (wd->glayer_continues_enable)) /* start also on MOVE */
1786 { /* We start on MOVE when cont-enabled only */
1787 st->line_st.x = st->line_end.x = pe_local.x;
1788 st->line_st.y = st->line_end.y = pe_local.y;
1789 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1790 st->xdir = st->ydir = 0;
1791 st->info.x2 = st->info.x1 = pe_local.x;
1792 st->info.y2 = st->info.y1 = pe_local.y;
1793 st->info.tx = st->info.ty = pe_local.timestamp;
1794 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1795 &st->info, EINA_FALSE);
1796 consume_event(wd, event_info, event_type, ev_flag);
1803 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1805 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1806 state_to_report = ELM_GESTURE_STATE_ABORT;
1808 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1809 { /* Too long of a wait, reset all values */
1810 st->line_st.x = pe_local.x;
1811 st->line_st.y = pe_local.y;
1812 st->t_st_y = st->t_st_x = pe_local.timestamp;
1813 st->info.tx = st->t_st_x;
1814 st->info.ty = st->t_st_y;
1815 st->xdir = st->ydir = 0;
1820 xdir = _get_direction(st->line_st.x, pe_local.x);
1821 ydir = _get_direction(st->line_st.y, pe_local.y);
1822 if (!xdir || (xdir == (-st->xdir)))
1824 st->line_st.x = st->line_end.x;
1825 st->info.tx = st->t_st_x = st->t_end;
1829 if (!ydir || (ydir == (-st->ydir)))
1831 st->line_st.y = st->line_end.y;
1832 st->info.ty = st->t_st_y = st->t_end;
1837 st->info.x2 = st->line_end.x = pe_local.x;
1838 st->info.y2 = st->line_end.y = pe_local.y;
1839 st->t_end = pe_local.timestamp;
1840 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1841 st->t_st_x, st->t_st_y, pe_local.timestamp);
1842 ev_flag = _set_state(gesture, state_to_report, &st->info,
1844 consume_event(wd, event_info, event_type, ev_flag);
1848 case EVAS_CALLBACK_MOUSE_UP:
1849 case EVAS_CALLBACK_MULTI_UP:
1850 st->t_up = pe_local.timestamp; /* Record recent up event time */
1851 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1852 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1855 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1856 { /* Too long of a wait, reset all values */
1857 st->line_st.x = pe_local.x;
1858 st->line_st.y = pe_local.y;
1859 st->t_st_y = st->t_st_x = pe_local.timestamp;
1860 st->xdir = st->ydir = 0;
1863 st->info.x2 = pe_local.x;
1864 st->info.y2 = pe_local.y;
1865 st->line_end.x = pe_local.x;
1866 st->line_end.y = pe_local.y;
1867 st->t_end = pe_local.timestamp;
1869 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1870 st->t_st_x, st->t_st_y, pe_local.timestamp);
1872 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1874 consume_event(wd, event_info, event_type, ev_flag);
1883 compare_line_device(const void *data1, const void *data2)
1884 { /* Compare device component of line struct */
1885 const Line_Data *ln1 = data1;
1886 const int *device = data2;
1888 if (ln1->t_st) /* Compare only with lines that started */
1889 return (ln1->device - (*device));
1897 * This function construct line struct from input.
1898 * @param info pointer to store line momentum.
1899 * @param st line info to store input data.
1900 * @param pe The recent input event as stored in pe struct.
1902 * @ingroup Elm_Gesture_Layer
1905 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1906 Pointer_Event *pe, Evas_Callback_Type event_type)
1907 { /* Record events and set momentum for line pointed by st */
1913 case EVAS_CALLBACK_MOUSE_DOWN:
1914 case EVAS_CALLBACK_MOUSE_MOVE:
1915 case EVAS_CALLBACK_MULTI_DOWN:
1916 case EVAS_CALLBACK_MULTI_MOVE:
1918 { /* This happens only when line starts */
1919 st->line_st.x = pe->x;
1920 st->line_st.y = pe->y;
1921 st->t_st = pe->timestamp;
1922 st->device = pe->device;
1923 info->momentum.x1 = pe->x;
1924 info->momentum.y1 = pe->y;
1925 info->momentum.tx = pe->timestamp;
1926 info->momentum.ty = pe->timestamp;
1933 case EVAS_CALLBACK_MOUSE_UP:
1934 case EVAS_CALLBACK_MULTI_UP:
1935 /* IGNORE if line info was cleared, like long press, move */
1939 st->line_end.x = pe->x;
1940 st->line_end.y = pe->y;
1941 st->t_end = pe->timestamp;
1950 _line_data_reset(st);
1954 info->momentum.x2 = pe->x;
1955 info->momentum.y2 = pe->y;
1956 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1957 st->t_st, st->t_st, pe->timestamp);
1965 * This function test for (n) line gesture.
1966 * @param obj The gesture-layer object.
1967 * @param pe The recent input event as stored in pe struct.
1968 * @param event_info Original input event pointer.
1969 * @param event_type Type of original input event.
1970 * @param g_type what Gesture we are testing.
1972 * @ingroup Elm_Gesture_Layer
1975 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1976 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1980 Widget_Data *wd = elm_widget_data_get(obj);
1982 Gesture_Info *gesture = wd->gesture[g_type];
1983 if (!gesture ) return;
1985 Line_Type *st = gesture->data;
1988 st = calloc(1, sizeof(Line_Type));
1992 Line_Data *line = NULL;
1993 Eina_List *list = st->list;
1994 unsigned cnt = eina_list_count(list);
1997 { /* list is not empty, locate this device on list */
1998 line = (Line_Data *) eina_list_search_unsorted(st->list,
1999 compare_line_device, &pe->device);
2003 { /* List is empty or device not found, new line-struct on START only */
2004 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2005 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2006 ((wd->glayer_continues_enable) && /* START on MOVE also */
2007 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2008 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2009 { /* Allocate new item on START only */
2010 line = calloc(1, sizeof(Line_Data));
2011 _line_data_reset(line);
2012 list = eina_list_append(list, line);
2017 if (!line) /* This may happen on MOVE that comes before DOWN */
2018 return; /* No line-struct to work with, can't continue testing */
2020 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2021 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2023 /* Get direction and magnitude of the line */
2025 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2026 &line->line_length, &angle);
2028 /* These are used later to compare lines length */
2029 Evas_Coord shortest_line_len = line->line_length;
2030 Evas_Coord longest_line_len = line->line_length;
2031 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2033 /* Now update line-state */
2035 { /* Analyze line only if line started */
2036 if (line->line_angle >= 0.0)
2037 { /* if line direction was set, we test if broke tolerance */
2038 double a = fabs(angle - line->line_angle);
2040 double d = (tan(a)) * line->line_length; /* Distance from line */
2041 #if defined(DEBUG_GESTURE_LAYER)
2042 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2044 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2045 { /* Broke tolerance: abort line and start a new one */
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);
2052 if (wd->glayer_continues_enable)
2053 { /* We may finish line if momentum is zero */
2054 /* This is for continues-gesture */
2055 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2056 { /* Finish line on zero momentum for continues gesture */
2057 line->line_end.x = pe->x;
2058 line->line_end.y = pe->y;
2059 line->t_end = pe->timestamp;
2064 { /* Record the line angle as it broke minimum length for line */
2065 if (line->line_length >= wd->line_min_length)
2066 st->info.angle = line->line_angle = angle;
2072 if (line->line_angle < 0.0)
2073 { /* it's not a line, too short more close to a tap */
2074 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2075 &st->info, EINA_FALSE);
2076 consume_event(wd, event_info, event_type, ev_flag);
2082 /* Count how many lines already started / ended */
2085 unsigned int tm_start = pe->timestamp;
2086 unsigned int tm_end = pe->timestamp;
2089 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2090 Eina_Bool lines_parallel = EINA_TRUE;
2091 EINA_LIST_FOREACH(list, l, t_line)
2094 base_angle = t_line->line_angle;
2097 if (t_line->line_angle >= 0)
2098 { /* Compare angle only with lines with direction defined */
2099 if (fabs(base_angle - t_line->line_angle) >
2100 wd->line_angular_tolerance)
2101 lines_parallel = EINA_FALSE;
2105 if (t_line->line_length)
2106 { /* update only if this line is used */
2107 if (shortest_line_len > t_line->line_length)
2108 shortest_line_len = t_line->line_length;
2110 if (longest_line_len < t_line->line_length)
2111 longest_line_len = t_line->line_length;
2117 if (t_line->t_st < tm_start)
2118 tm_start = t_line->t_st;
2124 if (t_line->t_end < tm_end)
2125 tm_end = t_line->t_end;
2129 st->info.n = started;
2133 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2134 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2135 { /* user lift one finger then starts again without line-end - ABORT */
2136 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2138 consume_event(wd, event_info, event_type, ev_flag);
2142 if (!lines_parallel)
2143 { /* Lines are NOT at same direction, abort this gesture */
2144 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2146 consume_event(wd, event_info, event_type, ev_flag);
2151 /* We report ABORT if lines length are NOT matching when fingers are up */
2152 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2154 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2156 consume_event(wd, event_info, event_type, ev_flag);
2160 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2161 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2162 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2164 consume_event(wd, event_info, event_type, ev_flag);
2170 case EVAS_CALLBACK_MOUSE_UP:
2171 case EVAS_CALLBACK_MULTI_UP:
2172 if ((started) && (started == ended))
2174 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2175 &st->info, EINA_FALSE);
2176 consume_event(wd, event_info, event_type, ev_flag);
2181 case EVAS_CALLBACK_MOUSE_DOWN:
2182 case EVAS_CALLBACK_MULTI_DOWN:
2183 case EVAS_CALLBACK_MOUSE_MOVE:
2184 case EVAS_CALLBACK_MULTI_MOVE:
2187 if (wd->glayer_continues_enable && (started == ended))
2188 { /* For continues gesture */
2189 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2190 &st->info, EINA_FALSE);
2191 consume_event(wd, event_info, event_type, ev_flag);
2194 { /* When continues, may START on MOVE event too */
2195 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2197 /* This happens when: on n > 1 lines then one finger up */
2198 /* caused abort, then put finger down. */
2199 /* This will stop line from starting again. */
2200 /* Number of lines, MUST match touched-device in list */
2201 if ((!wd->glayer_continues_enable) &&
2202 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2203 s = ELM_GESTURE_STATE_ABORT;
2205 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2206 s = ELM_GESTURE_STATE_START;
2208 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2209 consume_event(wd, event_info, event_type, ev_flag);
2215 return; /* Unhandeld event type */
2222 * This function is used to check if rotation gesture started.
2223 * @param st Contains current rotation values from user input.
2224 * @return TRUE/FALSE if we need to set rotation START.
2226 * @ingroup Elm_Gesture_Layer
2229 rotation_broke_tolerance(Rotate_Type *st)
2231 if (st->info.base_angle < 0)
2232 return EINA_FALSE; /* Angle has to be computed first */
2234 if (st->rotate_angular_tolerance < 0)
2237 double low = st->info.base_angle - st->rotate_angular_tolerance;
2238 double high = st->info.base_angle + st->rotate_angular_tolerance;
2239 double t = st->info.angle;
2252 if (high > RAD_360DEG)
2263 #if defined(DEBUG_GESTURE_LAYER)
2264 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2266 if ((t < low) || (t > high))
2267 { /* This marks that roation action has started */
2268 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2269 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2279 * This function is used for computing the gap between fingers.
2280 * It returns the length and center point between fingers.
2282 * @param x1 first finger x location.
2283 * @param y1 first finger y location.
2284 * @param x2 second finger x location.
2285 * @param y2 second finger y location.
2286 * @param x Gets center point x cord (output)
2287 * @param y Gets center point y cord (output)
2289 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2291 * @ingroup Elm_Gesture_Layer
2294 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2295 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2297 double a, b, xx, yy, gap;
2300 gap = sqrt(xx*xx + yy*yy);
2302 /* START - Compute zoom center point */
2303 /* The triangle defined as follows:
2311 * http://en.wikipedia.org/wiki/Trigonometric_functions
2312 *************************************/
2313 if (((int) xx) && ((int) yy))
2315 double A = atan((yy / xx));
2316 #if defined(DEBUG_GESTURE_LAYER)
2317 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2319 a = (Evas_Coord) ((gap / 2) * sin(A));
2320 b = (Evas_Coord) ((gap / 2) * cos(A));
2321 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2322 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2327 { /* horiz line, take half width */
2328 #if defined(DEBUG_GESTURE_LAYER)
2329 printf("==== HORIZ ====\n");
2331 *x = (Evas_Coord) (xx / 2);
2332 *y = (Evas_Coord) (y1);
2336 { /* vert line, take half width */
2337 #if defined(DEBUG_GESTURE_LAYER)
2338 printf("==== VERT ====\n");
2340 *x = (Evas_Coord) (x1);
2341 *y = (Evas_Coord) (yy / 2);
2344 /* END - Compute zoom center point */
2346 return (Evas_Coord) gap;
2352 * This function is used for computing zoom value.
2354 * @param st Pointer to zoom data based on user input.
2355 * @param x1 first finger x location.
2356 * @param y1 first finger y location.
2357 * @param x2 second finger x location.
2358 * @param y2 second finger y location.
2359 * @param factor zoom-factor, used to determine how fast zoom works.
2361 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2363 * @ingroup Elm_Gesture_Layer
2365 /* FIXME change float to double */
2367 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2368 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2371 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2372 &st->info.x, &st->info.y);
2374 st->info.radius = diam / 2;
2378 st->zoom_base = diam;
2379 return st->info.zoom;
2382 if (st->zoom_distance_tolerance)
2383 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2384 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2385 { /* avoid jump with zoom value when break tolerance */
2386 st->zoom_base -= st->zoom_distance_tolerance;
2387 st->zoom_distance_tolerance = 0;
2390 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2391 { /* avoid jump with zoom value when break tolerance */
2392 st->zoom_base += st->zoom_distance_tolerance;
2393 st->zoom_distance_tolerance = 0;
2399 /* We use factor only on the difference between gap-base */
2400 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2401 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2402 (float) st->zoom_base) * zoom_finger_factor));
2405 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2406 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2417 * This function handles zoom with mouse wheel.
2418 * thats a combination of wheel + CTRL key.
2419 * @param obj The gesture-layer object.
2420 * @param event_info Original input event pointer.
2421 * @param event_type Type of original input event.
2422 * @param g_type what Gesture we are testing.
2424 * @ingroup Elm_Gesture_Layer
2427 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2428 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2430 Widget_Data *wd = elm_widget_data_get(obj);
2432 if (!wd->gesture[g_type]) return;
2434 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2435 Zoom_Type *st = gesture_zoom->data;
2436 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2438 { /* Allocated once on first time, used for zoom intermediate data */
2439 st = calloc(1, sizeof(Zoom_Type));
2440 gesture_zoom->data = st;
2441 _zoom_test_reset(gesture_zoom);
2446 case EVAS_CALLBACK_KEY_UP:
2448 Evas_Event_Key_Up *p = event_info;
2449 if ((!strcmp(p->keyname, "Control_L")) ||
2450 (!strcmp(p->keyname, "Control_R")))
2451 { /* Test if we ended a zoom gesture when releasing CTRL */
2452 if ((st->zoom_wheel) &&
2453 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2454 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2455 { /* User released CTRL after zooming */
2456 ev_flag = _set_state(gesture_zoom,
2457 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2458 consume_event(wd, event_info, event_type, ev_flag);
2466 case EVAS_CALLBACK_MOUSE_WHEEL:
2469 Elm_Gesture_State s;
2470 if (!evas_key_modifier_is_set(
2471 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2473 { /* if using wheel witout CTRL after starting zoom */
2474 if ((st->zoom_wheel) &&
2475 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2476 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2478 ev_flag = _set_state(gesture_zoom,
2479 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2480 consume_event(wd, event_info, event_type, ev_flag);
2485 return; /* Ignore mouse-wheel without control */
2488 /* Using mouse wheel with CTRL for zoom */
2489 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2490 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2491 we continue a zoom gesture */
2493 s = ELM_GESTURE_STATE_MOVE;
2496 { /* On first wheel event, report START */
2497 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2498 evas_object_evas_get(wd->target), "Control");
2500 s = ELM_GESTURE_STATE_START;
2501 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2502 ERR("Failed to Grabbed CTRL_L");
2503 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2504 ERR("Failed to Grabbed CTRL_R");
2507 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2508 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2509 st->info.x = st->zoom_wheel->canvas.x;
2510 st->info.y = st->zoom_wheel->canvas.y;
2512 if (st->zoom_wheel->z < 0) /* zoom in */
2513 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2515 if (st->zoom_wheel->z > 0) /* zoom out */
2516 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2518 if (st->info.zoom < 0.0)
2519 st->info.zoom = 0.0;
2521 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2522 consume_event(wd, event_info, event_type, ev_flag);
2534 * This function is used to test zoom gesture.
2535 * user may combine zoom, rotation together.
2536 * so its possible that both will be detected from input.
2537 * (both are two-finger movement-oriented gestures)
2539 * @param obj The gesture-layer object.
2540 * @param event_info Pointer to recent input event.
2541 * @param event_type Recent input event type.
2542 * @param g_type what Gesture we are testing.
2544 * @ingroup Elm_Gesture_Layer
2547 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2548 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2552 Widget_Data *wd = elm_widget_data_get(obj);
2554 if (!wd->gesture[g_type]) return;
2556 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2557 Zoom_Type *st = gesture_zoom->data;
2560 { /* Allocated once on first time, used for zoom data */
2561 st = calloc(1, sizeof(Zoom_Type));
2562 gesture_zoom->data = st;
2563 _zoom_test_reset(gesture_zoom);
2567 /* Start - new zoom testing, letting all fingers start */
2568 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2571 case EVAS_CALLBACK_MOUSE_MOVE:
2572 case EVAS_CALLBACK_MULTI_MOVE:
2573 /* if non-continues mode and gesture NOT started, ignore MOVE */
2574 if ((!wd->glayer_continues_enable) &&
2575 (!st->zoom_st.timestamp))
2578 case EVAS_CALLBACK_MOUSE_DOWN:
2579 case EVAS_CALLBACK_MULTI_DOWN:
2580 { /* Here we take care of zoom-start and zoom move */
2584 if(eina_list_count(wd->touched) > 2)
2585 { /* Process zoom only when 2 fingers on surface */
2586 ev_flag = _set_state(gesture_zoom,
2587 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2588 consume_event(wd, event_info, event_type, ev_flag);
2593 if (!st->zoom_st.timestamp)
2594 { /* Now scan touched-devices list and find other finger */
2595 EINA_LIST_FOREACH(wd->touched, l, p)
2596 { /* Device of other finger <> pe device */
2597 if (p->device != pe->device)
2601 if (!p) /* Single finger on touch */
2604 /* Record down fingers */
2605 consume_event(wd, event_info, event_type, ev_flag);
2606 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2607 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2609 /* Set mv field as well to be ready for MOVE events */
2610 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2611 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2613 /* Here we have zoom_st, zoom_st1 set, report START */
2614 /* Set zoom-base after BOTH down events recorded */
2615 /* Compute length of line between fingers zoom start */
2616 st->info.zoom = 1.0;
2617 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2618 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2619 &st->info.x, &st->info.y);
2621 st->info.radius = st->zoom_base / 2;
2623 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2624 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2625 { /* zoom started with mouse-wheel, don't report twice */
2626 ev_flag = _set_state(gesture_zoom,
2627 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2628 consume_event(wd, event_info, event_type, ev_flag);
2631 return; /* Zoom started */
2632 } /* End of ZOOM_START handling */
2635 /* if we got here, we have (exacally) two fingers on surfce */
2636 /* we also after START, report MOVE */
2637 /* First detect which finger moved */
2638 if (pe->device == st->zoom_mv.device)
2639 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2640 else if (pe->device == st->zoom_mv1.device)
2641 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2643 /* Compute change in zoom as fingers move */
2644 st->info.zoom = compute_zoom(st,
2645 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2646 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2647 wd->zoom_finger_factor);
2649 if (!st->zoom_distance_tolerance)
2650 { /* Zoom broke tolerance, report move */
2651 double d = st->info.zoom - st->next_step;
2655 if (d >= wd->zoom_step)
2656 { /* Report move in steps */
2657 st->next_step = st->info.zoom;
2659 ev_flag = _set_state(gesture_zoom,
2660 ELM_GESTURE_STATE_MOVE,
2661 &st->info, EINA_TRUE);
2662 consume_event(wd, event_info, event_type, ev_flag);
2664 } /* End of ZOOM_MOVE handling */
2669 case EVAS_CALLBACK_MOUSE_UP:
2670 case EVAS_CALLBACK_MULTI_UP:
2671 /* Reset timestamp of finger-up.This is used later
2672 by _zoom_test_reset() to retain finger-down data */
2673 consume_event(wd, event_info, event_type, ev_flag);
2674 if (((st->zoom_wheel) || (st->zoom_base)) &&
2675 (st->zoom_distance_tolerance == 0))
2677 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2678 &st->info, EINA_FALSE);
2679 consume_event(wd, event_info, event_type, ev_flag);
2684 /* if we got here not a ZOOM */
2685 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2686 { /* Must be != undefined, if gesture started */
2687 ev_flag = _set_state(gesture_zoom,
2688 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2689 consume_event(wd, event_info, event_type, ev_flag);
2692 _zoom_test_reset(gesture_zoom);
2702 _get_rotate_properties(Rotate_Type *st,
2703 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2704 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2707 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2708 &st->info.x, &st->info.y) / 2;
2710 *angle = get_angle(x1, y1, x2, y2);
2711 #if 0 /* (NOT YET SUPPORTED) */
2712 if (angle == &st->info.angle)
2713 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2714 st->info.momentum = (((*angle) - st->info.base_angle) /
2715 (fabs(tm2 - tm1))) * 1000;
2718 st->info.momentum = 0;
2728 * This function is used to test rotation gesture.
2729 * user may combine zoom, rotation together.
2730 * so its possible that both will be detected from input.
2731 * (both are two-finger movement-oriented gestures)
2733 * @param obj The gesture-layer object.
2734 * @param event_info Pointer to recent input event.
2735 * @param event_type Recent input event type.
2736 * @param g_type what Gesture we are testing.
2738 * @ingroup Elm_Gesture_Layer
2741 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2742 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2747 Widget_Data *wd = elm_widget_data_get(obj);
2749 if (!wd->gesture[g_type]) return;
2751 Gesture_Info *gesture = wd->gesture[g_type];
2752 Rotate_Type *st = gesture->data;
2757 { /* Allocated once on first time */
2758 st = calloc(1, sizeof(Rotate_Type));
2760 _rotate_test_reset(gesture);
2764 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2767 case EVAS_CALLBACK_MOUSE_MOVE:
2768 case EVAS_CALLBACK_MULTI_MOVE:
2769 /* if non-continues mode and gesture NOT started, ignore MOVE */
2770 if ((!wd->glayer_continues_enable) &&
2771 (!st->rotate_st.timestamp))
2774 case EVAS_CALLBACK_MOUSE_DOWN:
2775 case EVAS_CALLBACK_MULTI_DOWN:
2776 { /* Here we take care of rotate-start and rotate move */
2780 if(eina_list_count(wd->touched) > 2)
2781 { /* Process rotate only when 2 fingers on surface */
2782 ev_flag = _set_state(gesture,
2783 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2784 consume_event(wd, event_info, event_type, ev_flag);
2789 if (!st->rotate_st.timestamp)
2790 { /* Now scan touched-devices list and find other finger */
2791 EINA_LIST_FOREACH(wd->touched, l, p)
2792 { /* Device of other finger <> pe device */
2793 if (p->device != pe->device)
2798 return; /* Single finger on touch */
2800 /* Record down fingers */
2801 consume_event(wd, event_info, event_type, ev_flag);
2802 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2803 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2805 /* Set mv field as well to be ready for MOVE events */
2806 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2807 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2809 /* Here we have rotate_st, rotate_st1 set, report START */
2810 /* Set rotate-base after BOTH down events recorded */
2811 /* Compute length of line between fingers rotate start */
2812 _get_rotate_properties(st,
2813 st->rotate_st.x, st->rotate_st.y,
2814 st->rotate_st.timestamp,
2815 st->rotate_st1.x, st->rotate_st1.y,
2816 st->rotate_st1.timestamp, &st->info.base_angle);
2818 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2819 &st->info, EINA_FALSE);
2820 consume_event(wd, event_info, event_type, ev_flag);
2822 return; /* Rotate started */
2823 } /* End of ROTATE_START handling */
2826 /* if we got here, we have (exacally) two fingers on surfce */
2827 /* we also after START, report MOVE */
2828 /* First detect which finger moved */
2829 if (pe->device == st->rotate_mv.device)
2830 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2831 else if (pe->device == st->rotate_mv1.device)
2832 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2834 /* Compute change in rotate as fingers move */
2835 _get_rotate_properties(st,
2836 st->rotate_mv.x, st->rotate_mv.y,
2837 st->rotate_mv.timestamp,
2838 st->rotate_mv1.x, st->rotate_mv1.y,
2839 st->rotate_mv1.timestamp, &st->info.angle);
2841 if (rotation_broke_tolerance(st))
2842 { /* Rotation broke tolerance, report move */
2843 double d = st->info.angle - st->next_step;
2847 if (d >= wd->rotate_step)
2848 { /* Report move in steps */
2849 st->next_step = st->info.angle;
2851 ev_flag = _set_state(gesture,
2852 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2853 consume_event(wd, event_info, event_type, ev_flag);
2855 } /* End of ROTATE_MOVE handling */
2860 case EVAS_CALLBACK_MOUSE_UP:
2861 case EVAS_CALLBACK_MULTI_UP:
2862 consume_event(wd, event_info, event_type, ev_flag);
2863 /* Reset timestamp of finger-up.This is used later
2864 by rotate_test_reset() to retain finger-down data */
2865 if (st->rotate_angular_tolerance < 0)
2867 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2868 &st->info, EINA_FALSE);
2869 consume_event(wd, event_info, event_type, ev_flag);
2874 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2875 { /* Must be != undefined, if gesture started */
2876 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2877 &st->info, EINA_FALSE);
2878 consume_event(wd, event_info, event_type, ev_flag);
2881 _rotate_test_reset(gesture);
2892 * This function is used to save input events in an abstract struct
2893 * to be used later by getsure-testing functions.
2895 * @param data The gesture-layer object.
2896 * @param event_info Pointer to recent input event.
2897 * @param event_type Recent input event type.
2898 * @param pe The abstract data-struct (output).
2900 * @ingroup Elm_Gesture_Layer
2903 _make_pointer_event(void *data, void *event_info,
2904 Evas_Callback_Type event_type, Pointer_Event *pe)
2906 Widget_Data *wd = elm_widget_data_get(data);
2907 if (!wd) return EINA_FALSE;
2909 memset(pe, '\0', sizeof(*pe));
2912 case EVAS_CALLBACK_MOUSE_DOWN:
2913 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2914 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2915 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2916 pe->device = ELM_MOUSE_DEVICE;
2919 case EVAS_CALLBACK_MOUSE_UP:
2920 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2921 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2922 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2923 pe->device = ELM_MOUSE_DEVICE;
2926 case EVAS_CALLBACK_MOUSE_MOVE:
2927 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2928 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2929 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2930 pe->device = ELM_MOUSE_DEVICE;
2933 case EVAS_CALLBACK_MULTI_DOWN:
2934 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2935 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2936 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2937 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2940 case EVAS_CALLBACK_MULTI_UP:
2941 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2942 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2943 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2944 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2947 case EVAS_CALLBACK_MULTI_MOVE:
2948 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2949 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2950 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2951 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2958 pe->event_type = event_type;
2965 * This function restartes line, flick, zoom and rotate gestures
2966 * when gesture-layer continues-gestures enabled.
2967 * Example of continues-gesture:
2968 * When doing a line, user stops moving finger but keeps fingers on touch.
2969 * This will cause line-end, then as user continues moving his finger
2970 * it re-starts line gesture.
2971 * When continue mode is disabled, user has to lift finger from touch
2972 * to end a gesture. Them touch-again to start a new one.
2974 * @param data The gesture-layer object.
2975 * @param wd gesture layer widget data.
2976 * @param states_reset flag that marks gestures were reset in history clear.
2978 * @ingroup Elm_Gesture_Layer
2980 void continues_gestures_restart(void *data, Eina_Bool states_reset)
2982 Widget_Data *wd = elm_widget_data_get(data);
2985 /* Run through events to restart gestures */
2987 Eina_Bool n_lines, n_flicks, zoom, rotate;
2988 /* We turn-on flag for finished, aborted, not-started gestures */
2989 g = wd->gesture[ELM_GESTURE_N_LINES];
2990 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2991 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2994 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
2995 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2999 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3000 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3001 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3004 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3005 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3009 g = wd->gesture[ELM_GESTURE_ZOOM];
3010 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3011 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3014 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3015 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3019 g = wd->gesture[ELM_GESTURE_ROTATE];
3020 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3021 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3024 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3025 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3033 * This function the core-function where input handling is done.
3034 * Here we get user input and stream it to gesture testing.
3035 * We notify user about any gestures with new state:
3037 * START - gesture started.
3038 * MOVE - gesture is ongoing.
3039 * END - gesture was completed.
3040 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3042 * We also check if a gesture was detected, then reset event history
3043 * If no gestures were found we reset gesture test flag
3044 * after streaming event-history to widget.
3045 * (stream to the widget all events not consumed as a gesture)
3047 * @param data The gesture-layer object.
3048 * @param event_info Pointer to recent input event.
3049 * @param event_type Recent input event type.
3051 * @ingroup Elm_Gesture_Layer
3054 _event_process(void *data, Evas_Object *obj __UNUSED__,
3055 void *event_info, Evas_Callback_Type event_type)
3058 Pointer_Event *pe = NULL;
3059 Widget_Data *wd = elm_widget_data_get(data);
3062 #if defined(DEBUG_GESTURE_LAYER)
3065 printf("Gesture | State | is tested\n");
3066 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3070 printf(" %d %d %d\n", i, g->state, g->test);
3074 /* Start testing candidate gesture from here */
3075 if (_make_pointer_event(data, event_info, event_type, &_pe))
3078 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3079 _n_long_tap_test(data, pe, event_info, event_type,
3080 ELM_GESTURE_N_LONG_TAPS);
3082 /* This takes care of single, double and tripple tap */
3083 _tap_gestures_test(data, pe, event_info, event_type);
3085 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3086 _momentum_test(data, pe, event_info, event_type,
3087 ELM_GESTURE_MOMENTUM);
3089 if (IS_TESTED(ELM_GESTURE_N_LINES))
3090 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3092 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3093 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3095 if (IS_TESTED(ELM_GESTURE_ZOOM))
3096 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3098 if (IS_TESTED(ELM_GESTURE_ZOOM))
3099 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3101 if (IS_TESTED(ELM_GESTURE_ROTATE))
3102 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3104 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3105 _event_history_add(data, event_info, event_type);
3106 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3107 (event_type == EVAS_CALLBACK_MULTI_UP))
3109 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3112 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3113 _event_history_add(data, event_info, event_type);
3117 /* Log event to restart gestures */
3118 wd->recent_device_event = _add_recent_device_event(wd->recent_device_event, &_pe);
3120 /* we maintain list of touched devices */
3121 /* We also use move to track current device x.y pos */
3122 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3123 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3124 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3125 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3127 wd->touched = _add_touched_device(wd->touched, pe);
3129 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3130 (event_type == EVAS_CALLBACK_MULTI_UP))
3132 wd->touched = _remove_touched_device(wd->touched, pe);
3135 /* Report current states and clear history if needed */
3136 Eina_Bool states_reset = _clear_if_finished(data);
3137 if (wd->glayer_continues_enable)
3138 continues_gestures_restart(data, states_reset);
3143 * For all _mouse_* / multi_* functions wethen send this event to
3144 * _event_process function.
3146 * @param data The gesture-layer object.
3147 * @param event_info Pointer to recent input event.
3149 * @ingroup Elm_Gesture_Layer
3152 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3155 Widget_Data *wd = elm_widget_data_get(data);
3157 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3158 return; /* We only process left-click at the moment */
3160 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3164 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3167 Widget_Data *wd = elm_widget_data_get(data);
3170 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3174 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3177 Widget_Data *wd = elm_widget_data_get(data);
3180 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3184 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3187 Widget_Data *wd = elm_widget_data_get(data);
3190 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3194 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3197 Widget_Data *wd = elm_widget_data_get(data);
3200 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3201 return; /* We only process left-click at the moment */
3203 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3207 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3210 Widget_Data *wd = elm_widget_data_get(data);
3213 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3217 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3220 Widget_Data *wd = elm_widget_data_get(data);
3223 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3227 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3230 Widget_Data *wd = elm_widget_data_get(data);
3233 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3237 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3240 Widget_Data *wd = elm_widget_data_get(data);
3243 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3247 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3249 Widget_Data *wd = elm_widget_data_get(obj);
3250 if (!wd) return EINA_FALSE;
3252 return !wd->repeat_events;
3256 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3258 Widget_Data *wd = elm_widget_data_get(obj);
3261 wd->repeat_events = !r;
3265 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3267 Widget_Data *wd = elm_widget_data_get(obj);
3277 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3279 Widget_Data *wd = elm_widget_data_get(obj);
3285 wd->rotate_step = s;
3289 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3291 Widget_Data *wd = elm_widget_data_get(obj);
3292 if (!wd) return EINA_FALSE;
3297 /* if was attached before, unregister callbacks first */
3299 _unregister_callbacks(obj);
3303 _register_callbacks(obj);
3308 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3309 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3311 Widget_Data *wd = elm_widget_data_get(obj);
3315 if (!wd->gesture[idx])
3316 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3317 if (!wd->gesture[idx]) return;
3319 p = wd->gesture[idx];
3322 p->fn[cb_type].cb = cb;
3323 p->fn[cb_type].user_data = data;
3324 p->state = ELM_GESTURE_STATE_UNDEFINED;
3329 _disable_hook(Evas_Object *obj)
3331 if (elm_widget_disabled_get(obj))
3332 _unregister_callbacks(obj);
3334 _register_callbacks(obj);
3338 elm_gesture_layer_add(Evas_Object *parent)
3344 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3346 wd = ELM_NEW(Widget_Data);
3347 e = evas_object_evas_get(parent);
3348 if (!e) return NULL;
3349 obj = elm_widget_add(e);
3350 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3351 elm_widget_type_set(obj, "gesture_layer");
3352 elm_widget_sub_object_add(parent, obj);
3353 elm_widget_data_set(obj, wd);
3354 elm_widget_del_hook_set(obj, _del_hook);
3355 elm_widget_disable_hook_set(obj, _disable_hook);
3358 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3359 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3360 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3361 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3362 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3363 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3364 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3365 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3366 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3367 wd->repeat_events = EINA_TRUE;
3368 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3370 #if defined(DEBUG_GESTURE_LAYER)
3371 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3372 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);
3374 memset(wd->gesture, 0, sizeof(wd->gesture));