1 #include <Elementary.h>
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
10 #define ELM_GESTURE_MULTI_TIMEOUT 50
12 /* Some Trigo values */
13 #define RAD_90DEG M_PI_2
14 #define RAD_180DEG M_PI
15 #define RAD_270DEG (M_PI_2 * 3)
16 #define RAD_360DEG (M_PI * 2)
17 /* #define DEBUG_GESTURE_LAYER 1 */
20 _glayer_bufdup(void *buf, size_t size)
27 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
30 #define SET_TEST_BIT(P) do { \
31 P->test = P->fn[ELM_GESTURE_STATE_START].cb || P->fn[ELM_GESTURE_STATE_MOVE].cb || P->fn[ELM_GESTURE_STATE_END].cb || P->fn[ELM_GESTURE_STATE_ABORT].cb; \
34 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
40 * Struct holds callback information.
42 * @ingroup Elm_Gesture_Layer
46 void *user_data; /**< Holds user data to CB (like sd) */
47 Elm_Gesture_Event_Cb cb;
54 * type for callback information
56 * @ingroup Elm_Gesture_Layer
58 typedef struct _Func_Data Func_Data;
63 * @struct _Gesture_Info
64 * Struct holds gesture info
66 * @ingroup Elm_Gesture_Layer
71 void *data; /**< Holds gesture intemidiate processing data */
72 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
73 Elm_Gesture_Types g_type; /**< gesture type */
74 Elm_Gesture_State state; /**< gesture state */
75 void *info; /**< Data for the state callback */
76 Eina_Bool test; /**< if true this gesture should be tested on input */
82 * @typedef Gesture_Info
83 * Type for _Gesture_Info
85 * @ingroup Elm_Gesture_Layer
87 typedef struct _Gesture_Info Gesture_Info;
92 * @struct _Event_History
93 * Struct holds event history.
94 * These events are repeated if no gesture found.
96 * @ingroup Elm_Gesture_Layer
102 Evas_Callback_Type event_type;
108 * @typedef Event_History
109 * Type for _Event_History
111 * @ingroup Elm_Gesture_Layer
113 typedef struct _Event_History Event_History;
118 * @struct _Pointer_Event
119 * Struct holds pointer-event info
120 * This is a generic pointer event structure
122 * @ingroup Elm_Gesture_Layer
124 struct _Pointer_Event
127 unsigned int timestamp;
129 Evas_Callback_Type event_type;
135 * @typedef Pointer_Event
136 * Type for generic pointer event structure
138 * @ingroup Elm_Gesture_Layer
140 typedef struct _Pointer_Event Pointer_Event;
142 /* All *Type structs hold result for the user in 'info' field
143 * The rest is gesture processing intermediate data.
144 * NOTE: info field must be FIRST in the struct.
145 * This is used when reporting ABORT in event_history_clear() */
148 Elm_Gesture_Taps_Info info;
151 unsigned int n_taps_needed;
155 typedef struct _Taps_Type Taps_Type;
157 struct _Long_Tap_Type
159 Elm_Gesture_Taps_Info info;
162 unsigned int max_touched;
163 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
166 typedef struct _Long_Tap_Type Long_Tap_Type;
168 struct _Momentum_Type
169 { /* Fields used by _line_test() */
170 Elm_Gesture_Momentum_Info info;
171 Evas_Coord_Point line_st;
172 Evas_Coord_Point line_end;
173 unsigned int t_st_x; /* Time start on X */
174 unsigned int t_st_y; /* Time start on Y */
175 unsigned int t_end; /* Time end */
176 unsigned int t_up; /* Recent up event time */
179 typedef struct _Momentum_Type Momentum_Type;
183 Evas_Coord_Point line_st;
184 Evas_Coord_Point line_end;
185 Evas_Coord line_length;
186 unsigned int t_st; /* Time start */
187 unsigned int t_end; /* Time end */
189 double line_angle; /* Current angle of line */
191 typedef struct _Line_Data Line_Data;
194 { /* Fields used by _line_test() */
195 Elm_Gesture_Line_Info info;
196 Eina_List *list; /* List of Line_Data */
198 typedef struct _Line_Type Line_Type;
201 { /* Fields used by _zoom_test() */
202 Elm_Gesture_Zoom_Info info;
203 Pointer_Event zoom_st;
204 Pointer_Event zoom_mv;
205 Pointer_Event zoom_st1;
206 Pointer_Event zoom_mv1;
207 Evas_Event_Mouse_Wheel *zoom_wheel;
208 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
209 Evas_Coord zoom_distance_tolerance;
210 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
211 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
214 typedef struct _Zoom_Type Zoom_Type;
217 { /* Fields used by _rotation_test() */
218 Elm_Gesture_Rotate_Info info;
219 Pointer_Event rotate_st;
220 Pointer_Event rotate_mv;
221 Pointer_Event rotate_st1;
222 Pointer_Event rotate_mv1;
223 double rotate_angular_tolerance;
225 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
226 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
228 typedef struct _Rotate_Type Rotate_Type;
232 Evas_Object *target; /* Target Widget */
233 Event_History *event_history_list;
236 Evas_Coord zoom_distance_tolerance;
237 Evas_Coord line_distance_tolerance;
238 double line_angular_tolerance;
239 double zoom_wheel_factor; /* mouse wheel zoom steps */
240 double zoom_finger_factor; /* used for zoom factor */
241 double rotate_angular_tolerance;
242 unsigned int flick_time_limit_ms;
243 double long_tap_start_timeout;
244 Eina_Bool glayer_continues_enable;
249 Gesture_Info *gesture[ELM_GESTURE_LAST];
250 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
251 Eina_List *pending; /* List of devices need to refeed *UP event */
252 Eina_List *touched; /* Information of touched devices */
254 Eina_Bool repeat_events : 1;
256 typedef struct _Widget_Data Widget_Data;
258 static const char *widtype = NULL;
259 static void _del_hook(Evas_Object *obj);
261 static Eina_Bool _event_history_clear(Evas_Object *obj);
262 static void _reset_states(Widget_Data *wd);
263 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
264 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
265 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
266 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
267 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
268 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
269 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
271 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
272 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
273 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
275 /* START - Functions to manage touched-device list */
278 * This function is used to find if device is touched
280 * @ingroup Elm_Gesture_Layer
283 compare_device(const void *data1, const void *data2)
284 { /* Compare the two device numbers */
285 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
291 * Remove Pointer Event from touched device list
292 * @param list Pointer to touched device list.
293 * @param Pointer_Event Pointer to PE.
295 * @ingroup Elm_Gesture_Layer
298 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
300 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
304 return eina_list_remove(list, p);
313 * Recoed Pointer Event in touched device list
314 * Note: This fuction allocates memory for PE event
315 * This memory is released in _remove_touched_device()
316 * @param list Pointer to touched device list.
317 * @param Pointer_Event Pointer to PE.
319 * @ingroup Elm_Gesture_Layer
322 _add_touched_device(Eina_List *list, Pointer_Event *pe)
324 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
326 { /* We like to track device touch-position, overwrite info */
327 memcpy(p, pe, sizeof(Pointer_Event));
331 p = malloc(sizeof(Pointer_Event));
332 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
333 return eina_list_append(list, p);
335 /* END - Functions to manage touched-device list */
341 * @param event_info pointer to event.
343 * @ingroup Elm_Gesture_Layer
345 static Evas_Event_Flags
346 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
350 case EVAS_CALLBACK_MOUSE_IN:
351 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
352 case EVAS_CALLBACK_MOUSE_OUT:
353 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
354 case EVAS_CALLBACK_MOUSE_DOWN:
355 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
356 case EVAS_CALLBACK_MOUSE_MOVE:
357 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
358 case EVAS_CALLBACK_MOUSE_UP:
359 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
360 case EVAS_CALLBACK_MOUSE_WHEEL:
361 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
362 case EVAS_CALLBACK_MULTI_DOWN:
363 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
364 case EVAS_CALLBACK_MULTI_MOVE:
365 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
366 case EVAS_CALLBACK_MULTI_UP:
367 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
368 case EVAS_CALLBACK_KEY_DOWN:
369 return ((Evas_Event_Key_Down *) event_info)->event_flags;
370 case EVAS_CALLBACK_KEY_UP:
371 return ((Evas_Event_Key_Up *) event_info)->event_flags;
373 return EVAS_EVENT_FLAG_NONE;
380 * Sets event flag to value returned from user callback
381 * @param wd Widget Data
382 * @param event_info pointer to event.
383 * @param event_type what type was ev (mouse down, etc...)
384 * @param ev_flags event flags
386 * @ingroup Elm_Gesture_Layer
389 consume_event(Widget_Data *wd, void *event_info,
390 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
391 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
392 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
393 /* should not refeed this event. */
395 return; /* This happens when restarting gestures */
397 if ((ev_flags) || (!wd->repeat_events))
401 case EVAS_CALLBACK_MOUSE_DOWN:
402 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
404 case EVAS_CALLBACK_MOUSE_MOVE:
405 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
407 case EVAS_CALLBACK_MOUSE_UP:
408 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
410 case EVAS_CALLBACK_MOUSE_WHEEL:
411 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
413 case EVAS_CALLBACK_MULTI_DOWN:
414 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
416 case EVAS_CALLBACK_MULTI_MOVE:
417 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
419 case EVAS_CALLBACK_MULTI_UP:
420 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
422 case EVAS_CALLBACK_KEY_DOWN:
423 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
425 case EVAS_CALLBACK_KEY_UP:
426 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
437 * Report current state of a gesture by calling user callback.
438 * @param gesture what gesture state we report.
439 * @param info inforamtion for user callback
441 * @ingroup Elm_Gesture_Layer
443 static Evas_Event_Flags
444 _report_state(Gesture_Info *gesture, void *info)
445 { /* We report current state (START, MOVE, END, ABORT), once */
446 #if defined(DEBUG_GESTURE_LAYER)
447 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
450 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
451 (gesture->fn[gesture->state].cb))
452 { /* Fill state-info struct and send ptr to user callback */
453 return gesture->fn[gesture->state].cb(
454 gesture->fn[gesture->state].user_data, info);
457 return EVAS_EVENT_FLAG_NONE;
463 * Update state for a given gesture.
464 * We may update gesture state to:
465 * UNDEFINED - current input did not start gesure yet.
466 * START - gesture started according to input.
467 * MOVE - gusture in progress.
468 * END - gesture completed according to input.
469 * ABORT - input does not matches gesure.
470 * note that we may move from UNDEFINED to ABORT
471 * because we may detect that gesture will not START
472 * with a given input.
474 * @param g given gesture to change state.
475 * @param s gesure new state.
476 * @param info buffer to be sent to user callback on report_state.
477 * @param force makes report_state to report the new-state even
478 * if its same as current state. Works for MOVE - gesture in progress.
480 * @ingroup Elm_Gesture_Layer
482 static Evas_Event_Flags
483 _set_state(Gesture_Info *g, Elm_Gesture_State s,
484 void *info, Eina_Bool force)
486 Elm_Gesture_State old_state;
487 if ((g->state == s) && (!force))
488 return EVAS_EVENT_FLAG_NONE;
490 old_state = g->state;
493 g->info = info; /* Information for user callback */
494 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
495 (g->state == ELM_GESTURE_STATE_END))
496 g->test = EINA_FALSE;
498 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
499 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
500 (s == ELM_GESTURE_STATE_ABORT))))
501 return _report_state(g, g->info);
503 return EVAS_EVENT_FLAG_NONE;
509 * This resets all gesture states and sets test-bit.
510 * this is used for restarting gestures to listen to input.
511 * happens after we complete a gesture or no gesture was detected.
512 * @param wd Widget data of the gesture-layer object.
514 * @ingroup Elm_Gesture_Layer
517 _reset_states(Widget_Data *wd)
521 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
526 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
535 * if gesture was NOT detected AND we only have gestures in ABORT state
536 * we clear history immediately to be ready for input.
538 * @param obj The gesture-layer object.
539 * @return TRUE on event history_clear
541 * @ingroup Elm_Gesture_Layer
544 _clear_if_finished(Evas_Object *obj)
546 Widget_Data *wd = elm_widget_data_get(obj);
547 if (!wd) return EINA_FALSE;
550 /* Clear history if all we have aborted gestures */
551 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
552 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
553 { /* If no gesture started and all we have aborted gestures, reset all */
554 Gesture_Info *p = wd->gesture[i];
555 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
557 if ((p->state == ELM_GESTURE_STATE_START) ||
558 (p->state == ELM_GESTURE_STATE_MOVE))
559 reset_s = EINA_FALSE;
561 all_undefined = EINA_FALSE;
565 if (reset_s && (!all_undefined))
566 return _event_history_clear(obj);
572 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
574 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
590 /* All *test_reset() funcs are called to clear
591 * gesture intermediate data.
592 * This happens when we need to reset our tests.
593 * for example when gesture is detected or all ABORTed. */
595 _tap_gestures_test_reset(Gesture_Info *gesture)
600 Widget_Data *wd = elm_widget_data_get(gesture->obj);
601 wd->dbl_timeout = NULL;
608 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
609 EINA_LIST_FREE(data, pe)
612 memset(gesture->data, 0, sizeof(Taps_Type));
615 /* All *test_reset() funcs are called to clear
616 * gesture intermediate data.
617 * This happens when we need to reset our tests.
618 * for example when gesture is detected or all ABORTed. */
620 _n_long_tap_test_reset(Gesture_Info *gesture)
628 Long_Tap_Type *st = gesture->data;
631 EINA_LIST_FOREACH(st->touched, l, p)
634 eina_list_free(st->touched);
635 if (st->timeout) ecore_timer_del(st->timeout);
636 memset(gesture->data, 0, sizeof(Long_Tap_Type));
640 _momentum_test_reset(Gesture_Info *gesture)
648 memset(gesture->data, 0, sizeof(Momentum_Type));
652 _line_data_reset(Line_Data *st)
657 memset(st, 0, sizeof(Line_Data));
658 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
662 _line_test_reset(Gesture_Info *gesture)
670 Line_Type *st = gesture->data;
671 Eina_List *list = st->list;
674 EINA_LIST_FOREACH(list, l, t_line)
677 eina_list_free(list);
682 _zoom_test_reset(Gesture_Info *gesture)
690 Widget_Data *wd = elm_widget_data_get(gesture->obj);
691 Zoom_Type *st = gesture->data;
692 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
693 evas_object_evas_get(wd->target), "Control");
694 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
695 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
697 memset(st, 0, sizeof(Zoom_Type));
698 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
703 _rotate_test_reset(Gesture_Info *gesture)
711 Widget_Data *wd = elm_widget_data_get(gesture->obj);
712 Rotate_Type *st = gesture->data;
714 memset(st, 0, sizeof(Rotate_Type));
715 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
716 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
723 * We register callbacks when gesture layer is attached to an object
724 * or when its enabled after disable.
726 * @param obj The gesture-layer object.
728 * @ingroup Elm_Gesture_Layer
731 _register_callbacks(Evas_Object *obj)
733 Widget_Data *wd = elm_widget_data_get(obj);
738 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
740 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
742 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
745 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
748 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
750 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
752 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
755 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
757 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
765 * We unregister callbacks when gesture layer is disabled.
767 * @param obj The gesture-layer object.
769 * @ingroup Elm_Gesture_Layer
772 _unregister_callbacks(Evas_Object *obj)
774 Widget_Data *wd = elm_widget_data_get(obj);
779 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
781 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
783 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
786 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
789 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
792 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
795 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
798 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
800 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
805 /* START - Event history list handling functions */
808 * This function is used to find if device number
809 * is found in a list of devices.
810 * The list contains devices for refeeding *UP event
812 * @ingroup Elm_Gesture_Layer
815 device_in_pending_list(const void *data1, const void *data2)
816 { /* Compare the two device numbers */
817 return (((intptr_t) data1) - ((intptr_t) data2));
823 * This functions adds device to refeed-pending device list
824 * @ingroup Elm_Gesture_Layer
827 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
829 int device = ELM_MOUSE_DEVICE;
832 case EVAS_CALLBACK_MOUSE_DOWN:
834 case EVAS_CALLBACK_MULTI_DOWN:
835 device = ((Evas_Event_Multi_Down *) event)->device;
841 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
844 return eina_list_append(list, (intptr_t*) device);
853 * This functions returns pending-device node
854 * @ingroup Elm_Gesture_Layer
857 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
859 int device = ELM_MOUSE_DEVICE;
862 case EVAS_CALLBACK_MOUSE_UP:
864 case EVAS_CALLBACK_MULTI_UP:
865 device = ((Evas_Event_Multi_Up *) event)->device;
871 return eina_list_search_unsorted_list(list, device_in_pending_list,
872 (intptr_t *) device);
878 * This function reports ABORT to all none-detected gestures
879 * Then resets test bits for all desired gesures
880 * and clears input-events history.
881 * note: if no gesture was detected, events from history list
882 * are streamed to the widget because it's unused by layer.
883 * user may cancel refeed of events by setting repeat events.
885 * @param obj The gesture-layer object.
887 * @ingroup Elm_Gesture_Layer
890 _event_history_clear(Evas_Object *obj)
892 Widget_Data *wd = elm_widget_data_get(obj);
893 if (!wd) return EINA_FALSE;
897 Evas *e = evas_object_evas_get(obj);
898 Eina_Bool gesture_found = EINA_FALSE;
899 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
904 if (p->state == ELM_GESTURE_STATE_END)
905 gesture_found = EINA_TRUE;
907 { /* Report ABORT to all gestures that still not finished */
908 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
914 _reset_states(wd); /* we are ready to start testing for gestures again */
916 /* Clear all gestures intermediate data */
917 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
918 { /* We do not clear a long-tap gesture if fingers still on surface */
919 /* and gesture timer still pending to test gesture state */
920 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
921 if ((st) && /* st not allocated if clear occurs before 1st input */
922 ((!eina_list_count(st->touched)) || (!st->timeout)))
923 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
928 ecore_timer_del(wd->dbl_timeout);
929 wd->dbl_timeout = NULL;
932 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
933 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
934 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
935 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
936 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
937 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
938 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
939 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
941 /* Disable gesture layer so refeeded events won't be consumed by it */
942 _unregister_callbacks(obj);
943 while (wd->event_history_list)
946 t = wd->event_history_list;
947 Eina_List *pending = _device_is_pending(wd->pending,
948 wd->event_history_list->event,
949 wd->event_history_list->event_type);
951 /* Refeed events if no gesture matched input */
952 if (pending || ((!gesture_found) && (!wd->repeat_events)))
954 evas_event_refeed_event(e, wd->event_history_list->event,
955 wd->event_history_list->event_type);
959 wd->pending = eina_list_remove_list(wd->pending, pending);
963 wd->pending = _add_device_pending(wd->pending,
964 wd->event_history_list->event,
965 wd->event_history_list->event_type);
969 free(wd->event_history_list->event);
970 wd->event_history_list = (Event_History *) eina_inlist_remove(
971 EINA_INLIST_GET(wd->event_history_list),
972 EINA_INLIST_GET(wd->event_history_list));
975 _register_callbacks(obj);
982 * This function copies input events.
983 * We copy event info before adding it to history.
984 * The memory is freed when we clear history.
986 * @param event the event to copy
987 * @param event_type event type to copy
989 * @ingroup Elm_Gesture_Layer
992 _copy_event_info(void *event, Evas_Callback_Type event_type)
996 case EVAS_CALLBACK_MOUSE_DOWN:
997 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
999 case EVAS_CALLBACK_MOUSE_MOVE:
1000 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1002 case EVAS_CALLBACK_MOUSE_UP:
1003 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1005 case EVAS_CALLBACK_MOUSE_WHEEL:
1006 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1008 case EVAS_CALLBACK_MULTI_DOWN:
1009 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1011 case EVAS_CALLBACK_MULTI_MOVE:
1012 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1014 case EVAS_CALLBACK_MULTI_UP:
1015 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1017 case EVAS_CALLBACK_KEY_DOWN:
1018 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1020 case EVAS_CALLBACK_KEY_UP:
1021 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1029 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1031 Widget_Data *wd = elm_widget_data_get(obj);
1033 if (!wd) return EINA_FALSE;
1035 ev = malloc(sizeof(Event_History));
1036 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1037 ev->event_type = event_type;
1038 wd->event_history_list = (Event_History *) eina_inlist_append(
1039 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1043 /* END - Event history list handling functions */
1046 _del_hook(Evas_Object *obj)
1048 Widget_Data *wd = elm_widget_data_get(obj);
1051 _event_history_clear(obj);
1052 eina_list_free(wd->pending);
1054 Pointer_Event *data;
1055 EINA_LIST_FREE(wd->touched, data)
1058 if (!elm_widget_disabled_get(obj))
1059 _unregister_callbacks(obj);
1061 /* Free all gestures internal data structures */
1063 for (i = 0; i < ELM_GESTURE_LAST; i++)
1066 if (wd->gesture[i]->data)
1067 free(wd->gesture[i]->data);
1069 free(wd->gesture[i]);
1076 compare_match_fingers(const void *data1, const void *data2)
1077 { /* Compare coords of first item in list to cur coords */
1078 const Pointer_Event *pe1 = eina_list_data_get(data1);
1079 const Pointer_Event *pe2 = data2;
1081 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1083 else if (pe1->x < pe2->x)
1087 if (pe1->x == pe2->x)
1088 return pe1->y - pe2->y;
1095 compare_pe_device(const void *data1, const void *data2)
1096 { /* Compare device of first item in list to our pe device */
1097 const Pointer_Event *pe1 = eina_list_data_get(data1);
1098 const Pointer_Event *pe2 = data2;
1100 /* Only match if last was a down event */
1101 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1102 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1106 if (pe1->device == pe2->device)
1108 else if (pe1->device < pe2->device)
1115 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1116 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1117 { /* Keep copy of pe and record it in list */
1118 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1119 memcpy(p, pe, sizeof(Pointer_Event));
1120 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1126 /* This will also update middle-point to report to user later */
1127 st->info.x = st->sum_x / st->n_taps;
1128 st->info.y = st->sum_y / st->n_taps;
1129 st->info.timestamp = pe->timestamp;
1133 pe_list = eina_list_append(pe_list, p);
1134 st->l = eina_list_append(st->l, pe_list);
1137 pe_list = eina_list_append(pe_list, p);
1145 * This function sets state a tap-gesture to END or ABORT
1147 * @param data gesture info pointer
1149 * @ingroup Elm_Gesture_Layer
1152 _tap_gesture_finish(void *data)
1153 { /* This function will test each tap gesture when timer expires */
1154 Gesture_Info *gesture = data;
1155 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1156 /* Here we check if taps-gesture was completed successfuly */
1157 /* Count how many taps were recieved on each device then */
1158 /* determine if it matches n_taps_needed defined on START */
1159 Taps_Type *st = gesture->data;
1162 EINA_LIST_FOREACH(st->l, l, pe_list)
1164 if (eina_list_count(pe_list) != st->n_taps_needed)
1165 { /* No match taps number on device, ABORT */
1166 s = ELM_GESTURE_STATE_ABORT;
1171 st->info.n = eina_list_count(st->l);
1172 _set_state(gesture, s, gesture->info, EINA_FALSE);
1173 _tap_gestures_test_reset(gesture);
1179 * when this timer expires we finish tap gestures.
1181 * @param data The gesture-layer object.
1182 * @return cancles callback for this timer.
1184 * @ingroup Elm_Gesture_Layer
1187 _multi_tap_timeout(void *data)
1189 Widget_Data *wd = elm_widget_data_get(data);
1190 if (!wd) return EINA_FALSE;
1192 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1193 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1195 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1196 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1198 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1199 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1201 _clear_if_finished(data);
1202 wd->dbl_timeout = NULL;
1203 return ECORE_CALLBACK_CANCEL;
1209 * when this timer expires we START long tap gesture
1211 * @param data The gesture-layer object.
1212 * @return cancles callback for this timer.
1214 * @ingroup Elm_Gesture_Layer
1217 _long_tap_timeout(void *data)
1219 Gesture_Info *gesture = data;
1220 Long_Tap_Type *st = gesture->data;
1223 _set_state(gesture, ELM_GESTURE_STATE_START,
1224 gesture->data, EINA_FALSE);
1226 return ECORE_CALLBACK_CANCEL;
1233 * This function checks if a tap gesture should start
1235 * @param wd Gesture Layer Widget Data.
1236 * @param pe The recent input event as stored in pe struct.
1237 * @param event_info Original input event pointer.
1238 * @param event_type Type of original input event.
1239 * @param gesture what gesture is tested
1240 * @param how many taps for this gesture (1, 2 or 3)
1242 * @return Flag to determine if we need to set a timer for finish
1244 * @ingroup Elm_Gesture_Layer
1247 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1248 void *event_info, Evas_Callback_Type event_type,
1249 Gesture_Info *gesture, int taps)
1250 { /* Here we fill Tap struct */
1251 Taps_Type *st = gesture->data;
1253 { /* Allocated once on first time */
1254 st = calloc(1, sizeof(Taps_Type));
1256 _tap_gestures_test_reset(gesture);
1259 Eina_List *pe_list = NULL;
1260 Pointer_Event *pe_down = NULL;
1261 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1262 switch (pe->event_type)
1264 case EVAS_CALLBACK_MULTI_DOWN:
1265 case EVAS_CALLBACK_MOUSE_DOWN:
1266 /* Check if got tap on same cord was tapped before */
1267 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1270 eina_list_search_unsorted(st->l, compare_pe_device, pe))
1271 { /* This device was touched in other cord before completion */
1272 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1273 &st->info, EINA_FALSE);
1274 consume_event(wd, event_info, event_type, ev_flag);
1279 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1280 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1281 { /* This is the first mouse down we got */
1282 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1283 &st->info, EINA_FALSE);
1284 consume_event(wd, event_info, event_type, ev_flag);
1286 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1293 case EVAS_CALLBACK_MULTI_UP:
1294 case EVAS_CALLBACK_MOUSE_UP:
1295 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1299 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1302 case EVAS_CALLBACK_MULTI_MOVE:
1303 case EVAS_CALLBACK_MOUSE_MOVE:
1304 /* Get first event in first list, this has to be a Mouse Down event */
1305 /* and verify that user didn't move out of this area before next tap */
1306 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1309 pe_down = eina_list_data_get(pe_list);
1310 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1312 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1313 &st->info, EINA_FALSE);
1314 consume_event(wd, event_info, event_type, ev_flag);
1330 * This function checks all click/tap and double/triple taps
1332 * @param obj The gesture-layer object.
1333 * @param pe The recent input event as stored in pe struct.
1334 * @param event_info Original input event pointer.
1335 * @param event_type Type of original input event.
1337 * @ingroup Elm_Gesture_Layer
1340 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1341 void *event_info, Evas_Callback_Type event_type)
1342 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1343 Eina_Bool need_timer = EINA_FALSE;
1344 Widget_Data *wd = elm_widget_data_get(obj);
1347 if (!pe) /* this happens when unhandled event arrived */
1348 return; /* see _make_pointer_event function */
1350 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1351 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1352 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1354 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1355 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1356 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1358 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1359 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1360 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1362 if ((need_timer) && (!wd->dbl_timeout))
1363 { /* Set a timer to finish these gestures */
1364 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1372 * This function computes center-point for long-tap gesture
1374 * @param st Long Tap gesture info pointer
1375 * @param pe The recent input event as stored in pe struct.
1377 * @ingroup Elm_Gesture_Layer
1380 _compute_taps_center(Long_Tap_Type *st,
1381 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1383 if(!eina_list_count(st->touched))
1388 Evas_Coord x = 0, y = 0;
1389 EINA_LIST_FOREACH(st->touched, l, p)
1390 { /* Accumulate all then take avarage */
1391 if (p->device == pe->device)
1392 { /* This will take care of values coming from MOVE event */
1403 *x_out = x / eina_list_count(st->touched);
1404 *y_out = y / eina_list_count(st->touched);
1410 * This function checks N long-tap gesture.
1412 * @param obj The gesture-layer object.
1413 * @param pe The recent input event as stored in pe struct.
1414 * @param event_info Original input event pointer.
1415 * @param event_type Type of original input event.
1416 * @param g_type what Gesture we are testing.
1417 * @param taps How many click/taps we test for.
1419 * @ingroup Elm_Gesture_Layer
1422 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1423 void *event_info, Evas_Callback_Type event_type,
1424 Elm_Gesture_Types g_type)
1425 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1426 Widget_Data *wd = elm_widget_data_get(obj);
1429 if (!pe) /* this happens when unhandled event arrived */
1430 return; /* see _make_pointer_event function */
1431 Gesture_Info *gesture = wd->gesture[g_type];
1432 if (!gesture) return;
1434 Long_Tap_Type *st = gesture->data;
1436 { /* Allocated once on first time */
1437 st = calloc(1, sizeof(Long_Tap_Type));
1439 _n_long_tap_test_reset(gesture);
1442 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1443 switch (pe->event_type)
1445 case EVAS_CALLBACK_MULTI_DOWN:
1446 case EVAS_CALLBACK_MOUSE_DOWN:
1447 st->touched = _add_touched_device(st->touched, pe);
1448 st->info.n = eina_list_count(st->touched);
1449 if (st->info.n > st->max_touched)
1450 st->max_touched = st->info.n;
1452 { /* User removed finger from touch, then put back - ABORT */
1453 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1454 (gesture->state == ELM_GESTURE_STATE_MOVE))
1456 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1457 &st->info, EINA_FALSE);
1458 consume_event(wd, event_info, event_type, ev_flag);
1462 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1463 { /* This is the first mouse down we got */
1464 st->info.timestamp = pe->timestamp;
1466 /* To test long tap */
1467 /* When this timer expires, gesture STARTED */
1469 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1470 _long_tap_timeout, gesture);
1473 consume_event(wd, event_info, event_type, ev_flag);
1474 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1475 st->center_x = st->info.x;
1476 st->center_y = st->info.y;
1479 case EVAS_CALLBACK_MULTI_UP:
1480 case EVAS_CALLBACK_MOUSE_UP:
1481 st->touched = _remove_touched_device(st->touched, pe);
1482 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1484 ((gesture->state == ELM_GESTURE_STATE_START) ||
1485 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1486 { /* Report END only for gesture that STARTed */
1487 if (eina_list_count(st->touched) == 0)
1488 { /* Report END only at last release event */
1489 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1490 &st->info, EINA_FALSE);
1491 consume_event(wd, event_info, event_type, ev_flag);
1495 { /* Stop test, user lifts finger before long-start */
1496 if (st->timeout) ecore_timer_del(st->timeout);
1498 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1499 &st->info, EINA_FALSE);
1500 consume_event(wd, event_info, event_type, ev_flag);
1505 case EVAS_CALLBACK_MULTI_MOVE:
1506 case EVAS_CALLBACK_MOUSE_MOVE:
1508 ((gesture->state == ELM_GESTURE_STATE_START) ||
1509 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1510 { /* Report MOVE only if STARTED */
1513 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1515 _compute_taps_center(st, &x, &y, pe);
1516 /* ABORT if user moved fingers out of tap area */
1517 #if defined(DEBUG_GESTURE_LAYER)
1518 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1520 if (!_inside(x, y, st->center_x, st->center_y))
1521 state_to_report = ELM_GESTURE_STATE_ABORT;
1523 /* Report MOVE if gesture started */
1524 ev_flag = _set_state(gesture, state_to_report,
1525 &st->info, EINA_TRUE);
1526 consume_event(wd, event_info, event_type, ev_flag);
1538 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1539 * This momentum value will be sent to widget when gesture is completed.
1541 * @param momentum pointer to buffer where we record momentum value.
1542 * @param x1 x coord where user started gesture.
1543 * @param y1 y coord where user started gesture.
1544 * @param x2 x coord where user completed gesture.
1545 * @param y2 y coord where user completed gesture.
1546 * @param t1x timestamp for X, when user started gesture.
1547 * @param t1y timestamp for Y, when user started gesture.
1548 * @param t2 timestamp when user completed gesture.
1550 * @ingroup Elm_Gesture_Layer
1553 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1554 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1557 Evas_Coord velx = 0, vely = 0, vel;
1558 Evas_Coord dx = x2 - x1;
1559 Evas_Coord dy = y2 - y1;
1563 velx = (dx * 1000) / dtx;
1566 vely = (dy * 1000) / dty;
1568 vel = sqrt((velx * velx) + (vely * vely));
1570 if ((_elm_config->thumbscroll_friction > 0.0) &&
1571 (vel > _elm_config->thumbscroll_momentum_threshold))
1572 { /* report momentum */
1573 momentum->mx = velx;
1574 momentum->my = vely;
1586 * This function is used for computing rotation angle (DEG).
1588 * @param x1 first finger x location.
1589 * @param y1 first finger y location.
1590 * @param x2 second finger x location.
1591 * @param y2 second finger y location.
1593 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1595 * @ingroup Elm_Gesture_Layer
1598 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1604 if (((int) xx) && ((int) yy))
1611 return RAD_360DEG - a;
1622 return RAD_180DEG + a;
1626 return RAD_180DEG - a;
1632 { /* Horizontal line */
1657 * This function is used for computing the magnitude and direction
1658 * of vector between two points.
1660 * @param x1 first finger x location.
1661 * @param y1 first finger y location.
1662 * @param x2 second finger x location.
1663 * @param y2 second finger y location.
1664 * @param l length computed (output)
1665 * @param a angle computed (output)
1667 * @ingroup Elm_Gesture_Layer
1670 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1671 Evas_Coord *l, double *a)
1676 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1677 *a = get_angle(x1, y1, x2, y2);
1681 _get_direction(Evas_Coord x1, Evas_Coord x2)
1693 * This function tests momentum gesture.
1694 * @param obj The gesture-layer object.
1695 * @param pe The recent input event as stored in pe struct.
1696 * @param event_info recent input event.
1697 * @param event_type recent event type.
1698 * @param g_type what Gesture we are testing.
1700 * @ingroup Elm_Gesture_Layer
1703 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1704 void *event_info, Evas_Callback_Type event_type,
1705 Elm_Gesture_Types g_type)
1707 Widget_Data *wd = elm_widget_data_get(obj);
1709 Gesture_Info *gesture = wd->gesture[g_type];
1710 if (!gesture ) return;
1712 Momentum_Type *st = gesture->data;
1713 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1715 { /* Allocated once on first time */
1716 st = calloc(1, sizeof(Momentum_Type));
1718 _momentum_test_reset(gesture);
1724 /* First make avarage of all touched devices to determine center point */
1727 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1728 unsigned int cnt = 1; /* We start counter counting current pe event */
1729 EINA_LIST_FOREACH(wd->touched, l, p)
1730 if (p->device != pe_local.device)
1738 /* Compute avarage to get center point */
1742 /* If user added finger - reset gesture */
1743 if ((st->info.n) && (st->info.n < cnt))
1744 state_to_report = ELM_GESTURE_STATE_ABORT;
1746 if (st->info.n < cnt)
1749 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1752 case EVAS_CALLBACK_MOUSE_DOWN:
1753 case EVAS_CALLBACK_MULTI_DOWN:
1754 case EVAS_CALLBACK_MOUSE_MOVE:
1755 case EVAS_CALLBACK_MULTI_MOVE:
1758 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1759 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1760 (wd->glayer_continues_enable)) /* start also on MOVE */
1761 { /* We start on MOVE when cont-enabled only */
1762 st->line_st.x = st->line_end.x = pe_local.x;
1763 st->line_st.y = st->line_end.y = pe_local.y;
1764 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1765 st->xdir = st->ydir = 0;
1766 st->info.x2 = st->info.x1 = pe_local.x;
1767 st->info.y2 = st->info.y1 = pe_local.y;
1768 st->info.tx = st->info.ty = pe_local.timestamp;
1769 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1770 &st->info, EINA_FALSE);
1771 consume_event(wd, event_info, event_type, ev_flag);
1778 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1780 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1781 state_to_report = ELM_GESTURE_STATE_ABORT;
1783 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1784 { /* Too long of a wait, reset all values */
1785 st->line_st.x = pe_local.x;
1786 st->line_st.y = pe_local.y;
1787 st->t_st_y = st->t_st_x = pe_local.timestamp;
1788 st->info.tx = st->t_st_x;
1789 st->info.ty = st->t_st_y;
1790 st->xdir = st->ydir = 0;
1795 xdir = _get_direction(st->line_st.x, pe_local.x);
1796 ydir = _get_direction(st->line_st.y, pe_local.y);
1797 if (!xdir || (xdir == (-st->xdir)))
1799 st->line_st.x = st->line_end.x;
1800 st->info.tx = st->t_st_x = st->t_end;
1804 if (!ydir || (ydir == (-st->ydir)))
1806 st->line_st.y = st->line_end.y;
1807 st->info.ty = st->t_st_y = st->t_end;
1812 st->info.x2 = st->line_end.x = pe_local.x;
1813 st->info.y2 = st->line_end.y = pe_local.y;
1814 st->t_end = pe_local.timestamp;
1815 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1816 st->t_st_x, st->t_st_y, pe_local.timestamp);
1817 ev_flag = _set_state(gesture, state_to_report, &st->info,
1819 consume_event(wd, event_info, event_type, ev_flag);
1823 case EVAS_CALLBACK_MOUSE_UP:
1824 case EVAS_CALLBACK_MULTI_UP:
1825 st->t_up = pe_local.timestamp; /* Record recent up event time */
1826 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1827 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1830 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1831 { /* Too long of a wait, reset all values */
1832 st->line_st.x = pe_local.x;
1833 st->line_st.y = pe_local.y;
1834 st->t_st_y = st->t_st_x = pe_local.timestamp;
1835 st->xdir = st->ydir = 0;
1838 st->info.x2 = pe_local.x;
1839 st->info.y2 = pe_local.y;
1840 st->line_end.x = pe_local.x;
1841 st->line_end.y = pe_local.y;
1842 st->t_end = pe_local.timestamp;
1844 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1845 st->t_st_x, st->t_st_y, pe_local.timestamp);
1847 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1849 consume_event(wd, event_info, event_type, ev_flag);
1858 compare_line_device(const void *data1, const void *data2)
1859 { /* Compare device component of line struct */
1860 const Line_Data *ln1 = data1;
1861 const int *device = data2;
1863 if (ln1->t_st) /* Compare only with lines that started */
1864 return (ln1->device - (*device));
1872 * This function construct line struct from input.
1873 * @param info pointer to store line momentum.
1874 * @param st line info to store input data.
1875 * @param pe The recent input event as stored in pe struct.
1877 * @ingroup Elm_Gesture_Layer
1880 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1881 Pointer_Event *pe, Evas_Callback_Type event_type)
1882 { /* Record events and set momentum for line pointed by st */
1888 case EVAS_CALLBACK_MOUSE_DOWN:
1889 case EVAS_CALLBACK_MOUSE_MOVE:
1890 case EVAS_CALLBACK_MULTI_DOWN:
1891 case EVAS_CALLBACK_MULTI_MOVE:
1893 { /* This happens only when line starts */
1894 st->line_st.x = pe->x;
1895 st->line_st.y = pe->y;
1896 st->t_st = pe->timestamp;
1897 st->device = pe->device;
1898 info->momentum.x1 = pe->x;
1899 info->momentum.y1 = pe->y;
1900 info->momentum.tx = pe->timestamp;
1901 info->momentum.ty = pe->timestamp;
1908 case EVAS_CALLBACK_MOUSE_UP:
1909 case EVAS_CALLBACK_MULTI_UP:
1910 /* IGNORE if line info was cleared, like long press, move */
1914 st->line_end.x = pe->x;
1915 st->line_end.y = pe->y;
1916 st->t_end = pe->timestamp;
1925 _line_data_reset(st);
1929 info->momentum.x2 = pe->x;
1930 info->momentum.y2 = pe->y;
1931 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1932 st->t_st, st->t_st, pe->timestamp);
1940 * This function test for (n) line gesture.
1941 * @param obj The gesture-layer object.
1942 * @param pe The recent input event as stored in pe struct.
1943 * @param event_info Original input event pointer.
1944 * @param event_type Type of original input event.
1945 * @param g_type what Gesture we are testing.
1947 * @ingroup Elm_Gesture_Layer
1950 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1951 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1955 Widget_Data *wd = elm_widget_data_get(obj);
1957 Gesture_Info *gesture = wd->gesture[g_type];
1958 if (!gesture ) return;
1960 Line_Type *st = gesture->data;
1963 st = calloc(1, sizeof(Line_Type));
1967 Line_Data *line = NULL;
1968 Eina_List *list = st->list;
1969 unsigned cnt = eina_list_count(list);
1972 { /* list is not empty, locate this device on list */
1973 line = (Line_Data *) eina_list_search_unsorted(st->list,
1974 compare_line_device, &pe->device);
1978 { /* List is empty or device not found, new line-struct on START only */
1979 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1980 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1981 ((wd->glayer_continues_enable) && /* START on MOVE also */
1982 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1983 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
1984 { /* Allocate new item on START only */
1985 line = calloc(1, sizeof(Line_Data));
1986 _line_data_reset(line);
1987 list = eina_list_append(list, line);
1992 if (!line) /* This may happen on MOVE that comes before DOWN */
1993 return; /* No line-struct to work with, can't continue testing */
1995 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
1996 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1998 /* Get direction and magnitude of the line */
2000 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2001 &line->line_length, &angle);
2003 /* These are used later to compare lines length */
2004 Evas_Coord shortest_line_len = line->line_length;
2005 Evas_Coord longest_line_len = line->line_length;
2006 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2008 /* Now update line-state */
2010 { /* Analyze line only if line started */
2011 if (line->line_angle >= 0.0)
2012 { /* if line direction was set, we test if broke tolerance */
2013 double a = fabs(angle - line->line_angle);
2015 double d = (tan(a)) * line->line_length; /* Distance from line */
2016 #if defined(DEBUG_GESTURE_LAYER)
2017 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2019 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2020 { /* Broke tolerance: abort line and start a new one */
2021 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2022 &st->info, EINA_FALSE);
2023 consume_event(wd, event_info, event_type, ev_flag);
2027 if (wd->glayer_continues_enable)
2028 { /* We may finish line if momentum is zero */
2029 /* This is for continues-gesture */
2030 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2031 { /* Finish line on zero momentum for continues gesture */
2032 line->line_end.x = pe->x;
2033 line->line_end.y = pe->y;
2034 line->t_end = pe->timestamp;
2039 { /* Record the line angle as it broke minimum length for line */
2040 if (line->line_length >= wd->line_min_length)
2041 st->info.angle = line->line_angle = angle;
2047 if (line->line_angle < 0.0)
2048 { /* it's not a line, too short more close to a tap */
2049 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2050 &st->info, EINA_FALSE);
2051 consume_event(wd, event_info, event_type, ev_flag);
2057 /* Count how many lines already started / ended */
2060 unsigned int tm_start = pe->timestamp;
2061 unsigned int tm_end = pe->timestamp;
2064 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2065 Eina_Bool lines_parallel = EINA_TRUE;
2066 EINA_LIST_FOREACH(list, l, t_line)
2069 base_angle = t_line->line_angle;
2072 if (t_line->line_angle >= 0)
2073 { /* Compare angle only with lines with direction defined */
2074 if (fabs(base_angle - t_line->line_angle) >
2075 wd->line_angular_tolerance)
2076 lines_parallel = EINA_FALSE;
2080 if (t_line->line_length)
2081 { /* update only if this line is used */
2082 if (shortest_line_len > t_line->line_length)
2083 shortest_line_len = t_line->line_length;
2085 if (longest_line_len < t_line->line_length)
2086 longest_line_len = t_line->line_length;
2092 if (t_line->t_st < tm_start)
2093 tm_start = t_line->t_st;
2099 if (t_line->t_end < tm_end)
2100 tm_end = t_line->t_end;
2104 st->info.momentum.n = started;
2108 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2109 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2110 { /* user lift one finger then starts again without line-end - ABORT */
2111 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2113 consume_event(wd, event_info, event_type, ev_flag);
2117 if (!lines_parallel)
2118 { /* Lines are NOT at same direction, abort this gesture */
2119 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2121 consume_event(wd, event_info, event_type, ev_flag);
2126 /* We report ABORT if lines length are NOT matching when fingers are up */
2127 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2129 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2131 consume_event(wd, event_info, event_type, ev_flag);
2135 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2136 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2137 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2139 consume_event(wd, event_info, event_type, ev_flag);
2145 case EVAS_CALLBACK_MOUSE_UP:
2146 case EVAS_CALLBACK_MULTI_UP:
2147 if ((started) && (started == ended))
2149 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2150 &st->info, EINA_FALSE);
2151 consume_event(wd, event_info, event_type, ev_flag);
2156 case EVAS_CALLBACK_MOUSE_DOWN:
2157 case EVAS_CALLBACK_MULTI_DOWN:
2158 case EVAS_CALLBACK_MOUSE_MOVE:
2159 case EVAS_CALLBACK_MULTI_MOVE:
2162 if (wd->glayer_continues_enable && (started == ended))
2163 { /* For continues gesture */
2164 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2165 &st->info, EINA_FALSE);
2166 consume_event(wd, event_info, event_type, ev_flag);
2169 { /* When continues, may START on MOVE event too */
2170 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2172 /* This happens when: on n > 1 lines then one finger up */
2173 /* caused abort, then put finger down. */
2174 /* This will stop line from starting again. */
2175 /* Number of lines, MUST match touched-device in list */
2176 if ((!wd->glayer_continues_enable) &&
2177 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2178 s = ELM_GESTURE_STATE_ABORT;
2180 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2181 s = ELM_GESTURE_STATE_START;
2183 ev_flag = _set_state(gesture, s, &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
2341 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2342 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2345 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2346 &st->info.x, &st->info.y);
2348 st->info.radius = diam / 2;
2352 st->zoom_base = diam;
2353 return st->info.zoom;
2356 if (st->zoom_distance_tolerance)
2357 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2358 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2359 { /* avoid jump with zoom value when break tolerance */
2360 st->zoom_base -= st->zoom_distance_tolerance;
2361 st->zoom_distance_tolerance = 0;
2364 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2365 { /* avoid jump with zoom value when break tolerance */
2366 st->zoom_base += st->zoom_distance_tolerance;
2367 st->zoom_distance_tolerance = 0;
2373 /* We use factor only on the difference between gap-base */
2374 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2375 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2376 (float) st->zoom_base) * zoom_finger_factor));
2379 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2380 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2391 * This function handles zoom with mouse wheel.
2392 * thats a combination of wheel + CTRL key.
2393 * @param obj The gesture-layer object.
2394 * @param event_info Original input event pointer.
2395 * @param event_type Type of original input event.
2396 * @param g_type what Gesture we are testing.
2398 * @ingroup Elm_Gesture_Layer
2401 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2402 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2404 Widget_Data *wd = elm_widget_data_get(obj);
2406 if (!wd->gesture[g_type]) return;
2408 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2409 Zoom_Type *st = gesture_zoom->data;
2410 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2412 { /* Allocated once on first time, used for zoom intermediate data */
2413 st = calloc(1, sizeof(Zoom_Type));
2414 gesture_zoom->data = st;
2415 _zoom_test_reset(gesture_zoom);
2420 case EVAS_CALLBACK_KEY_UP:
2422 Evas_Event_Key_Up *p = event_info;
2423 if ((!strcmp(p->keyname, "Control_L")) ||
2424 (!strcmp(p->keyname, "Control_R")))
2425 { /* Test if we ended a zoom gesture when releasing CTRL */
2426 if ((st->zoom_wheel) &&
2427 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2428 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2429 { /* User released CTRL after zooming */
2430 ev_flag = _set_state(gesture_zoom,
2431 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2432 consume_event(wd, event_info, event_type, ev_flag);
2440 case EVAS_CALLBACK_MOUSE_WHEEL:
2443 Elm_Gesture_State s;
2444 if (!evas_key_modifier_is_set(
2445 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2447 { /* if using wheel witout CTRL after starting zoom */
2448 if ((st->zoom_wheel) &&
2449 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2450 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2452 ev_flag = _set_state(gesture_zoom,
2453 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2454 consume_event(wd, event_info, event_type, ev_flag);
2459 return; /* Ignore mouse-wheel without control */
2462 /* Using mouse wheel with CTRL for zoom */
2463 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2464 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2465 we continue a zoom gesture */
2467 s = ELM_GESTURE_STATE_MOVE;
2470 { /* On first wheel event, report START */
2471 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2472 evas_object_evas_get(wd->target), "Control");
2474 s = ELM_GESTURE_STATE_START;
2475 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2476 ERR("Failed to Grabbed CTRL_L");
2477 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2478 ERR("Failed to Grabbed CTRL_R");
2481 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2482 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2483 st->info.x = st->zoom_wheel->canvas.x;
2484 st->info.y = st->zoom_wheel->canvas.y;
2486 if (st->zoom_wheel->z < 0) /* zoom in */
2487 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2489 if (st->zoom_wheel->z > 0) /* zoom out */
2490 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2492 if (st->info.zoom < 0.0)
2493 st->info.zoom = 0.0;
2495 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2496 consume_event(wd, event_info, event_type, ev_flag);
2508 * This function is used to test zoom gesture.
2509 * user may combine zoom, rotation together.
2510 * so its possible that both will be detected from input.
2511 * (both are two-finger movement-oriented gestures)
2513 * @param obj The gesture-layer object.
2514 * @param event_info Pointer to recent input event.
2515 * @param event_type Recent input event type.
2516 * @param g_type what Gesture we are testing.
2518 * @ingroup Elm_Gesture_Layer
2521 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2522 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2526 Widget_Data *wd = elm_widget_data_get(obj);
2528 if (!wd->gesture[g_type]) return;
2530 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2531 Zoom_Type *st = gesture_zoom->data;
2534 { /* Allocated once on first time, used for zoom data */
2535 st = calloc(1, sizeof(Zoom_Type));
2536 gesture_zoom->data = st;
2537 _zoom_test_reset(gesture_zoom);
2541 /* Start - new zoom testing, letting all fingers start */
2542 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2545 case EVAS_CALLBACK_MOUSE_MOVE:
2546 case EVAS_CALLBACK_MULTI_MOVE:
2547 /* if non-continues mode and gesture NOT started, ignore MOVE */
2548 if ((!wd->glayer_continues_enable) &&
2549 (!st->zoom_st.timestamp))
2552 case EVAS_CALLBACK_MOUSE_DOWN:
2553 case EVAS_CALLBACK_MULTI_DOWN:
2554 { /* Here we take care of zoom-start and zoom move */
2558 if(eina_list_count(wd->touched) > 2)
2559 { /* Process zoom only when 2 fingers on surface */
2560 ev_flag = _set_state(gesture_zoom,
2561 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2562 consume_event(wd, event_info, event_type, ev_flag);
2567 if (!st->zoom_st.timestamp)
2568 { /* Now scan touched-devices list and find other finger */
2569 EINA_LIST_FOREACH(wd->touched, l, p)
2570 { /* Device of other finger <> pe device */
2571 if (p->device != pe->device)
2575 if (!p) /* Single finger on touch */
2578 /* Record down fingers */
2579 consume_event(wd, event_info, event_type, ev_flag);
2580 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2581 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2583 /* Set mv field as well to be ready for MOVE events */
2584 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2585 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2587 /* Here we have zoom_st, zoom_st1 set, report START */
2588 /* Set zoom-base after BOTH down events recorded */
2589 /* Compute length of line between fingers zoom start */
2590 st->info.zoom = 1.0;
2591 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2592 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2593 &st->info.x, &st->info.y);
2595 st->info.radius = st->zoom_base / 2;
2597 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2598 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2599 { /* zoom started with mouse-wheel, don't report twice */
2600 ev_flag = _set_state(gesture_zoom,
2601 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2602 consume_event(wd, event_info, event_type, ev_flag);
2605 return; /* Zoom started */
2606 } /* End of ZOOM_START handling */
2609 /* if we got here, we have (exacally) two fingers on surfce */
2610 /* we also after START, report MOVE */
2611 /* First detect which finger moved */
2612 if (pe->device == st->zoom_mv.device)
2613 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2614 else if (pe->device == st->zoom_mv1.device)
2615 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2617 /* Compute change in zoom as fingers move */
2618 st->info.zoom = compute_zoom(st,
2619 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2620 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2621 wd->zoom_finger_factor);
2623 if (!st->zoom_distance_tolerance)
2624 { /* Zoom broke tolerance, report move */
2625 double d = st->info.zoom - st->next_step;
2629 if (d >= wd->zoom_step)
2630 { /* Report move in steps */
2631 st->next_step = st->info.zoom;
2633 ev_flag = _set_state(gesture_zoom,
2634 ELM_GESTURE_STATE_MOVE,
2635 &st->info, EINA_TRUE);
2636 consume_event(wd, event_info, event_type, ev_flag);
2638 } /* End of ZOOM_MOVE handling */
2643 case EVAS_CALLBACK_MOUSE_UP:
2644 case EVAS_CALLBACK_MULTI_UP:
2645 /* Reset timestamp of finger-up.This is used later
2646 by _zoom_test_reset() to retain finger-down data */
2647 consume_event(wd, event_info, event_type, ev_flag);
2648 if (((st->zoom_wheel) || (st->zoom_base)) &&
2649 (st->zoom_distance_tolerance == 0))
2651 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2652 &st->info, EINA_FALSE);
2653 consume_event(wd, event_info, event_type, ev_flag);
2658 /* if we got here not a ZOOM */
2659 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2660 { /* Must be != undefined, if gesture started */
2661 ev_flag = _set_state(gesture_zoom,
2662 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2663 consume_event(wd, event_info, event_type, ev_flag);
2666 _zoom_test_reset(gesture_zoom);
2676 _get_rotate_properties(Rotate_Type *st,
2677 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2678 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2681 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2682 &st->info.x, &st->info.y) / 2;
2684 *angle = get_angle(x1, y1, x2, y2);
2685 #if 0 /* (NOT YET SUPPORTED) */
2686 if (angle == &st->info.angle)
2687 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2688 st->info.momentum = (((*angle) - st->info.base_angle) /
2689 (fabs(tm2 - tm1))) * 1000;
2692 st->info.momentum = 0;
2702 * This function is used to test rotation gesture.
2703 * user may combine zoom, rotation together.
2704 * so its possible that both will be detected from input.
2705 * (both are two-finger movement-oriented gestures)
2707 * @param obj The gesture-layer object.
2708 * @param event_info Pointer to recent input event.
2709 * @param event_type Recent input event type.
2710 * @param g_type what Gesture we are testing.
2712 * @ingroup Elm_Gesture_Layer
2715 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2716 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2721 Widget_Data *wd = elm_widget_data_get(obj);
2723 if (!wd->gesture[g_type]) return;
2725 Gesture_Info *gesture = wd->gesture[g_type];
2726 Rotate_Type *st = gesture->data;
2731 { /* Allocated once on first time */
2732 st = calloc(1, sizeof(Rotate_Type));
2734 _rotate_test_reset(gesture);
2738 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2741 case EVAS_CALLBACK_MOUSE_MOVE:
2742 case EVAS_CALLBACK_MULTI_MOVE:
2743 /* if non-continues mode and gesture NOT started, ignore MOVE */
2744 if ((!wd->glayer_continues_enable) &&
2745 (!st->rotate_st.timestamp))
2748 case EVAS_CALLBACK_MOUSE_DOWN:
2749 case EVAS_CALLBACK_MULTI_DOWN:
2750 { /* Here we take care of rotate-start and rotate move */
2754 if(eina_list_count(wd->touched) > 2)
2755 { /* Process rotate only when 2 fingers on surface */
2756 ev_flag = _set_state(gesture,
2757 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2758 consume_event(wd, event_info, event_type, ev_flag);
2763 if (!st->rotate_st.timestamp)
2764 { /* Now scan touched-devices list and find other finger */
2765 EINA_LIST_FOREACH(wd->touched, l, p)
2766 { /* Device of other finger <> pe device */
2767 if (p->device != pe->device)
2772 return; /* Single finger on touch */
2774 /* Record down fingers */
2775 consume_event(wd, event_info, event_type, ev_flag);
2776 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2777 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2779 /* Set mv field as well to be ready for MOVE events */
2780 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2781 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2783 /* Here we have rotate_st, rotate_st1 set, report START */
2784 /* Set rotate-base after BOTH down events recorded */
2785 /* Compute length of line between fingers rotate start */
2786 _get_rotate_properties(st,
2787 st->rotate_st.x, st->rotate_st.y,
2788 st->rotate_st.timestamp,
2789 st->rotate_st1.x, st->rotate_st1.y,
2790 st->rotate_st1.timestamp, &st->info.base_angle);
2792 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2793 &st->info, EINA_FALSE);
2794 consume_event(wd, event_info, event_type, ev_flag);
2796 return; /* Rotate started */
2797 } /* End of ROTATE_START handling */
2800 /* if we got here, we have (exacally) two fingers on surfce */
2801 /* we also after START, report MOVE */
2802 /* First detect which finger moved */
2803 if (pe->device == st->rotate_mv.device)
2804 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2805 else if (pe->device == st->rotate_mv1.device)
2806 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2808 /* Compute change in rotate as fingers move */
2809 _get_rotate_properties(st,
2810 st->rotate_mv.x, st->rotate_mv.y,
2811 st->rotate_mv.timestamp,
2812 st->rotate_mv1.x, st->rotate_mv1.y,
2813 st->rotate_mv1.timestamp, &st->info.angle);
2815 if (rotation_broke_tolerance(st))
2816 { /* Rotation broke tolerance, report move */
2817 double d = st->info.angle - st->next_step;
2821 if (d >= wd->rotate_step)
2822 { /* Report move in steps */
2823 st->next_step = st->info.angle;
2825 ev_flag = _set_state(gesture,
2826 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2827 consume_event(wd, event_info, event_type, ev_flag);
2829 } /* End of ROTATE_MOVE handling */
2834 case EVAS_CALLBACK_MOUSE_UP:
2835 case EVAS_CALLBACK_MULTI_UP:
2836 consume_event(wd, event_info, event_type, ev_flag);
2837 /* Reset timestamp of finger-up.This is used later
2838 by rotate_test_reset() to retain finger-down data */
2839 if (st->rotate_angular_tolerance < 0)
2841 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2842 &st->info, EINA_FALSE);
2843 consume_event(wd, event_info, event_type, ev_flag);
2848 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2849 { /* Must be != undefined, if gesture started */
2850 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2851 &st->info, EINA_FALSE);
2852 consume_event(wd, event_info, event_type, ev_flag);
2855 _rotate_test_reset(gesture);
2866 * This function is used to save input events in an abstract struct
2867 * to be used later by getsure-testing functions.
2869 * @param data The gesture-layer object.
2870 * @param event_info Pointer to recent input event.
2871 * @param event_type Recent input event type.
2872 * @param pe The abstract data-struct (output).
2874 * @ingroup Elm_Gesture_Layer
2877 _make_pointer_event(void *data, void *event_info,
2878 Evas_Callback_Type event_type, Pointer_Event *pe)
2880 Widget_Data *wd = elm_widget_data_get(data);
2881 if (!wd) return EINA_FALSE;
2883 memset(pe, '\0', sizeof(*pe));
2886 case EVAS_CALLBACK_MOUSE_DOWN:
2887 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2888 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2889 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2890 pe->device = ELM_MOUSE_DEVICE;
2893 case EVAS_CALLBACK_MOUSE_UP:
2894 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2895 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2896 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2897 pe->device = ELM_MOUSE_DEVICE;
2900 case EVAS_CALLBACK_MOUSE_MOVE:
2901 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2902 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2903 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2904 pe->device = ELM_MOUSE_DEVICE;
2907 case EVAS_CALLBACK_MULTI_DOWN:
2908 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2909 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2910 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2911 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2914 case EVAS_CALLBACK_MULTI_UP:
2915 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2916 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2917 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2918 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2921 case EVAS_CALLBACK_MULTI_MOVE:
2922 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2923 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2924 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2925 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2932 pe->event_type = event_type;
2939 * This function restartes line, flick, zoom and rotate gestures
2940 * when gesture-layer continues-gestures enabled.
2941 * Example of continues-gesture:
2942 * When doing a line, user stops moving finger but keeps fingers on touch.
2943 * This will cause line-end, then as user continues moving his finger
2944 * it re-starts line gesture.
2945 * When continue mode is disabled, user has to lift finger from touch
2946 * to end a gesture. Them touch-again to start a new one.
2948 * @param data The gesture-layer object.
2949 * @param wd gesture layer widget data.
2950 * @param states_reset flag that marks gestures were reset in history clear.
2952 * @ingroup Elm_Gesture_Layer
2954 void continues_gestures_restart(void *data, Eina_Bool states_reset)
2956 Widget_Data *wd = elm_widget_data_get(data);
2959 /* Run through events to restart gestures */
2961 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
2962 /* We turn-on flag for finished, aborted, not-started gestures */
2963 g = wd->gesture[ELM_GESTURE_MOMENTUM];
2964 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2965 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2968 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
2969 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2973 g = wd->gesture[ELM_GESTURE_N_LINES];
2974 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2975 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2978 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
2979 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2983 g = wd->gesture[ELM_GESTURE_N_FLICKS];
2984 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2985 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2988 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
2989 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2993 g = wd->gesture[ELM_GESTURE_ZOOM];
2994 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2995 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2998 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
2999 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3003 g = wd->gesture[ELM_GESTURE_ROTATE];
3004 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3005 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3008 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3009 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3017 * This function the core-function where input handling is done.
3018 * Here we get user input and stream it to gesture testing.
3019 * We notify user about any gestures with new state:
3021 * START - gesture started.
3022 * MOVE - gesture is ongoing.
3023 * END - gesture was completed.
3024 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3026 * We also check if a gesture was detected, then reset event history
3027 * If no gestures were found we reset gesture test flag
3028 * after streaming event-history to widget.
3029 * (stream to the widget all events not consumed as a gesture)
3031 * @param data The gesture-layer object.
3032 * @param event_info Pointer to recent input event.
3033 * @param event_type Recent input event type.
3035 * @ingroup Elm_Gesture_Layer
3038 _event_process(void *data, Evas_Object *obj __UNUSED__,
3039 void *event_info, Evas_Callback_Type event_type)
3042 Pointer_Event *pe = NULL;
3043 Widget_Data *wd = elm_widget_data_get(data);
3046 #if defined(DEBUG_GESTURE_LAYER)
3049 printf("Gesture | State | is tested\n");
3050 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3054 printf(" %d %d %d\n", i, g->state, g->test);
3058 /* Start testing candidate gesture from here */
3059 if (_make_pointer_event(data, event_info, event_type, &_pe))
3062 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3063 _n_long_tap_test(data, pe, event_info, event_type,
3064 ELM_GESTURE_N_LONG_TAPS);
3066 /* This takes care of single, double and tripple tap */
3067 _tap_gestures_test(data, pe, event_info, event_type);
3069 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3070 _momentum_test(data, pe, event_info, event_type,
3071 ELM_GESTURE_MOMENTUM);
3073 if (IS_TESTED(ELM_GESTURE_N_LINES))
3074 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3076 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3077 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3079 if (IS_TESTED(ELM_GESTURE_ZOOM))
3080 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3082 if (IS_TESTED(ELM_GESTURE_ZOOM))
3083 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3085 if (IS_TESTED(ELM_GESTURE_ROTATE))
3086 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3088 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3089 _event_history_add(data, event_info, event_type);
3090 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3091 (event_type == EVAS_CALLBACK_MULTI_UP))
3093 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3096 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3097 _event_history_add(data, event_info, event_type);
3101 /* we maintain list of touched devices */
3102 /* We also use move to track current device x.y pos */
3103 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3104 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3105 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3106 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3108 wd->touched = _add_touched_device(wd->touched, pe);
3110 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3111 (event_type == EVAS_CALLBACK_MULTI_UP))
3113 wd->touched = _remove_touched_device(wd->touched, pe);
3116 /* Report current states and clear history if needed */
3117 Eina_Bool states_reset = _clear_if_finished(data);
3118 if (wd->glayer_continues_enable)
3119 continues_gestures_restart(data, states_reset);
3124 * For all _mouse_* / multi_* functions wethen send this event to
3125 * _event_process function.
3127 * @param data The gesture-layer object.
3128 * @param event_info Pointer to recent input event.
3130 * @ingroup Elm_Gesture_Layer
3133 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3136 Widget_Data *wd = elm_widget_data_get(data);
3138 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3139 return; /* We only process left-click at the moment */
3141 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3145 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3148 Widget_Data *wd = elm_widget_data_get(data);
3151 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3155 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3158 Widget_Data *wd = elm_widget_data_get(data);
3161 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3165 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3168 Widget_Data *wd = elm_widget_data_get(data);
3171 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3175 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3178 Widget_Data *wd = elm_widget_data_get(data);
3181 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3182 return; /* We only process left-click at the moment */
3184 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3188 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3191 Widget_Data *wd = elm_widget_data_get(data);
3194 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3198 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3201 Widget_Data *wd = elm_widget_data_get(data);
3204 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3208 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3211 Widget_Data *wd = elm_widget_data_get(data);
3214 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3218 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3221 Widget_Data *wd = elm_widget_data_get(data);
3224 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3228 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3230 Widget_Data *wd = elm_widget_data_get(obj);
3231 if (!wd) return EINA_FALSE;
3233 return !wd->repeat_events;
3237 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3239 Widget_Data *wd = elm_widget_data_get(obj);
3242 wd->repeat_events = !r;
3246 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3248 Widget_Data *wd = elm_widget_data_get(obj);
3258 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3260 Widget_Data *wd = elm_widget_data_get(obj);
3266 wd->rotate_step = s;
3270 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3272 Widget_Data *wd = elm_widget_data_get(obj);
3273 if (!wd) return EINA_FALSE;
3278 /* if was attached before, unregister callbacks first */
3280 _unregister_callbacks(obj);
3284 _register_callbacks(obj);
3289 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3290 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3292 Widget_Data *wd = elm_widget_data_get(obj);
3296 if (!wd->gesture[idx])
3297 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3298 if (!wd->gesture[idx]) return;
3300 p = wd->gesture[idx];
3303 p->fn[cb_type].cb = cb;
3304 p->fn[cb_type].user_data = data;
3305 p->state = ELM_GESTURE_STATE_UNDEFINED;
3310 _disable_hook(Evas_Object *obj)
3312 if (elm_widget_disabled_get(obj))
3313 _unregister_callbacks(obj);
3315 _register_callbacks(obj);
3319 elm_gesture_layer_add(Evas_Object *parent)
3325 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3327 wd = ELM_NEW(Widget_Data);
3328 e = evas_object_evas_get(parent);
3329 if (!e) return NULL;
3330 obj = elm_widget_add(e);
3331 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3332 elm_widget_type_set(obj, "gesture_layer");
3333 elm_widget_sub_object_add(parent, obj);
3334 elm_widget_data_set(obj, wd);
3335 elm_widget_del_hook_set(obj, _del_hook);
3336 elm_widget_disable_hook_set(obj, _disable_hook);
3339 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3340 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3341 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3342 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3343 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3344 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3345 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3346 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3347 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3348 wd->repeat_events = EINA_TRUE;
3349 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3351 #if defined(DEBUG_GESTURE_LAYER)
3352 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3353 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);
3355 memset(wd->gesture, 0, sizeof(wd->gesture));