1 #include <Elementary.h>
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
11 /* Some Trigo values */
12 #define RAD_90DEG M_PI_2
13 #define RAD_180DEG M_PI
14 #define RAD_270DEG (M_PI_2 * 3)
15 #define RAD_360DEG (M_PI * 2)
16 /* #define DEBUG_GESTURE_LAYER 1 */
19 _glayer_bufdup(void *buf, size_t size)
26 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
29 #define SET_TEST_BIT(P) do { \
30 P->test = P->fn[ELM_GESTURE_STATE_START].cb || P->fn[ELM_GESTURE_STATE_MOVE].cb || P->fn[ELM_GESTURE_STATE_END].cb || P->fn[ELM_GESTURE_STATE_ABORT].cb; \
33 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
39 * Struct holds callback information.
41 * @ingroup Elm_Gesture_Layer
45 void *user_data; /**< Holds user data to CB (like sd) */
46 Elm_Gesture_Event_Cb cb;
53 * type for callback information
55 * @ingroup Elm_Gesture_Layer
57 typedef struct _Func_Data Func_Data;
62 * @struct _Gesture_Info
63 * Struct holds gesture info
65 * @ingroup Elm_Gesture_Layer
70 void *data; /**< Holds gesture intemidiate processing data */
71 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
72 Elm_Gesture_Types g_type; /**< gesture type */
73 Elm_Gesture_State state; /**< gesture state */
74 void *info; /**< Data for the state callback */
75 Eina_Bool test; /**< if true this gesture should be tested on input */
81 * @typedef Gesture_Info
82 * Type for _Gesture_Info
84 * @ingroup Elm_Gesture_Layer
86 typedef struct _Gesture_Info Gesture_Info;
91 * @struct _Event_History
92 * Struct holds event history.
93 * These events are repeated if no gesture found.
95 * @ingroup Elm_Gesture_Layer
101 Evas_Callback_Type event_type;
107 * @typedef Event_History
108 * Type for _Event_History
110 * @ingroup Elm_Gesture_Layer
112 typedef struct _Event_History Event_History;
117 * @struct _Pointer_Event
118 * Struct holds pointer-event info
119 * This is a generic pointer event structure
121 * @ingroup Elm_Gesture_Layer
123 struct _Pointer_Event
126 unsigned int timestamp;
128 Evas_Callback_Type event_type;
134 * @typedef Pointer_Event
135 * Type for generic pointer event structure
137 * @ingroup Elm_Gesture_Layer
139 typedef struct _Pointer_Event Pointer_Event;
141 /* All *Type structs hold result for the user in 'info' field
142 * The rest is gesture processing intermediate data.
143 * NOTE: info field must be FIRST in the struct.
144 * This is used when reporting ABORT in event_history_clear() */
147 Elm_Gesture_Taps_Info info;
148 unsigned int count_ups;
154 typedef struct _Taps_Type Taps_Type;
156 struct _Long_Tap_Type
158 Elm_Gesture_Taps_Info info;
159 unsigned int center_x;
160 unsigned int center_y;
162 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
165 typedef struct _Long_Tap_Type Long_Tap_Type;
167 struct _Momentum_Type
168 { /* Fields used by _line_test() */
169 Elm_Gesture_Momentum_Info info;
170 Evas_Coord_Point line_st;
171 Evas_Coord_Point line_end;
172 unsigned int t_st_x; /* Time start on X */
173 unsigned int t_st_y; /* Time start on Y */
174 unsigned int t_end; /* Time end */
177 typedef struct _Momentum_Type Momentum_Type;
181 Evas_Coord_Point line_st;
182 Evas_Coord_Point line_end;
183 Evas_Coord line_length;
184 unsigned int t_st; /* Time start */
185 unsigned int t_end; /* Time end */
187 double line_angle; /* Current angle of line */
189 typedef struct _Line_Data Line_Data;
192 { /* Fields used by _line_test() */
193 Elm_Gesture_Line_Info info;
194 Eina_List *list; /* List of Line_Data */
196 typedef struct _Line_Type Line_Type;
199 { /* Fields used by _zoom_test() */
200 Elm_Gesture_Zoom_Info info;
201 Pointer_Event zoom_st;
202 Pointer_Event zoom_mv;
203 Pointer_Event zoom_st1;
204 Pointer_Event zoom_mv1;
205 Evas_Event_Mouse_Wheel *zoom_wheel;
206 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
207 Evas_Coord zoom_distance_tolerance;
208 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
209 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
212 typedef struct _Zoom_Type Zoom_Type;
215 { /* Fields used by _rotation_test() */
216 Elm_Gesture_Rotate_Info info;
217 Pointer_Event rotate_st;
218 Pointer_Event rotate_mv;
219 Pointer_Event rotate_st1;
220 Pointer_Event rotate_mv1;
221 double rotate_angular_tolerance;
223 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
224 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
226 typedef struct _Rotate_Type Rotate_Type;
230 Evas_Object *target; /* Target Widget */
231 Event_History *event_history_list;
234 Evas_Coord zoom_distance_tolerance;
235 Evas_Coord line_distance_tolerance;
236 double line_angular_tolerance;
237 double zoom_wheel_factor; /* mouse wheel zoom steps */
238 double zoom_finger_factor; /* used for zoom factor */
239 double rotate_angular_tolerance;
240 unsigned int flick_time_limit_ms;
241 double long_tap_start_timeout;
242 Eina_Bool glayer_continues_enable;
247 Gesture_Info *gesture[ELM_GESTURE_LAST];
248 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
249 Eina_List *pending; /* List of devices need to refeed *UP event */
250 Eina_List *touched; /* Information of touched devices */
251 Eina_List *recent_device_event; /* Information of recent pe event of each device */
253 Eina_Bool repeat_events : 1;
255 typedef struct _Widget_Data Widget_Data;
257 static const char *widtype = NULL;
258 static void _del_hook(Evas_Object *obj);
260 static Eina_Bool _event_history_clear(Evas_Object *obj);
261 static void _reset_states(Widget_Data *wd);
262 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
263 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
264 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
265 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
266 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
267 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
268 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
270 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
271 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
272 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
274 /* START - Functions to manage touched-device list */
277 * This function is used to find if device is touched
279 * @ingroup Elm_Gesture_Layer
282 compare_device(const void *data1, const void *data2)
283 { /* Compare the two device numbers */
284 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
290 * Recoed Pointer Event in touched device list
291 * Note: This fuction allocates memory for PE event
292 * This memory is released in _remove_touched_device()
293 * @param list Pointer to touched device list.
294 * @param Pointer_Event Pointer to PE.
296 * @ingroup Elm_Gesture_Layer
299 _add_touched_device(Eina_List *list, Pointer_Event *pe)
301 if (eina_list_search_unsorted_list(list, compare_device, pe))
304 Pointer_Event *p = malloc(sizeof(Pointer_Event ));
305 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
306 return eina_list_append(list, p);
312 * Remove Pointer Event from touched device list
313 * @param list Pointer to touched device list.
314 * @param Pointer_Event Pointer to PE.
316 * @ingroup Elm_Gesture_Layer
319 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
321 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
325 return eina_list_remove(list, p);
330 /* END - Functions to manage touched-device list */
332 /* START - Functions to manage recent device event list */
333 /* This list holds the recent-event for each device */
334 /* it will hold a single recent-event for each device */
335 /* We are using those PE events of this list to */
336 /* send them later to test funcs to restart gestures */
337 /* We only keep DOWN, MOVE events in this list. */
338 /* So when no touch this list is empty. */
342 * Recoed Pointer Event in touched device list
343 * Note: This fuction allocates memory for PE event
344 * This memory is released here when device untouched
346 * @param list Pointer to touched device list.
347 * @param Pointer_Event Pointer to PE.
349 * @ingroup Elm_Gesture_Layer
352 _add_recent_device_event(Eina_List *list, Pointer_Event *pe)
354 void *data = eina_list_search_sorted(list, compare_device, pe);
356 Pointer_Event *p = NULL;
357 if(data) /* First remove recent event for this device */
358 l = eina_list_remove(list, data);
361 switch(pe->event_type)
363 case EVAS_CALLBACK_MOUSE_DOWN:
364 case EVAS_CALLBACK_MOUSE_MOVE:
365 case EVAS_CALLBACK_MULTI_DOWN:
366 case EVAS_CALLBACK_MULTI_MOVE:
367 p = malloc(sizeof(Pointer_Event));
368 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in here or on cleanup */
369 l = eina_list_sorted_insert(l, compare_device, p);
372 /* Kept those cases for referance */
373 case EVAS_CALLBACK_MOUSE_IN:
374 case EVAS_CALLBACK_MOUSE_OUT:
375 case EVAS_CALLBACK_MOUSE_WHEEL:
376 case EVAS_CALLBACK_MOUSE_UP:
377 case EVAS_CALLBACK_MULTI_UP:
378 case EVAS_CALLBACK_KEY_DOWN:
379 case EVAS_CALLBACK_KEY_UP:
388 /* END - Functions to manage recent device event list */
394 * @param event_info pointer to event.
396 * @ingroup Elm_Gesture_Layer
398 static Evas_Event_Flags
399 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
403 case EVAS_CALLBACK_MOUSE_IN:
404 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
405 case EVAS_CALLBACK_MOUSE_OUT:
406 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
407 case EVAS_CALLBACK_MOUSE_DOWN:
408 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
409 case EVAS_CALLBACK_MOUSE_MOVE:
410 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
411 case EVAS_CALLBACK_MOUSE_UP:
412 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
413 case EVAS_CALLBACK_MOUSE_WHEEL:
414 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
415 case EVAS_CALLBACK_MULTI_DOWN:
416 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
417 case EVAS_CALLBACK_MULTI_MOVE:
418 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
419 case EVAS_CALLBACK_MULTI_UP:
420 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
421 case EVAS_CALLBACK_KEY_DOWN:
422 return ((Evas_Event_Key_Down *) event_info)->event_flags;
423 case EVAS_CALLBACK_KEY_UP:
424 return ((Evas_Event_Key_Up *) event_info)->event_flags;
426 return EVAS_EVENT_FLAG_NONE;
433 * Sets event flag to value returned from user callback
434 * @param wd Widget Data
435 * @param event_info pointer to event.
436 * @param event_type what type was ev (mouse down, etc...)
437 * @param ev_flags event flags
439 * @ingroup Elm_Gesture_Layer
442 consume_event(Widget_Data *wd, void *event_info,
443 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
444 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
445 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
446 /* should not refeed this event. */
448 return; /* This happens when restarting gestures */
450 if ((ev_flags) || (!wd->repeat_events))
454 case EVAS_CALLBACK_MOUSE_DOWN:
455 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
457 case EVAS_CALLBACK_MOUSE_MOVE:
458 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
460 case EVAS_CALLBACK_MOUSE_UP:
461 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
463 case EVAS_CALLBACK_MOUSE_WHEEL:
464 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
466 case EVAS_CALLBACK_MULTI_DOWN:
467 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
469 case EVAS_CALLBACK_MULTI_MOVE:
470 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
472 case EVAS_CALLBACK_MULTI_UP:
473 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
475 case EVAS_CALLBACK_KEY_DOWN:
476 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
478 case EVAS_CALLBACK_KEY_UP:
479 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
490 * Report current state of a gesture by calling user callback.
491 * @param gesture what gesture state we report.
492 * @param info inforamtion for user callback
494 * @ingroup Elm_Gesture_Layer
496 static Evas_Event_Flags
497 _report_state(Gesture_Info *gesture, void *info)
498 { /* We report current state (START, MOVE, END, ABORT), once */
499 #if defined(DEBUG_GESTURE_LAYER)
500 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
503 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
504 (gesture->fn[gesture->state].cb))
505 { /* Fill state-info struct and send ptr to user callback */
506 return gesture->fn[gesture->state].cb(
507 gesture->fn[gesture->state].user_data, info);
510 return EVAS_EVENT_FLAG_NONE;
516 * Update state for a given gesture.
517 * We may update gesture state to:
518 * UNDEFINED - current input did not start gesure yet.
519 * START - gesture started according to input.
520 * MOVE - gusture in progress.
521 * END - gesture completed according to input.
522 * ABORT - input does not matches gesure.
523 * note that we may move from UNDEFINED to ABORT
524 * because we may detect that gesture will not START
525 * with a given input.
527 * @param g given gesture to change state.
528 * @param s gesure new state.
529 * @param info buffer to be sent to user callback on report_state.
530 * @param force makes report_state to report the new-state even
531 * if its same as current state. Works for MOVE - gesture in progress.
533 * @ingroup Elm_Gesture_Layer
535 static Evas_Event_Flags
536 _set_state(Gesture_Info *g, Elm_Gesture_State s,
537 void *info, Eina_Bool force)
539 Elm_Gesture_State old_state;
540 if ((g->state == s) && (!force))
541 return EVAS_EVENT_FLAG_NONE;
543 old_state = g->state;
546 g->info = info; /* Information for user callback */
547 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
548 (g->state == ELM_GESTURE_STATE_END))
549 g->test = EINA_FALSE;
551 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
552 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
553 (s == ELM_GESTURE_STATE_ABORT))))
554 return _report_state(g, g->info);
556 return EVAS_EVENT_FLAG_NONE;
562 * This resets all gesture states and sets test-bit.
563 * this is used for restarting gestures to listen to input.
564 * happens after we complete a gesture or no gesture was detected.
565 * @param wd Widget data of the gesture-layer object.
567 * @ingroup Elm_Gesture_Layer
570 _reset_states(Widget_Data *wd)
574 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
579 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
588 * if gesture was NOT detected AND we only have gestures in ABORT state
589 * we clear history immediately to be ready for input.
591 * @param obj The gesture-layer object.
592 * @return TRUE on event history_clear
594 * @ingroup Elm_Gesture_Layer
597 _clear_if_finished(Evas_Object *obj)
599 Widget_Data *wd = elm_widget_data_get(obj);
600 if (!wd) return EINA_FALSE;
603 /* Clear history if all we have aborted gestures */
604 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
605 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
606 { /* If no gesture started and all we have aborted gestures, reset all */
607 Gesture_Info *p = wd->gesture[i];
608 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
610 if ((p->state == ELM_GESTURE_STATE_START) ||
611 (p->state == ELM_GESTURE_STATE_MOVE))
612 reset_s = EINA_FALSE;
614 all_undefined = EINA_FALSE;
618 // if ((!wd->touched) || (reset_s && !all_undefined))
619 /* (!wd->touched && reset_s) - don't stop zoom with mouse-wheel */
620 if (reset_s && (!all_undefined))
621 return _event_history_clear(obj);
627 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
629 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
645 /* All *test_reset() funcs are called to clear
646 * gesture intermediate data.
647 * This happens when we need to reset our tests.
648 * for example when gesture is detected or all ABORTed. */
650 _dbl_click_test_reset(Gesture_Info *gesture)
655 Widget_Data *wd = elm_widget_data_get(gesture->obj);
656 if (wd->dbl_timeout) ecore_timer_del(wd->dbl_timeout);
657 wd->dbl_timeout = NULL;
664 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
665 EINA_LIST_FREE(data, pe)
668 memset(gesture->data, 0, sizeof(Taps_Type));
671 /* All *test_reset() funcs are called to clear
672 * gesture intermediate data.
673 * This happens when we need to reset our tests.
674 * for example when gesture is detected or all ABORTed. */
676 _n_long_tap_test_reset(Gesture_Info *gesture)
684 Long_Tap_Type *st = gesture->data;
685 if (st->timeout) ecore_timer_del(st->timeout);
688 EINA_LIST_FOREACH(st->touched, l, p)
691 eina_list_free(st->touched);
692 memset(gesture->data, 0, sizeof(Long_Tap_Type));
696 _momentum_test_reset(Gesture_Info *gesture)
704 memset(gesture->data, 0, sizeof(Momentum_Type));
708 _line_data_reset(Line_Data *st)
713 memset(st, 0, sizeof(Line_Data));
714 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
718 _line_test_reset(Gesture_Info *gesture)
726 Line_Type *st = gesture->data;
727 Eina_List *list = st->list;
730 EINA_LIST_FOREACH(list, l, t_line)
733 eina_list_free(list);
738 _zoom_test_reset(Gesture_Info *gesture)
746 Widget_Data *wd = elm_widget_data_get(gesture->obj);
747 Zoom_Type *st = gesture->data;
748 Pointer_Event pe, pe1;
749 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
750 evas_object_evas_get(wd->target), "Control");
751 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
752 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
754 pe.timestamp = pe1.timestamp = 0;
756 if (eina_list_search_unsorted_list(wd->touched, compare_device,
758 memcpy(&pe, &st->zoom_st, sizeof(Pointer_Event));
760 if (eina_list_search_unsorted_list(wd->touched, compare_device,
762 memcpy(&pe1, &st->zoom_st1, sizeof(Pointer_Event));
764 memset(st, 0, sizeof(Zoom_Type));
766 /* If user released one finger only, restore down-info */
767 if (pe.timestamp && (!pe1.timestamp))
768 memcpy(&st->zoom_st, &pe, sizeof(Pointer_Event));
770 if (pe1.timestamp && (!pe.timestamp))
771 memcpy(&st->zoom_st1, &pe1, sizeof(Pointer_Event));
773 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
778 _rotate_test_reset(Gesture_Info *gesture)
786 Widget_Data *wd = elm_widget_data_get(gesture->obj);
787 Rotate_Type *st = gesture->data;
788 Pointer_Event pe, pe1;
790 pe.timestamp = pe1.timestamp = 0;
792 if (eina_list_search_unsorted_list(wd->touched, compare_device,
794 memcpy(&pe, &st->rotate_st, sizeof(Pointer_Event));
796 if (eina_list_search_unsorted_list(wd->touched, compare_device,
798 memcpy(&pe1, &st->rotate_st1, sizeof(Pointer_Event));
800 memset(st, 0, sizeof(Rotate_Type));
802 /* If user released one finger only, restore down-info */
803 if (pe.timestamp && (!pe1.timestamp))
804 memcpy(&st->rotate_st, &pe, sizeof(Pointer_Event));
806 if (pe1.timestamp && (!pe.timestamp))
807 memcpy(&st->rotate_st1, &pe1, sizeof(Pointer_Event));
810 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
811 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
818 * We register callbacks when gesture layer is attached to an object
819 * or when its enabled after disable.
821 * @param obj The gesture-layer object.
823 * @ingroup Elm_Gesture_Layer
826 _register_callbacks(Evas_Object *obj)
828 Widget_Data *wd = elm_widget_data_get(obj);
833 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
835 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
837 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
840 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
843 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
845 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
847 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
850 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
852 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
860 * We unregister callbacks when gesture layer is disabled.
862 * @param obj The gesture-layer object.
864 * @ingroup Elm_Gesture_Layer
867 _unregister_callbacks(Evas_Object *obj)
869 Widget_Data *wd = elm_widget_data_get(obj);
874 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
876 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
878 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
881 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
884 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
887 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
890 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
893 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
895 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
900 /* START - Event history list handling functions */
903 * This function is used to find if device number
904 * is found in a list of devices.
905 * The list contains devices for refeeding *UP event
907 * @ingroup Elm_Gesture_Layer
910 device_in_pending_list(const void *data1, const void *data2)
911 { /* Compare the two device numbers */
912 return (((intptr_t) data1) - ((intptr_t) data2));
918 * This functions adds device to refeed-pending device list
919 * @ingroup Elm_Gesture_Layer
922 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
924 int device = ELM_MOUSE_DEVICE;
927 case EVAS_CALLBACK_MOUSE_DOWN:
929 case EVAS_CALLBACK_MULTI_DOWN:
930 device = ((Evas_Event_Multi_Down *) event)->device;
936 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
939 return eina_list_append(list, (intptr_t*) device);
948 * This functions returns pending-device node
949 * @ingroup Elm_Gesture_Layer
952 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
954 int device = ELM_MOUSE_DEVICE;
957 case EVAS_CALLBACK_MOUSE_UP:
959 case EVAS_CALLBACK_MULTI_UP:
960 device = ((Evas_Event_Multi_Up *) event)->device;
966 return eina_list_search_unsorted_list(list, device_in_pending_list,
967 (intptr_t *) device);
973 * This function reports ABORT to all none-detected gestures
974 * Then resets test bits for all desired gesures
975 * and clears input-events history.
976 * note: if no gesture was detected, events from history list
977 * are streamed to the widget because it's unused by layer.
978 * user may cancel refeed of events by setting repeat events.
980 * @param obj The gesture-layer object.
982 * @ingroup Elm_Gesture_Layer
985 _event_history_clear(Evas_Object *obj)
987 Widget_Data *wd = elm_widget_data_get(obj);
988 if (!wd) return EINA_FALSE;
992 Evas *e = evas_object_evas_get(obj);
993 Eina_Bool gesture_found = EINA_FALSE;
994 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
999 if (p->state == ELM_GESTURE_STATE_END)
1000 gesture_found = EINA_TRUE;
1002 { /* Report ABORT to all gestures that still not finished */
1003 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
1009 _reset_states(wd); /* we are ready to start testing for gestures again */
1011 /* Clear all gestures intermediate date */
1012 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
1013 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
1014 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1015 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1016 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
1017 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
1018 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
1019 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
1020 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
1022 /* Disable gesture layer so refeeded events won't be consumed by it */
1023 _unregister_callbacks(obj);
1024 while (wd->event_history_list)
1027 t = wd->event_history_list;
1028 Eina_List *pending = _device_is_pending(wd->pending,
1029 wd->event_history_list->event,
1030 wd->event_history_list->event_type);
1032 /* Refeed events if no gesture matched input */
1033 if (pending || ((!gesture_found) && (!wd->repeat_events)))
1035 evas_event_refeed_event(e, wd->event_history_list->event,
1036 wd->event_history_list->event_type);
1040 wd->pending = eina_list_remove_list(wd->pending, pending);
1041 int device = ELM_MOUSE_DEVICE;
1042 if (wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
1043 device = ((Evas_Event_Multi_Up *)
1044 (wd->event_history_list->event))->device;
1047 wd->pending = _add_device_pending(wd->pending,
1048 wd->event_history_list->event,
1049 wd->event_history_list->event_type);
1052 free(wd->event_history_list->event);
1053 wd->event_history_list = (Event_History *) eina_inlist_remove(
1054 EINA_INLIST_GET(wd->event_history_list),
1055 EINA_INLIST_GET(wd->event_history_list));
1058 _register_callbacks(obj);
1065 * This function copies input events.
1066 * We copy event info before adding it to history.
1067 * The memory is freed when we clear history.
1069 * @param event the event to copy
1070 * @param event_type event type to copy
1072 * @ingroup Elm_Gesture_Layer
1075 _copy_event_info(void *event, Evas_Callback_Type event_type)
1079 case EVAS_CALLBACK_MOUSE_DOWN:
1080 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1082 case EVAS_CALLBACK_MOUSE_MOVE:
1083 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1085 case EVAS_CALLBACK_MOUSE_UP:
1086 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1088 case EVAS_CALLBACK_MOUSE_WHEEL:
1089 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1091 case EVAS_CALLBACK_MULTI_DOWN:
1092 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1094 case EVAS_CALLBACK_MULTI_MOVE:
1095 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1097 case EVAS_CALLBACK_MULTI_UP:
1098 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1100 case EVAS_CALLBACK_KEY_DOWN:
1101 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1103 case EVAS_CALLBACK_KEY_UP:
1104 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1112 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1114 Widget_Data *wd = elm_widget_data_get(obj);
1116 if (!wd) return EINA_FALSE;
1118 ev = malloc(sizeof(Event_History));
1119 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1120 ev->event_type = event_type;
1121 wd->event_history_list = (Event_History *) eina_inlist_append(
1122 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1126 /* END - Event history list handling functions */
1129 _del_hook(Evas_Object *obj)
1131 Widget_Data *wd = elm_widget_data_get(obj);
1134 _event_history_clear(obj);
1135 eina_list_free(wd->pending);
1137 Pointer_Event *data;
1138 EINA_LIST_FREE(wd->touched, data)
1141 EINA_LIST_FREE(wd->recent_device_event, data)
1144 if (!elm_widget_disabled_get(obj))
1145 _unregister_callbacks(obj);
1147 /* Free all gestures internal data structures */
1149 for (i = 0; i < ELM_GESTURE_LAST; i++)
1152 if (wd->gesture[i]->data)
1153 free(wd->gesture[i]->data);
1155 free(wd->gesture[i]);
1162 compare_match_fingers(const void *data1, const void *data2)
1163 { /* Compare coords of first item in list to cur coords */
1164 const Pointer_Event *pe1 = eina_list_data_get(data1);
1165 const Pointer_Event *pe2 = data2;
1167 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1169 else if (pe1->x < pe2->x)
1173 if (pe1->x == pe2->x)
1174 return pe1->y - pe2->y;
1181 compare_pe_device(const void *data1, const void *data2)
1182 { /* Compare coords of first item in list to cur coords */
1183 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1184 const Pointer_Event *pe2 = data2;
1186 /* Only match if last was a down event */
1187 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1188 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1192 if (pe1->device == pe2->device)
1194 else if (pe1->device < pe2->device)
1201 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1202 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1203 { /* Keep copy of pe and record it in list */
1204 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1205 memcpy(p, pe, sizeof(Pointer_Event));
1206 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1212 /* This will also update middle-point to report to user later */
1213 st->info.x = st->sum_x / st->n_taps;
1214 st->info.y = st->sum_y / st->n_taps;
1215 st->info.timestamp = pe->timestamp;
1219 pe_list = eina_list_append(pe_list, p);
1220 st->l = eina_list_append(st->l, pe_list);
1223 pe_list = eina_list_append(pe_list, p);
1231 * when this timer expires we ABORT double click gesture.
1233 * @param data The gesture-layer object.
1234 * @return cancles callback for this timer.
1236 * @ingroup Elm_Gesture_Layer
1239 _dbl_click_timeout(void *data)
1241 Gesture_Info *gesture = data;
1242 Widget_Data *wd = elm_widget_data_get(gesture->obj);
1244 wd->dbl_timeout = NULL;
1245 _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1246 gesture->info, EINA_FALSE);
1248 _dbl_click_test_reset(gesture);
1249 _clear_if_finished(gesture->obj);
1250 return ECORE_CALLBACK_CANCEL;
1256 * when this timer expires we START long tap gesture
1258 * @param data The gesture-layer object.
1259 * @return cancles callback for this timer.
1261 * @ingroup Elm_Gesture_Layer
1264 _long_tap_timeout(void *data)
1266 Gesture_Info *gesture = data;
1267 Long_Tap_Type *st = gesture->data;
1270 _set_state(gesture, ELM_GESTURE_STATE_START,
1271 gesture->data, EINA_FALSE);
1273 return ECORE_CALLBACK_CANCEL;
1279 * This function checks all click/tap and double/triple taps
1281 * @param obj The gesture-layer object.
1282 * @param pe The recent input event as stored in pe struct.
1283 * @param event_info Original input event pointer.
1284 * @param event_type Type of original input event.
1285 * @param g_type what Gesture we are testing.
1286 * @param taps How many click/taps we test for.
1288 * @ingroup Elm_Gesture_Layer
1291 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
1292 void *event_info, Evas_Callback_Type event_type,
1293 Elm_Gesture_Types g_type, int taps)
1294 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1295 Widget_Data *wd = elm_widget_data_get(obj);
1298 if (!pe) /* this happens when unhandled event arrived */
1299 return; /* see _make_pointer_event function */
1301 Gesture_Info *gesture = wd->gesture[g_type];
1302 if (!gesture ) return;
1304 if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1305 eina_list_count(wd->touched))
1306 return; /* user left a finger on device, do NOT start */
1308 Taps_Type *st = gesture->data;
1310 { /* Allocated once on first time */
1311 st = calloc(1, sizeof(Taps_Type));
1313 _dbl_click_test_reset(gesture);
1316 Eina_List *pe_list = NULL;
1317 Pointer_Event *pe_down = NULL;
1318 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1319 switch (pe->event_type)
1321 case EVAS_CALLBACK_MULTI_DOWN:
1322 case EVAS_CALLBACK_MOUSE_DOWN:
1323 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1324 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1325 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1326 { /* This is the first mouse down we got */
1327 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1328 &st->info, EINA_FALSE);
1329 consume_event(wd, event_info, event_type, ev_flag);
1331 /* To test dbl_click/dbl_tap */
1332 /* When this timer expires, gesture ABORTed if not completed */
1333 if (!wd->dbl_timeout && (taps > 1))
1334 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
1341 case EVAS_CALLBACK_MULTI_UP:
1342 case EVAS_CALLBACK_MOUSE_UP:
1343 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1345 return; /* Got only first mouse_down and mouse_up */
1347 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1349 if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
1350 return; /* Got only first mouse_down and mouse_up */
1352 /* Get first event in first list, this has to be Mouse Down event */
1353 pe_down = eina_list_data_get(pe_list);
1355 if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1361 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1362 &st->info, EINA_FALSE);
1363 consume_event(wd, event_info, event_type, ev_flag);
1367 if (st->count_ups == eina_list_count(st->l))
1369 /* Abort if we found a single click */
1370 if ((taps == 1) && (st->count_ups == 1))
1372 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1373 &st->info, EINA_FALSE);
1374 consume_event(wd, event_info, event_type, ev_flag);
1377 st->info.n = st->count_ups;
1378 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1379 &st->info, EINA_FALSE);
1380 consume_event(wd, event_info, event_type, ev_flag);
1387 case EVAS_CALLBACK_MULTI_MOVE:
1388 case EVAS_CALLBACK_MOUSE_MOVE:
1389 /* Get first event in first list, this has to be a Mouse Down event */
1390 /* and verify that user didn't move out of this area before next tap */
1391 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1394 pe_down = eina_list_data_get(pe_list);
1395 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1397 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1398 &st->info, EINA_FALSE);
1399 consume_event(wd, event_info, event_type, ev_flag);
1412 * This function computes center-point for long-tap gesture
1414 * @param st Long Tap gesture info pointer
1415 * @param pe The recent input event as stored in pe struct.
1417 * @ingroup Elm_Gesture_Layer
1420 _compute_taps_center(Long_Tap_Type *st, Pointer_Event *pe)
1422 if(!eina_list_count(st->touched))
1427 Evas_Coord x = 0, y = 0;
1428 EINA_LIST_FOREACH(st->touched, l, p)
1429 { /* Accumulate all then take avarage */
1430 if (p->device == pe->device)
1431 { /* This will take care of values coming from MOVE event */
1442 st->info.x = x / eina_list_count(st->touched);
1443 st->info.y = y / eina_list_count(st->touched);
1449 * This function checks N long-tap gesture.
1451 * @param obj The gesture-layer object.
1452 * @param pe The recent input event as stored in pe struct.
1453 * @param event_info Original input event pointer.
1454 * @param event_type Type of original input event.
1455 * @param g_type what Gesture we are testing.
1456 * @param taps How many click/taps we test for.
1458 * @ingroup Elm_Gesture_Layer
1461 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1462 void *event_info, Evas_Callback_Type event_type,
1463 Elm_Gesture_Types g_type)
1464 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1465 Widget_Data *wd = elm_widget_data_get(obj);
1468 if (!pe) /* this happens when unhandled event arrived */
1469 return; /* see _make_pointer_event function */
1471 Gesture_Info *gesture = wd->gesture[g_type];
1472 if (!gesture ) return;
1474 Long_Tap_Type *st = gesture->data;
1476 { /* Allocated once on first time */
1477 st = calloc(1, sizeof(Long_Tap_Type));
1479 _n_long_tap_test_reset(gesture);
1482 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1483 switch (pe->event_type)
1485 case EVAS_CALLBACK_MULTI_DOWN:
1486 case EVAS_CALLBACK_MOUSE_DOWN:
1487 if (st->info.n > eina_list_count(st->touched))
1488 { /* ABORT: user lifts finger then back before completing gesgure */
1489 if (st->timeout) ecore_timer_del(st->timeout);
1491 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1492 &st->info, EINA_FALSE);
1495 st->touched = _add_touched_device(st->touched, pe);
1496 st->info.n = eina_list_count(st->touched);
1497 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1498 { /* This is the first mouse down we got */
1499 st->info.timestamp = pe->timestamp;
1501 /* To test long tap */
1502 /* When this timer expires, gesture STARTED */
1504 st->timeout = ecore_timer_add(wd->long_tap_start_timeout, _long_tap_timeout,
1508 consume_event(wd, event_info, event_type, ev_flag);
1509 _compute_taps_center(st, pe);
1512 case EVAS_CALLBACK_MULTI_UP:
1513 case EVAS_CALLBACK_MOUSE_UP:
1514 st->touched = _remove_touched_device(st->touched, pe);
1516 ((gesture->state == ELM_GESTURE_STATE_START) ||
1517 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1518 { /* Report END only for gesture that STARTed */
1519 if (eina_list_count(st->touched) == 0)
1520 { /* Report END only at last release event */
1521 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1522 &st->info, EINA_FALSE);
1523 consume_event(wd, event_info, event_type, ev_flag);
1528 case EVAS_CALLBACK_MULTI_MOVE:
1529 case EVAS_CALLBACK_MOUSE_MOVE:
1531 ((gesture->state == ELM_GESTURE_STATE_START) ||
1532 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1533 { /* Report MOVE only if STARTED */
1534 _compute_taps_center(st, pe);
1535 /* Report MOVE if gesture started */
1536 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1537 &st->info, EINA_TRUE);
1538 consume_event(wd, event_info, event_type, ev_flag);
1550 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1551 * This momentum value will be sent to widget when gesture is completed.
1553 * @param momentum pointer to buffer where we record momentum value.
1554 * @param x1 x coord where user started gesture.
1555 * @param y1 y coord where user started gesture.
1556 * @param x2 x coord where user completed gesture.
1557 * @param y2 y coord where user completed gesture.
1558 * @param t1x timestamp for X, when user started gesture.
1559 * @param t1y timestamp for Y, when user started gesture.
1560 * @param t2 timestamp when user completed gesture.
1562 * @ingroup Elm_Gesture_Layer
1565 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1566 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1569 Evas_Coord velx = 0, vely = 0, vel;
1570 Evas_Coord dx = x2 - x1;
1571 Evas_Coord dy = y2 - y1;
1575 velx = (dx * 1000) / dtx;
1578 vely = (dy * 1000) / dty;
1580 vel = sqrt((velx * velx) + (vely * vely));
1582 if ((_elm_config->thumbscroll_friction > 0.0) &&
1583 (vel > _elm_config->thumbscroll_momentum_threshold))
1584 { /* report momentum */
1585 momentum->mx = velx;
1586 momentum->my = vely;
1598 * This function is used for computing rotation angle (DEG).
1600 * @param x1 first finger x location.
1601 * @param y1 first finger y location.
1602 * @param x2 second finger x location.
1603 * @param y2 second finger y location.
1605 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1607 * @ingroup Elm_Gesture_Layer
1610 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1616 if (((int) xx) && ((int) yy))
1623 return RAD_360DEG - a;
1634 return RAD_180DEG + a;
1638 return RAD_180DEG - a;
1644 { /* Horizontal line */
1669 * This function is used for computing the magnitude and direction
1670 * of vector between two points.
1672 * @param x1 first finger x location.
1673 * @param y1 first finger y location.
1674 * @param x2 second finger x location.
1675 * @param y2 second finger y location.
1676 * @param l length computed (output)
1677 * @param a angle computed (output)
1679 * @ingroup Elm_Gesture_Layer
1682 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1683 Evas_Coord *l, double *a)
1688 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1689 *a = get_angle(x1, y1, x2, y2);
1693 _get_direction(Evas_Coord x1, Evas_Coord x2)
1706 * This function tests momentum gesture.
1707 * @param obj The gesture-layer object.
1708 * @param pe The recent input event as stored in pe struct.
1709 * @param event_info recent input event.
1710 * @param event_type recent event type.
1711 * @param g_type what Gesture we are testing.
1713 * @ingroup Elm_Gesture_Layer
1716 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1717 void *event_info, Evas_Callback_Type event_type,
1718 Elm_Gesture_Types g_type)
1720 Widget_Data *wd = elm_widget_data_get(obj);
1722 Gesture_Info *gesture = wd->gesture[g_type];
1723 if (!gesture ) return;
1725 if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1726 eina_list_count(wd->touched))
1727 return; /* user left a finger on device, do NOT start */
1729 Momentum_Type *st = gesture->data;
1730 Elm_Gesture_State state_to_report;
1732 { /* Allocated once on first time */
1733 st = calloc(1, sizeof(Momentum_Type));
1735 _momentum_test_reset(gesture);
1741 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1744 case EVAS_CALLBACK_MOUSE_DOWN:
1745 st->line_st.x = st->line_end.x = pe->x;
1746 st->line_st.y = st->line_end.y = pe->y;
1747 st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1748 st->xdir = st->ydir = 0;
1749 st->info.x2 = st->info.x1 = pe->x;
1750 st->info.y2 = st->info.y1 = pe->y;
1751 st->info.tx = st->info.ty = pe->timestamp;
1752 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1753 &st->info, EINA_FALSE);
1754 consume_event(wd, event_info, event_type, ev_flag);
1757 case EVAS_CALLBACK_MOUSE_UP:
1758 /* IGNORE if line info was cleared, like long press, move */
1761 state_to_report = ELM_GESTURE_STATE_END;
1763 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1765 /* Too long of a wait, reset all values */
1766 st->line_st.x = pe->x;
1767 st->line_st.y = pe->y;
1768 st->t_st_y = st->t_st_x = pe->timestamp;
1769 st->xdir = st->ydir = 0;
1770 state_to_report = ELM_GESTURE_STATE_ABORT;
1773 st->info.x2 = pe->x;
1774 st->info.y2 = pe->y;
1775 st->line_end.x = pe->x;
1776 st->line_end.y = pe->y;
1777 st->t_end = pe->timestamp;
1779 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1780 st->t_st_x, st->t_st_y, pe->timestamp);
1782 ev_flag = _set_state(gesture, state_to_report, &st->info,
1784 consume_event(wd, event_info, event_type, ev_flag);
1788 case EVAS_CALLBACK_MOUSE_MOVE:
1789 /* IGNORE if line info was cleared, like long press, move */
1793 state_to_report = ELM_GESTURE_STATE_MOVE;
1794 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1796 /* Too long of a wait, reset all values */
1797 st->line_st.x = pe->x;
1798 st->line_st.y = pe->y;
1799 st->t_st_y = st->t_st_x = pe->timestamp;
1800 st->info.tx = st->t_st_x;
1801 st->info.ty = st->t_st_y;
1802 st->xdir = st->ydir = 0;
1803 state_to_report = ELM_GESTURE_STATE_ABORT;
1808 xdir = _get_direction(st->line_end.x, pe->x);
1809 ydir = _get_direction(st->line_end.y, pe->y);
1810 if (!xdir || (xdir == (-st->xdir)))
1812 st->line_st.x = st->line_end.x;
1813 st->info.tx = st->t_st_x = st->t_end;
1817 if (!ydir || (ydir == (-st->ydir)))
1819 st->line_st.y = st->line_end.y;
1820 st->info.ty = st->t_st_y = st->t_end;
1825 st->info.x2 = st->line_end.x = pe->x;
1826 st->info.y2 = st->line_end.y = pe->y;
1827 st->t_end = pe->timestamp;
1828 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1829 st->t_st_x, st->t_st_y, pe->timestamp);
1830 ev_flag = _set_state(gesture, state_to_report, &st->info,
1832 consume_event(wd, event_info, event_type, ev_flag);
1835 case EVAS_CALLBACK_MULTI_UP:
1836 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1838 consume_event(wd, event_info, event_type, ev_flag);
1847 compare_line_device(const void *data1, const void *data2)
1848 { /* Compare device component of line struct */
1849 const Line_Data *ln1 = data1;
1850 const int *device = data2;
1852 if (ln1->t_st) /* Compare only with lines that started */
1853 return (ln1->device - (*device));
1861 * This function construct line struct from input.
1862 * @param info pointer to store line momentum.
1863 * @param st line info to store input data.
1864 * @param pe The recent input event as stored in pe struct.
1866 * @ingroup Elm_Gesture_Layer
1869 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1870 Pointer_Event *pe, Evas_Callback_Type event_type)
1871 { /* Record events and set momentum for line pointed by st */
1877 case EVAS_CALLBACK_MOUSE_DOWN:
1878 case EVAS_CALLBACK_MULTI_DOWN:
1879 st->line_st.x = pe->x;
1880 st->line_st.y = pe->y;
1881 st->t_st = pe->timestamp;
1882 st->device = pe->device;
1883 info->momentum.x1 = pe->x;
1884 info->momentum.y1 = pe->y;
1885 info->momentum.tx = pe->timestamp;
1886 info->momentum.ty = pe->timestamp;
1891 case EVAS_CALLBACK_MOUSE_UP:
1892 case EVAS_CALLBACK_MULTI_UP:
1893 /* IGNORE if line info was cleared, like long press, move */
1897 st->line_end.x = pe->x;
1898 st->line_end.y = pe->y;
1899 st->t_end = pe->timestamp;
1902 case EVAS_CALLBACK_MOUSE_MOVE:
1903 case EVAS_CALLBACK_MULTI_MOVE:
1904 /* IGNORE if line info was cleared, like long press, move */
1915 _line_data_reset(st);
1919 info->momentum.x2 = pe->x;
1920 info->momentum.y2 = pe->y;
1921 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1922 st->t_st, st->t_st, pe->timestamp);
1930 * This function test for (n) line gesture.
1931 * @param obj The gesture-layer object.
1932 * @param pe The recent input event as stored in pe struct.
1933 * @param event_info Original input event pointer.
1934 * @param event_type Type of original input event.
1935 * @param g_type what Gesture we are testing.
1937 * @ingroup Elm_Gesture_Layer
1940 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1941 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1945 Widget_Data *wd = elm_widget_data_get(obj);
1947 Gesture_Info *gesture = wd->gesture[g_type];
1948 if (!gesture ) return;
1950 if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1951 eina_list_count(wd->touched))
1952 return; user left a finger on device, do NOT start
1954 Line_Type *st = gesture->data;
1957 st = calloc(1, sizeof(Line_Type));
1961 Line_Data *line = NULL;
1962 Eina_List *list = st->list;
1963 unsigned int i, cnt = eina_list_count(list);
1966 { /* list is not empty, locate this device on list */
1967 line = (Line_Data *) eina_list_search_unsorted(st->list,
1968 compare_line_device, &pe->device);
1971 { /* Try to locate an empty-node */
1972 for (i = 0; i < cnt; i++)
1974 line = eina_list_nth(list, i);
1976 break; /* Found a free node */
1984 { /* List is empty or device not found, new line-struct on START only */
1985 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1986 (event_type == EVAS_CALLBACK_MULTI_DOWN))
1987 { /* Allocate new item on START */
1988 line = calloc(1, sizeof(Line_Data));
1989 _line_data_reset(line);
1990 list = eina_list_append(list, line);
1995 if (!line) /* This may happen on MOVE that comes before DOWN */
1996 return; /* No line-struct to work with, can't continue testing */
1998 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
1999 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2001 /* Get direction and magnitude of the line */
2003 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2004 &line->line_length, &angle);
2006 /* These are used later to compare lines length */
2007 Evas_Coord shortest_line_len = line->line_length;
2008 Evas_Coord longest_line_len = line->line_length;
2009 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2011 /* Now update line-state */
2013 { /* Analyze line only if line started */
2014 if (line->line_angle >= 0.0)
2015 { /* if line direction was set, we test if broke tolerance */
2016 double a = fabs(angle - line->line_angle);
2018 double d = (tan(a)) * line->line_length; /* Distance from line */
2019 #if defined(DEBUG_GESTURE_LAYER)
2020 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2022 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2023 { /* Broke tolerance: abort line and start a new one */
2024 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2025 &st->info, EINA_FALSE);
2026 consume_event(wd, event_info, event_type, ev_flag);
2030 if (wd->glayer_continues_enable)
2031 { /* We may finish line if momentum is zero */
2032 /* This is for continues-gesture */
2033 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2034 { /* Finish line on zero momentum for continues gesture */
2035 line->line_end.x = pe->x;
2036 line->line_end.y = pe->y;
2037 line->t_end = pe->timestamp;
2042 { /* Record the line angle as it broke minimum length for line */
2043 if (line->line_length >= wd->line_min_length)
2044 st->info.angle = line->line_angle = angle;
2050 if (line->line_angle < 0.0)
2051 { /* it's not a line, too short more close to a tap */
2052 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2053 &st->info, EINA_FALSE);
2054 consume_event(wd, event_info, event_type, ev_flag);
2060 /* Count how many lines already started / ended */
2063 unsigned int tm_start = pe->timestamp;
2064 unsigned int tm_end = pe->timestamp;
2067 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2068 Eina_Bool lines_parallel = EINA_TRUE;
2069 EINA_LIST_FOREACH(list, l, t_line)
2072 base_angle = t_line->line_angle;
2075 if (t_line->line_angle >= 0)
2076 { /* Compare angle only with lines with direction defined */
2077 if (fabs(base_angle - t_line->line_angle) >
2078 wd->line_angular_tolerance)
2079 lines_parallel = EINA_FALSE;
2083 if (t_line->line_length)
2084 { /* update only if this line is used */
2085 if (shortest_line_len > t_line->line_length)
2086 shortest_line_len = t_line->line_length;
2088 if (longest_line_len < t_line->line_length)
2089 longest_line_len = t_line->line_length;
2095 if (t_line->t_st < tm_start)
2096 tm_start = t_line->t_st;
2102 if (t_line->t_end < tm_end)
2103 tm_end = t_line->t_end;
2107 st->info.n = started;
2111 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2112 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2113 { /* user lift one finger then starts again without line-end - ABORT */
2114 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2116 consume_event(wd, event_info, event_type, ev_flag);
2120 if (!lines_parallel)
2121 { /* Lines are NOT at same direction, abort this gesture */
2122 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2124 consume_event(wd, event_info, event_type, ev_flag);
2129 /* We report ABORT if lines length are NOT matching when fingers are up */
2130 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2132 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2134 consume_event(wd, event_info, event_type, ev_flag);
2138 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2139 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2140 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2142 consume_event(wd, event_info, event_type, ev_flag);
2148 case EVAS_CALLBACK_MOUSE_UP:
2149 case EVAS_CALLBACK_MULTI_UP:
2150 if ((started) && (started == ended))
2152 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2153 &st->info, EINA_FALSE);
2154 consume_event(wd, event_info, event_type, ev_flag);
2159 case EVAS_CALLBACK_MOUSE_DOWN:
2160 case EVAS_CALLBACK_MULTI_DOWN:
2163 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2164 &st->info, EINA_TRUE);
2165 consume_event(wd, event_info, event_type, ev_flag);
2170 case EVAS_CALLBACK_MOUSE_MOVE:
2171 case EVAS_CALLBACK_MULTI_MOVE:
2174 if (wd->glayer_continues_enable && started == ended)
2175 { /* For continues gesture */
2176 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2177 &st->info, EINA_FALSE);
2178 consume_event(wd, event_info, event_type, ev_flag);
2182 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
2183 &st->info, EINA_TRUE);
2184 consume_event(wd, event_info, event_type, ev_flag);
2190 return; /* Unhandeld event type */
2197 * This function is used to check if rotation gesture started.
2198 * @param st Contains current rotation values from user input.
2199 * @return TRUE/FALSE if we need to set rotation START.
2201 * @ingroup Elm_Gesture_Layer
2204 rotation_broke_tolerance(Rotate_Type *st)
2206 if (st->info.base_angle < 0)
2207 return EINA_FALSE; /* Angle has to be computed first */
2209 if (st->rotate_angular_tolerance < 0)
2212 double low = st->info.base_angle - st->rotate_angular_tolerance;
2213 double high = st->info.base_angle + st->rotate_angular_tolerance;
2214 double t = st->info.angle;
2227 if (high > RAD_360DEG)
2238 #if defined(DEBUG_GESTURE_LAYER)
2239 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2241 if ((t < low) || (t > high))
2242 { /* This marks that roation action has started */
2243 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2244 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2254 * This function is used for computing the gap between fingers.
2255 * It returns the length and center point between fingers.
2257 * @param x1 first finger x location.
2258 * @param y1 first finger y location.
2259 * @param x2 second finger x location.
2260 * @param y2 second finger y location.
2261 * @param x Gets center point x cord (output)
2262 * @param y Gets center point y cord (output)
2264 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2266 * @ingroup Elm_Gesture_Layer
2269 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2270 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2272 double a, b, xx, yy, gap;
2275 gap = sqrt(xx*xx + yy*yy);
2277 /* START - Compute zoom center point */
2278 /* The triangle defined as follows:
2286 * http://en.wikipedia.org/wiki/Trigonometric_functions
2287 *************************************/
2288 if (((int) xx) && ((int) yy))
2290 double A = atan((yy / xx));
2291 #if defined(DEBUG_GESTURE_LAYER)
2292 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2294 a = (Evas_Coord) ((gap / 2) * sin(A));
2295 b = (Evas_Coord) ((gap / 2) * cos(A));
2296 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2297 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2302 { /* horiz line, take half width */
2303 #if defined(DEBUG_GESTURE_LAYER)
2304 printf("==== HORIZ ====\n");
2306 *x = (Evas_Coord) (xx / 2);
2307 *y = (Evas_Coord) (y1);
2311 { /* vert line, take half width */
2312 #if defined(DEBUG_GESTURE_LAYER)
2313 printf("==== VERT ====\n");
2315 *x = (Evas_Coord) (x1);
2316 *y = (Evas_Coord) (yy / 2);
2319 /* END - Compute zoom center point */
2321 return (Evas_Coord) gap;
2327 * This function is used for computing zoom value.
2329 * @param st Pointer to zoom data based on user input.
2330 * @param x1 first finger x location.
2331 * @param y1 first finger y location.
2332 * @param x2 second finger x location.
2333 * @param y2 second finger y location.
2334 * @param factor zoom-factor, used to determine how fast zoom works.
2336 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2338 * @ingroup Elm_Gesture_Layer
2340 /* FIXME change float to double */
2342 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2343 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2346 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2347 &st->info.x, &st->info.y);
2349 st->info.radius = diam / 2;
2353 st->zoom_base = diam;
2354 return st->info.zoom;
2357 if (st->zoom_distance_tolerance)
2358 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2359 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2360 { /* avoid jump with zoom value when break tolerance */
2361 st->zoom_base -= st->zoom_distance_tolerance;
2362 st->zoom_distance_tolerance = 0;
2365 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2366 { /* avoid jump with zoom value when break tolerance */
2367 st->zoom_base += st->zoom_distance_tolerance;
2368 st->zoom_distance_tolerance = 0;
2374 /* We use factor only on the difference between gap-base */
2375 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2376 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2377 (float) st->zoom_base) * zoom_finger_factor));
2380 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2381 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2392 * This function handles zoom with mouse wheel.
2393 * thats a combination of wheel + CTRL key.
2394 * @param obj The gesture-layer object.
2395 * @param event_info Original input event pointer.
2396 * @param event_type Type of original input event.
2397 * @param g_type what Gesture we are testing.
2399 * @ingroup Elm_Gesture_Layer
2402 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2403 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2405 Widget_Data *wd = elm_widget_data_get(obj);
2407 if (!wd->gesture[g_type]) return;
2409 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2410 Zoom_Type *st = gesture_zoom->data;
2411 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2413 { /* Allocated once on first time, used for zoom intermediate data */
2414 st = calloc(1, sizeof(Zoom_Type));
2415 gesture_zoom->data = st;
2416 _zoom_test_reset(gesture_zoom);
2421 case EVAS_CALLBACK_KEY_UP:
2423 Evas_Event_Key_Up *p = event_info;
2424 if ((!strcmp(p->keyname, "Control_L")) ||
2425 (!strcmp(p->keyname, "Control_R")))
2426 { /* Test if we ended a zoom gesture when releasing CTRL */
2427 if ((st->zoom_wheel) &&
2428 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2429 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2430 { /* User released CTRL after zooming */
2431 ev_flag = _set_state(gesture_zoom,
2432 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2433 consume_event(wd, event_info, event_type, ev_flag);
2441 case EVAS_CALLBACK_MOUSE_WHEEL:
2444 Elm_Gesture_State s;
2445 if (!evas_key_modifier_is_set(
2446 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2448 { /* if using wheel witout CTRL after starting zoom */
2449 if ((st->zoom_wheel) &&
2450 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2451 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2453 ev_flag = _set_state(gesture_zoom,
2454 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2455 consume_event(wd, event_info, event_type, ev_flag);
2460 return; /* Ignore mouse-wheel without control */
2463 /* Using mouse wheel with CTRL for zoom */
2464 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2465 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2466 we continue a zoom gesture */
2468 s = ELM_GESTURE_STATE_MOVE;
2471 { /* On first wheel event, report START */
2472 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2473 evas_object_evas_get(wd->target), "Control");
2475 s = ELM_GESTURE_STATE_START;
2476 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2477 ERR("Failed to Grabbed CTRL_L");
2478 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2479 ERR("Failed to Grabbed CTRL_R");
2482 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2483 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2484 st->info.x = st->zoom_wheel->canvas.x;
2485 st->info.y = st->zoom_wheel->canvas.y;
2487 if (st->zoom_wheel->z < 0) /* zoom in */
2488 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2490 if (st->zoom_wheel->z > 0) /* zoom out */
2491 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2493 if (st->info.zoom < 0.0)
2494 st->info.zoom = 0.0;
2496 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2497 consume_event(wd, event_info, event_type, ev_flag);
2509 * This function is used to test zoom gesture.
2510 * user may combine zoom, rotation together.
2511 * so its possible that both will be detected from input.
2512 * (both are two-finger movement-oriented gestures)
2514 * @param obj The gesture-layer object.
2515 * @param event_info Pointer to recent input event.
2516 * @param event_type Recent input event type.
2517 * @param g_type what Gesture we are testing.
2519 * @ingroup Elm_Gesture_Layer
2522 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2523 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2527 Widget_Data *wd = elm_widget_data_get(obj);
2529 if (!wd->gesture[g_type]) return;
2531 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2532 Zoom_Type *st = gesture_zoom->data;
2535 { /* Allocated once on first time, used for zoom data */
2536 st = calloc(1, sizeof(Zoom_Type));
2537 gesture_zoom->data = st;
2538 _zoom_test_reset(gesture_zoom);
2541 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2544 case EVAS_CALLBACK_MOUSE_DOWN:
2545 consume_event(wd, event_info, event_type, ev_flag);
2546 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2550 case EVAS_CALLBACK_MOUSE_MOVE:
2551 consume_event(wd, event_info, event_type, ev_flag);
2552 if (!st->zoom_st.timestamp)
2553 return; /* we got move event before down event.Ignore it */
2555 consume_event(wd, event_info, event_type, ev_flag);
2556 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2558 /* We match this point to previous multi-move or multi-down event */
2559 if (st->zoom_mv1.timestamp)
2561 st->info.zoom = compute_zoom(st,
2562 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2563 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2564 wd->zoom_finger_factor);
2568 if (st->zoom_st1.timestamp)
2570 st->info.zoom = compute_zoom(st,
2571 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2572 st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2573 wd->zoom_finger_factor);
2579 case EVAS_CALLBACK_MULTI_MOVE:
2580 if (!st->zoom_st1.timestamp)
2581 return; /* We get move event before down event.Ignore it */
2583 consume_event(wd, event_info, event_type, ev_flag);
2584 if (st->zoom_mv1.timestamp)
2586 if (st->zoom_mv1.device !=
2587 ((Evas_Event_Multi_Move *) event_info)->device)
2588 { /* A third finger on screen, abort zoom */
2589 ev_flag = _set_state(gesture_zoom,
2590 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2591 consume_event(wd, event_info, event_type, ev_flag);
2597 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2599 /* Match this point to previous mouse-move or mouse-down event */
2600 if (st->zoom_mv.timestamp)
2602 st->info.zoom = compute_zoom(st,
2603 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2604 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2605 wd->zoom_finger_factor);
2609 if (st->zoom_st.timestamp)
2611 st->info.zoom = compute_zoom(st,
2612 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2613 st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2614 wd->zoom_finger_factor);
2620 case EVAS_CALLBACK_MULTI_DOWN:
2621 consume_event(wd, event_info, event_type, ev_flag);
2622 memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2625 case EVAS_CALLBACK_MOUSE_UP:
2626 case EVAS_CALLBACK_MULTI_UP:
2627 /* Reset timestamp of finger-up.This is used later
2628 by _zoom_test_reset() to retain finger-down data */
2629 consume_event(wd, event_info, event_type, ev_flag);
2630 if (((st->zoom_wheel) || (st->zoom_base)) &&
2631 (st->zoom_distance_tolerance == 0))
2633 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2634 &st->info, EINA_FALSE);
2635 consume_event(wd, event_info, event_type, ev_flag);
2640 /* if we got here not a ZOOM */
2641 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2642 { /* Must be != undefined, if gesture started */
2643 ev_flag = _set_state(gesture_zoom,
2644 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2645 consume_event(wd, event_info, event_type, ev_flag);
2648 _zoom_test_reset(gesture_zoom);
2657 if (!st->zoom_distance_tolerance)
2658 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2659 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2661 { /* Zoom broke tolerance, report move */
2662 double d = st->info.zoom - st->next_step;
2666 if (wd->glayer_continues_enable)
2667 { /* START For contiunues gesture: compute momentum */
2668 _set_momentum(&st->momentum1, st->zoom_st.x, st->zoom_st.y,
2669 st->zoom_mv.x, st->zoom_mv.y,st->zoom_st.timestamp, st->zoom_st.timestamp,
2670 st->zoom_mv.timestamp);
2672 _set_momentum(&st->momentum2, st->zoom_st1.x, st->zoom_st1.y,
2673 st->zoom_mv1.x, st->zoom_mv1.y,st->zoom_st1.timestamp, st->zoom_st1.timestamp,
2674 st->zoom_mv1.timestamp);
2676 if (!(st->momentum1.mx + st->momentum1.my + st->momentum2.mx + st->momentum2.my))
2678 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2679 &st->info, EINA_FALSE);
2682 } /* END For contiunues gesture: compute momentum */
2685 if (d >= wd->zoom_step)
2686 { /* Report move in steps */
2687 st->next_step = st->info.zoom;
2689 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2690 &st->info, EINA_TRUE);
2691 consume_event(wd, event_info, event_type, ev_flag);
2698 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2699 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2700 { /* report zoom start finger location is zoom-center temporarly */
2701 /* Zoom may have started with mouse-wheel, don't report START */
2702 if ((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2703 { /* Set zoom-base after BOTH down events were recorded */
2704 /* Compute length of line between fingers on zoom start */
2705 st->info.zoom = 1.0;
2706 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2707 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2708 &st->info.x, &st->info.y);
2710 st->info.radius = st->zoom_base / 2;
2712 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2713 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2714 { /* Report START only when two fingers touching */
2715 ev_flag = _set_state(gesture_zoom,
2716 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2717 consume_event(wd, event_info, event_type, ev_flag);
2726 _get_rotate_properties(Rotate_Type *st,
2727 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2728 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2731 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2732 &st->info.x, &st->info.y) / 2;
2734 *angle = get_angle(x1, y1, x2, y2);
2735 #if 0 /* (NOT YET SUPPORTED) */
2736 if (angle == &st->info.angle)
2737 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2738 st->info.momentum = (((*angle) - st->info.base_angle) /
2739 (fabs(tm2 - tm1))) * 1000;
2742 st->info.momentum = 0;
2752 * This function is used to test rotation gesture.
2753 * user may combine zoom, rotation together.
2754 * so its possible that both will be detected from input.
2755 * (both are two-finger movement-oriented gestures)
2757 * @param obj The gesture-layer object.
2758 * @param event_info Pointer to recent input event.
2759 * @param event_type Recent input event type.
2760 * @param g_type what Gesture we are testing.
2762 * @ingroup Elm_Gesture_Layer
2765 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2766 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2771 Widget_Data *wd = elm_widget_data_get(obj);
2773 if (!wd->gesture[g_type]) return;
2775 Gesture_Info *gesture = wd->gesture[g_type];
2776 Rotate_Type *st = gesture->data;
2781 { /* Allocated once on first time */
2782 st = calloc(1, sizeof(Rotate_Type));
2784 _rotate_test_reset(gesture);
2788 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2792 case EVAS_CALLBACK_MOUSE_DOWN:
2793 consume_event(wd, event_info, event_type, ev_flag);
2794 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2798 case EVAS_CALLBACK_MOUSE_MOVE:
2799 if (!st->rotate_st.timestamp)
2800 break; /* We got move event before down event.Ignore it */
2802 consume_event(wd, event_info, event_type, ev_flag);
2803 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2805 /* Match this point to previous multi-move or multi-down event */
2806 if (st->rotate_mv1.timestamp)
2807 { /* Compute rotation angle and report to user */
2808 _get_rotate_properties(st,
2809 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2810 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2815 if (st->rotate_st1.timestamp)
2816 { /* Compute rotation angle and report to user */
2817 _get_rotate_properties(st,
2818 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2819 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2826 case EVAS_CALLBACK_MULTI_MOVE:
2827 if (!st->rotate_st1.timestamp)
2828 break; /* We got move event before down event.Ignore it */
2830 consume_event(wd, event_info, event_type, ev_flag);
2831 if (st->rotate_mv1.timestamp)
2833 if (st->rotate_mv1.device !=
2834 ((Evas_Event_Multi_Move *) event_info)->device)
2835 { /* A third finger on screen, abort rotate */
2836 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2837 &st->info, EINA_FALSE);
2838 consume_event(wd, event_info, event_type, ev_flag);
2844 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2846 /* Match this point to previous mouse-move or mouse-down event */
2847 if (st->rotate_mv.timestamp)
2848 { /* Compute rotation angle and report to user */
2849 _get_rotate_properties(st,
2850 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2851 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2856 if (st->rotate_st.timestamp)
2857 { /* Compute rotation angle and report to user */
2858 _get_rotate_properties(st,
2859 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2860 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2867 case EVAS_CALLBACK_MULTI_DOWN:
2868 consume_event(wd, event_info, event_type, ev_flag);
2869 memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2870 _get_rotate_properties(st,
2871 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2872 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2876 case EVAS_CALLBACK_MOUSE_UP:
2877 case EVAS_CALLBACK_MULTI_UP:
2878 consume_event(wd, event_info, event_type, ev_flag);
2879 /* Reset timestamp of finger-up.This is used later
2880 by rotate_test_reset() to retain finger-down data */
2881 if (st->rotate_angular_tolerance < 0)
2883 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2884 &st->info, EINA_FALSE);
2885 consume_event(wd, event_info, event_type, ev_flag);
2890 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2891 { /* Must be != undefined, if gesture started */
2892 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2893 &st->info, EINA_FALSE);
2894 consume_event(wd, event_info, event_type, ev_flag);
2897 _rotate_test_reset(gesture);
2904 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2905 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2906 { /* Report MOVE or ABORT for *MOVE event */
2907 if (rotation_broke_tolerance(st))
2908 { /* Rotation broke tolerance, report move */
2909 double d = st->info.angle - st->next_step;
2913 if (wd->glayer_continues_enable)
2914 { /* START For contiunues gesture: compute momentum */
2915 _set_momentum(&st->momentum1, st->rotate_st.x, st->rotate_st.y,
2916 st->rotate_mv.x, st->rotate_mv.y,st->rotate_st.timestamp, st->rotate_st.timestamp,
2917 st->rotate_mv.timestamp);
2919 _set_momentum(&st->momentum2, st->rotate_st1.x, st->rotate_st1.y,
2920 st->rotate_mv1.x, st->rotate_mv1.y,st->rotate_st1.timestamp, st->rotate_st1.timestamp,
2921 st->rotate_mv1.timestamp);
2923 if (!(st->momentum1.mx + st->momentum1.my + st->momentum2.mx + st->momentum2.my))
2925 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2926 &st->info, EINA_FALSE);
2929 } /* END For contiunues gesture: compute momentum */
2931 if (d >= wd->rotate_step)
2932 { /* Report move in steps */
2933 st->next_step = st->info.angle;
2935 ev_flag = _set_state(gesture,
2936 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2937 consume_event(wd, event_info, event_type, ev_flag);
2944 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2945 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2947 if ((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2948 { /* two-fingers on touch screen - report rotate start */
2949 /* Set base angle, then report start. */
2950 _get_rotate_properties(st,
2951 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2952 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2953 &st->info.base_angle);
2955 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2956 &st->info, EINA_FALSE);
2957 consume_event(wd, event_info, event_type, ev_flag);
2967 * This function is used to save input events in an abstract struct
2968 * to be used later by getsure-testing functions.
2970 * @param data The gesture-layer object.
2971 * @param event_info Pointer to recent input event.
2972 * @param event_type Recent input event type.
2973 * @param pe The abstract data-struct (output).
2975 * @ingroup Elm_Gesture_Layer
2978 _make_pointer_event(void *data, void *event_info,
2979 Evas_Callback_Type event_type, Pointer_Event *pe)
2981 Widget_Data *wd = elm_widget_data_get(data);
2982 if (!wd) return EINA_FALSE;
2986 case EVAS_CALLBACK_MOUSE_DOWN:
2987 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2988 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2989 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2990 pe->device = ELM_MOUSE_DEVICE;
2993 case EVAS_CALLBACK_MOUSE_UP:
2994 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2995 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2996 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2997 pe->device = ELM_MOUSE_DEVICE;
3000 case EVAS_CALLBACK_MOUSE_MOVE:
3001 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
3002 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
3003 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
3004 pe->device = ELM_MOUSE_DEVICE;
3007 case EVAS_CALLBACK_MULTI_DOWN:
3008 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
3009 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
3010 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
3011 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
3014 case EVAS_CALLBACK_MULTI_UP:
3015 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
3016 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
3017 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
3018 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
3021 case EVAS_CALLBACK_MULTI_MOVE:
3022 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
3023 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
3024 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
3025 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
3032 pe->event_type = event_type;
3039 * This function restartes line, flick, zoom and rotate gestures
3040 * when gesture-layer continues-gestures enabled.
3041 * Example of continues-gesture:
3042 * When doing a line, user stops moving finger but keeps fingers on touch.
3043 * This will cause line-end, then as user continues moving his finger
3044 * it re-starts line gesture.
3045 * When continue mode is disabled, user has to lift finger from touch
3046 * to end a gesture. Them touch-again to start a new one.
3048 * @param data The gesture-layer object.
3049 * @param wd gesture layer widget data.
3050 * @param states_reset flag that marks gestures were reset in history clear.
3052 * @ingroup Elm_Gesture_Layer
3054 void continues_gestures_restart(void *data, Eina_Bool states_reset)
3056 Widget_Data *wd = elm_widget_data_get(data);
3059 /* Run through events to restart gestures */
3061 Eina_Bool n_lines, n_flicks, zoom, rotate;
3062 #if defined(DEBUG_GESTURE_LAYER)
3064 printf("Gesture | State | is tested\n");
3065 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3069 printf(" %d %d %d\n", i, g->state, g->test);
3072 /* We turn-on flag for finished, aborted, not-started gestures */
3073 g = wd->gesture[ELM_GESTURE_N_LINES];
3074 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3075 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3078 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3079 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3083 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3084 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3085 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3088 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3089 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3093 g = wd->gesture[ELM_GESTURE_ZOOM];
3094 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3095 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3098 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3099 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3104 g = wd->gesture[ELM_GESTURE_ROTATE];
3105 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3106 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3109 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3110 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3116 EINA_LIST_FOREACH(wd->recent_device_event, l, p)
3117 { /* Generate a DOWN event */
3118 Evas_Callback_Type e_type = p->event_type;
3119 if(p->event_type == EVAS_CALLBACK_MULTI_MOVE)
3120 e_type = EVAS_CALLBACK_MULTI_DOWN;
3122 if(p->event_type == EVAS_CALLBACK_MOUSE_MOVE)
3123 e_type = EVAS_CALLBACK_MOUSE_DOWN;
3126 if (n_lines && (IS_TESTED(ELM_GESTURE_N_LINES)))
3127 _n_line_test(data, p, NULL, e_type, ELM_GESTURE_N_LINES);
3129 if (n_flicks && (IS_TESTED(ELM_GESTURE_N_FLICKS)))
3130 _n_line_test(data, p, NULL, e_type, ELM_GESTURE_N_FLICKS);
3132 if (zoom && (IS_TESTED(ELM_GESTURE_ZOOM)))
3133 _zoom_test(data, p, NULL, e_type, ELM_GESTURE_ZOOM);
3135 if (rotate && (IS_TESTED(ELM_GESTURE_ROTATE)))
3136 _rotate_test(data, p, NULL, e_type, ELM_GESTURE_ROTATE);
3143 * This function the core-function where input handling is done.
3144 * Here we get user input and stream it to gesture testing.
3145 * We notify user about any gestures with new state:
3147 * START - gesture started.
3148 * MOVE - gesture is ongoing.
3149 * END - gesture was completed.
3150 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3152 * We also check if a gesture was detected, then reset event history
3153 * If no gestures were found we reset gesture test flag
3154 * after streaming event-history to widget.
3155 * (stream to the widget all events not consumed as a gesture)
3157 * @param data The gesture-layer object.
3158 * @param event_info Pointer to recent input event.
3159 * @param event_type Recent input event type.
3161 * @ingroup Elm_Gesture_Layer
3164 _event_process(void *data, Evas_Object *obj __UNUSED__,
3165 void *event_info, Evas_Callback_Type event_type)
3168 Pointer_Event *pe = NULL;
3169 Widget_Data *wd = elm_widget_data_get(data);
3172 /* Start testing candidate gesture from here */
3173 if (_make_pointer_event(data, event_info, event_type, &_pe))
3176 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3177 _n_long_tap_test(data, pe, event_info, event_type,
3178 ELM_GESTURE_N_LONG_TAPS);
3180 if (IS_TESTED(ELM_GESTURE_N_TAPS))
3181 _dbl_click_test(data, pe, event_info, event_type,
3182 ELM_GESTURE_N_TAPS, 1);
3184 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
3185 _dbl_click_test(data, pe, event_info, event_type,
3186 ELM_GESTURE_N_DOUBLE_TAPS, 2);
3188 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
3189 _dbl_click_test(data, pe, event_info, event_type,
3190 ELM_GESTURE_N_TRIPLE_TAPS, 3);
3192 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3193 _momentum_test(data, pe, event_info, event_type,
3194 ELM_GESTURE_MOMENTUM);
3196 if (IS_TESTED(ELM_GESTURE_N_LINES))
3197 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3199 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3200 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3202 if (IS_TESTED(ELM_GESTURE_ZOOM))
3203 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3205 if (IS_TESTED(ELM_GESTURE_ZOOM))
3206 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3208 if (IS_TESTED(ELM_GESTURE_ROTATE))
3209 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3211 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3212 _event_history_add(data, event_info, event_type);
3213 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3214 (event_type == EVAS_CALLBACK_MULTI_UP))
3216 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3219 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3220 _event_history_add(data, event_info, event_type);
3224 /* Log event to restart gestures */
3225 wd->recent_device_event = _add_recent_device_event(wd->recent_device_event, &_pe);
3227 /* we maintain list of touched devices*/
3228 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3229 (event_type == EVAS_CALLBACK_MULTI_DOWN))
3231 wd->touched = _add_touched_device(wd->touched, pe);
3233 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3234 (event_type == EVAS_CALLBACK_MULTI_UP))
3236 wd->touched = _remove_touched_device(wd->touched, pe);
3239 /* Report current states and clear history if needed */
3240 Eina_Bool states_reset = _clear_if_finished(data);
3241 if (wd->glayer_continues_enable)
3242 continues_gestures_restart(data, states_reset);
3247 * For all _mouse_* / multi_* functions wethen send this event to
3248 * _event_process function.
3250 * @param data The gesture-layer object.
3251 * @param event_info Pointer to recent input event.
3253 * @ingroup Elm_Gesture_Layer
3256 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3259 Widget_Data *wd = elm_widget_data_get(data);
3261 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3262 return; /* We only process left-click at the moment */
3264 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3268 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3271 Widget_Data *wd = elm_widget_data_get(data);
3274 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3278 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3281 Widget_Data *wd = elm_widget_data_get(data);
3284 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3288 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3291 Widget_Data *wd = elm_widget_data_get(data);
3294 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3298 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3301 Widget_Data *wd = elm_widget_data_get(data);
3304 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3305 return; /* We only process left-click at the moment */
3307 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3311 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3314 Widget_Data *wd = elm_widget_data_get(data);
3317 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3321 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3324 Widget_Data *wd = elm_widget_data_get(data);
3327 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3331 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3334 Widget_Data *wd = elm_widget_data_get(data);
3337 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3341 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3344 Widget_Data *wd = elm_widget_data_get(data);
3347 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3351 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3353 Widget_Data *wd = elm_widget_data_get(obj);
3354 if (!wd) return EINA_FALSE;
3356 return !wd->repeat_events;
3360 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3362 Widget_Data *wd = elm_widget_data_get(obj);
3365 wd->repeat_events = !r;
3369 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3371 Widget_Data *wd = elm_widget_data_get(obj);
3381 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3383 Widget_Data *wd = elm_widget_data_get(obj);
3389 wd->rotate_step = s;
3393 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3395 Widget_Data *wd = elm_widget_data_get(obj);
3396 if (!wd) return EINA_FALSE;
3401 /* if was attached before, unregister callbacks first */
3403 _unregister_callbacks(obj);
3407 _register_callbacks(obj);
3412 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3413 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3415 Widget_Data *wd = elm_widget_data_get(obj);
3419 if (!wd->gesture[idx])
3420 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3421 if (!wd->gesture[idx]) return;
3423 p = wd->gesture[idx];
3426 p->fn[cb_type].cb = cb;
3427 p->fn[cb_type].user_data = data;
3428 p->state = ELM_GESTURE_STATE_UNDEFINED;
3433 _disable_hook(Evas_Object *obj)
3435 if (elm_widget_disabled_get(obj))
3436 _unregister_callbacks(obj);
3438 _register_callbacks(obj);
3442 elm_gesture_layer_add(Evas_Object *parent)
3448 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3450 wd = ELM_NEW(Widget_Data);
3451 e = evas_object_evas_get(parent);
3452 if (!e) return NULL;
3453 obj = elm_widget_add(e);
3454 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3455 elm_widget_type_set(obj, "gesture_layer");
3456 elm_widget_sub_object_add(parent, obj);
3457 elm_widget_data_set(obj, wd);
3458 elm_widget_del_hook_set(obj, _del_hook);
3459 elm_widget_disable_hook_set(obj, _disable_hook);
3462 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3463 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3464 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3465 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3466 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3467 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3468 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3469 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3470 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3471 wd->repeat_events = EINA_TRUE;
3472 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3474 #if defined(DEBUG_GESTURE_LAYER)
3475 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3476 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);
3478 memset(wd->gesture, 0, sizeof(wd->gesture));