1 #include <Elementary.h>
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
10 #define ELM_GESTURE_MULTI_TIMEOUT 50
12 /* Some Trigo values */
13 #define RAD_90DEG M_PI_2
14 #define RAD_180DEG M_PI
15 #define RAD_270DEG (M_PI_2 * 3)
16 #define RAD_360DEG (M_PI * 2)
17 /* #define DEBUG_GESTURE_LAYER 1 */
20 _glayer_bufdup(void *buf, size_t size)
27 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
30 #define SET_TEST_BIT(P) do { \
31 P->test = P->fn[ELM_GESTURE_STATE_START].cb || P->fn[ELM_GESTURE_STATE_MOVE].cb || P->fn[ELM_GESTURE_STATE_END].cb || P->fn[ELM_GESTURE_STATE_ABORT].cb; \
34 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
40 * Struct holds callback information.
42 * @ingroup Elm_Gesture_Layer
46 void *user_data; /**< Holds user data to CB (like sd) */
47 Elm_Gesture_Event_Cb cb;
54 * type for callback information
56 * @ingroup Elm_Gesture_Layer
58 typedef struct _Func_Data Func_Data;
63 * @struct _Gesture_Info
64 * Struct holds gesture info
66 * @ingroup Elm_Gesture_Layer
71 void *data; /**< Holds gesture intemidiate processing data */
72 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
73 Elm_Gesture_Types g_type; /**< gesture type */
74 Elm_Gesture_State state; /**< gesture state */
75 void *info; /**< Data for the state callback */
76 Eina_Bool test; /**< if true this gesture should be tested on input */
82 * @typedef Gesture_Info
83 * Type for _Gesture_Info
85 * @ingroup Elm_Gesture_Layer
87 typedef struct _Gesture_Info Gesture_Info;
92 * @struct _Event_History
93 * Struct holds event history.
94 * These events are repeated if no gesture found.
96 * @ingroup Elm_Gesture_Layer
102 Evas_Callback_Type event_type;
108 * @typedef Event_History
109 * Type for _Event_History
111 * @ingroup Elm_Gesture_Layer
113 typedef struct _Event_History Event_History;
118 * @struct _Pointer_Event
119 * Struct holds pointer-event info
120 * This is a generic pointer event structure
122 * @ingroup Elm_Gesture_Layer
124 struct _Pointer_Event
127 unsigned int timestamp;
129 Evas_Callback_Type event_type;
135 * @typedef Pointer_Event
136 * Type for generic pointer event structure
138 * @ingroup Elm_Gesture_Layer
140 typedef struct _Pointer_Event Pointer_Event;
142 /* All *Type structs hold result for the user in 'info' field
143 * The rest is gesture processing intermediate data.
144 * NOTE: info field must be FIRST in the struct.
145 * This is used when reporting ABORT in event_history_clear() */
148 Elm_Gesture_Taps_Info info;
151 unsigned int n_taps_needed;
155 typedef struct _Taps_Type Taps_Type;
157 struct _Long_Tap_Type
159 Elm_Gesture_Taps_Info info;
162 unsigned int max_touched;
163 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
166 typedef struct _Long_Tap_Type Long_Tap_Type;
168 struct _Momentum_Type
169 { /* Fields used by _line_test() */
170 Elm_Gesture_Momentum_Info info;
171 Evas_Coord_Point line_st;
172 Evas_Coord_Point line_end;
173 unsigned int t_st_x; /* Time start on X */
174 unsigned int t_st_y; /* Time start on Y */
175 unsigned int t_end; /* Time end */
176 unsigned int t_up; /* Recent up event time */
180 typedef struct _Momentum_Type Momentum_Type;
184 Evas_Coord_Point line_st;
185 Evas_Coord_Point line_end;
186 Evas_Coord line_length;
187 unsigned int t_st; /* Time start */
188 unsigned int t_end; /* Time end */
190 double line_angle; /* Current angle of line */
192 typedef struct _Line_Data Line_Data;
195 { /* Fields used by _line_test() */
196 Elm_Gesture_Line_Info info;
197 Eina_List *list; /* List of Line_Data */
199 typedef struct _Line_Type Line_Type;
202 { /* Fields used by _zoom_test() */
203 Elm_Gesture_Zoom_Info info;
204 Pointer_Event zoom_st;
205 Pointer_Event zoom_mv;
206 Pointer_Event zoom_st1;
207 Pointer_Event zoom_mv1;
208 Evas_Event_Mouse_Wheel *zoom_wheel;
209 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
210 Evas_Coord zoom_distance_tolerance;
211 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
212 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
215 typedef struct _Zoom_Type Zoom_Type;
218 { /* Fields used by _rotation_test() */
219 Elm_Gesture_Rotate_Info info;
220 Pointer_Event rotate_st;
221 Pointer_Event rotate_mv;
222 Pointer_Event rotate_st1;
223 Pointer_Event rotate_mv1;
224 double rotate_angular_tolerance;
226 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
227 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
229 typedef struct _Rotate_Type Rotate_Type;
233 Evas_Object *target; /* Target Widget */
234 Event_History *event_history_list;
237 Evas_Coord zoom_distance_tolerance;
238 Evas_Coord line_distance_tolerance;
239 double line_angular_tolerance;
240 double zoom_wheel_factor; /* mouse wheel zoom steps */
241 double zoom_finger_factor; /* used for zoom factor */
242 double rotate_angular_tolerance;
243 unsigned int flick_time_limit_ms;
244 double long_tap_start_timeout;
245 Eina_Bool glayer_continues_enable;
250 Gesture_Info *gesture[ELM_GESTURE_LAST];
251 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
252 Eina_List *pending; /* List of devices need to refeed *UP event */
253 Eina_List *touched; /* Information of touched devices */
255 Eina_Bool repeat_events : 1;
257 typedef struct _Widget_Data Widget_Data;
259 static const char *widtype = NULL;
260 static void _del_hook(Evas_Object *obj);
262 static Eina_Bool _event_history_clear(Evas_Object *obj);
263 static void _reset_states(Widget_Data *wd);
264 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
265 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
266 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
267 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
268 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
269 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
270 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
272 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
273 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
274 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
276 /* START - Functions to manage touched-device list */
279 * This function is used to find if device is touched
281 * @ingroup Elm_Gesture_Layer
284 compare_device(const void *data1, const void *data2)
285 { /* Compare the two device numbers */
286 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
292 * Remove Pointer Event from touched device list
293 * @param list Pointer to touched device list.
294 * @param Pointer_Event Pointer to PE.
296 * @ingroup Elm_Gesture_Layer
299 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
301 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
305 return eina_list_remove(list, p);
314 * Recoed Pointer Event in touched device list
315 * Note: This fuction allocates memory for PE event
316 * This memory is released in _remove_touched_device()
317 * @param list Pointer to touched device list.
318 * @param Pointer_Event Pointer to PE.
320 * @ingroup Elm_Gesture_Layer
323 _add_touched_device(Eina_List *list, Pointer_Event *pe)
325 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
327 { /* We like to track device touch-position, overwrite info */
328 memcpy(p, pe, sizeof(Pointer_Event));
332 p = malloc(sizeof(Pointer_Event));
333 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
334 return eina_list_append(list, p);
336 /* END - Functions to manage touched-device list */
342 * @param event_info pointer to event.
344 * @ingroup Elm_Gesture_Layer
346 static Evas_Event_Flags
347 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
351 case EVAS_CALLBACK_MOUSE_IN:
352 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
353 case EVAS_CALLBACK_MOUSE_OUT:
354 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
355 case EVAS_CALLBACK_MOUSE_DOWN:
356 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
357 case EVAS_CALLBACK_MOUSE_MOVE:
358 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
359 case EVAS_CALLBACK_MOUSE_UP:
360 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
361 case EVAS_CALLBACK_MOUSE_WHEEL:
362 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
363 case EVAS_CALLBACK_MULTI_DOWN:
364 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
365 case EVAS_CALLBACK_MULTI_MOVE:
366 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
367 case EVAS_CALLBACK_MULTI_UP:
368 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
369 case EVAS_CALLBACK_KEY_DOWN:
370 return ((Evas_Event_Key_Down *) event_info)->event_flags;
371 case EVAS_CALLBACK_KEY_UP:
372 return ((Evas_Event_Key_Up *) event_info)->event_flags;
374 return EVAS_EVENT_FLAG_NONE;
381 * Sets event flag to value returned from user callback
382 * @param wd Widget Data
383 * @param event_info pointer to event.
384 * @param event_type what type was ev (mouse down, etc...)
385 * @param ev_flags event flags
387 * @ingroup Elm_Gesture_Layer
390 consume_event(Widget_Data *wd, void *event_info,
391 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
392 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
393 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
394 /* should not refeed this event. */
396 return; /* This happens when restarting gestures */
398 if ((ev_flags) || (!wd->repeat_events))
402 case EVAS_CALLBACK_MOUSE_DOWN:
403 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
405 case EVAS_CALLBACK_MOUSE_MOVE:
406 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
408 case EVAS_CALLBACK_MOUSE_UP:
409 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
411 case EVAS_CALLBACK_MOUSE_WHEEL:
412 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
414 case EVAS_CALLBACK_MULTI_DOWN:
415 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
417 case EVAS_CALLBACK_MULTI_MOVE:
418 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
420 case EVAS_CALLBACK_MULTI_UP:
421 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
423 case EVAS_CALLBACK_KEY_DOWN:
424 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
426 case EVAS_CALLBACK_KEY_UP:
427 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
438 * Report current state of a gesture by calling user callback.
439 * @param gesture what gesture state we report.
440 * @param info inforamtion for user callback
442 * @ingroup Elm_Gesture_Layer
444 static Evas_Event_Flags
445 _report_state(Gesture_Info *gesture, void *info)
446 { /* We report current state (START, MOVE, END, ABORT), once */
447 #if defined(DEBUG_GESTURE_LAYER)
448 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
451 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
452 (gesture->fn[gesture->state].cb))
453 { /* Fill state-info struct and send ptr to user callback */
454 return gesture->fn[gesture->state].cb(
455 gesture->fn[gesture->state].user_data, info);
458 return EVAS_EVENT_FLAG_NONE;
464 * Update state for a given gesture.
465 * We may update gesture state to:
466 * UNDEFINED - current input did not start gesure yet.
467 * START - gesture started according to input.
468 * MOVE - gusture in progress.
469 * END - gesture completed according to input.
470 * ABORT - input does not matches gesure.
471 * note that we may move from UNDEFINED to ABORT
472 * because we may detect that gesture will not START
473 * with a given input.
475 * @param g given gesture to change state.
476 * @param s gesure new state.
477 * @param info buffer to be sent to user callback on report_state.
478 * @param force makes report_state to report the new-state even
479 * if its same as current state. Works for MOVE - gesture in progress.
481 * @ingroup Elm_Gesture_Layer
483 static Evas_Event_Flags
484 _set_state(Gesture_Info *g, Elm_Gesture_State s,
485 void *info, Eina_Bool force)
487 Elm_Gesture_State old_state;
488 if ((g->state == s) && (!force))
489 return EVAS_EVENT_FLAG_NONE;
491 old_state = g->state;
494 g->info = info; /* Information for user callback */
495 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
496 (g->state == ELM_GESTURE_STATE_END))
497 g->test = EINA_FALSE;
499 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
500 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
501 (s == ELM_GESTURE_STATE_ABORT))))
502 return _report_state(g, g->info);
504 return EVAS_EVENT_FLAG_NONE;
510 * This resets all gesture states and sets test-bit.
511 * this is used for restarting gestures to listen to input.
512 * happens after we complete a gesture or no gesture was detected.
513 * @param wd Widget data of the gesture-layer object.
515 * @ingroup Elm_Gesture_Layer
518 _reset_states(Widget_Data *wd)
522 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
527 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
536 * if gesture was NOT detected AND we only have gestures in ABORT state
537 * we clear history immediately to be ready for input.
539 * @param obj The gesture-layer object.
540 * @return TRUE on event history_clear
542 * @ingroup Elm_Gesture_Layer
545 _clear_if_finished(Evas_Object *obj)
547 Widget_Data *wd = elm_widget_data_get(obj);
548 if (!wd) return EINA_FALSE;
551 /* Clear history if all we have aborted gestures */
552 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
553 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
554 { /* If no gesture started and all we have aborted gestures, reset all */
555 Gesture_Info *p = wd->gesture[i];
556 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
558 if ((p->state == ELM_GESTURE_STATE_START) ||
559 (p->state == ELM_GESTURE_STATE_MOVE))
560 reset_s = EINA_FALSE;
562 all_undefined = EINA_FALSE;
566 if (reset_s && (!all_undefined))
567 return _event_history_clear(obj);
573 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
575 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
591 /* All *test_reset() funcs are called to clear
592 * gesture intermediate data.
593 * This happens when we need to reset our tests.
594 * for example when gesture is detected or all ABORTed. */
596 _tap_gestures_test_reset(Gesture_Info *gesture)
601 Widget_Data *wd = elm_widget_data_get(gesture->obj);
602 wd->dbl_timeout = NULL;
609 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
610 EINA_LIST_FREE(data, pe)
613 memset(gesture->data, 0, sizeof(Taps_Type));
616 /* All *test_reset() funcs are called to clear
617 * gesture intermediate data.
618 * This happens when we need to reset our tests.
619 * for example when gesture is detected or all ABORTed. */
621 _n_long_tap_test_reset(Gesture_Info *gesture)
629 Long_Tap_Type *st = gesture->data;
632 EINA_LIST_FOREACH(st->touched, l, p)
635 eina_list_free(st->touched);
636 if (st->timeout) ecore_timer_del(st->timeout);
637 memset(gesture->data, 0, sizeof(Long_Tap_Type));
641 _momentum_test_reset(Gesture_Info *gesture)
649 memset(gesture->data, 0, sizeof(Momentum_Type));
653 _line_data_reset(Line_Data *st)
658 memset(st, 0, sizeof(Line_Data));
659 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
663 _line_test_reset(Gesture_Info *gesture)
671 Line_Type *st = gesture->data;
672 Eina_List *list = st->list;
675 EINA_LIST_FOREACH(list, l, t_line)
678 eina_list_free(list);
683 _zoom_test_reset(Gesture_Info *gesture)
691 Widget_Data *wd = elm_widget_data_get(gesture->obj);
692 Zoom_Type *st = gesture->data;
693 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
694 evas_object_evas_get(wd->target), "Control");
695 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
696 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
698 memset(st, 0, sizeof(Zoom_Type));
699 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
704 _rotate_test_reset(Gesture_Info *gesture)
712 Widget_Data *wd = elm_widget_data_get(gesture->obj);
713 Rotate_Type *st = gesture->data;
715 memset(st, 0, sizeof(Rotate_Type));
716 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
717 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
724 * We register callbacks when gesture layer is attached to an object
725 * or when its enabled after disable.
727 * @param obj The gesture-layer object.
729 * @ingroup Elm_Gesture_Layer
732 _register_callbacks(Evas_Object *obj)
734 Widget_Data *wd = elm_widget_data_get(obj);
739 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
741 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
743 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
746 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
749 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
751 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
753 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
756 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
758 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
766 * We unregister callbacks when gesture layer is disabled.
768 * @param obj The gesture-layer object.
770 * @ingroup Elm_Gesture_Layer
773 _unregister_callbacks(Evas_Object *obj)
775 Widget_Data *wd = elm_widget_data_get(obj);
780 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
782 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
784 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
787 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
790 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
793 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
796 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
799 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
801 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
806 /* START - Event history list handling functions */
809 * This function is used to find if device number
810 * is found in a list of devices.
811 * The list contains devices for refeeding *UP event
813 * @ingroup Elm_Gesture_Layer
816 device_in_pending_list(const void *data1, const void *data2)
817 { /* Compare the two device numbers */
818 return (((intptr_t) data1) - ((intptr_t) data2));
824 * This functions adds device to refeed-pending device list
825 * @ingroup Elm_Gesture_Layer
828 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
830 int device = ELM_MOUSE_DEVICE;
833 case EVAS_CALLBACK_MOUSE_DOWN:
835 case EVAS_CALLBACK_MULTI_DOWN:
836 device = ((Evas_Event_Multi_Down *) event)->device;
842 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
845 return eina_list_append(list, (intptr_t*) device);
854 * This functions returns pending-device node
855 * @ingroup Elm_Gesture_Layer
858 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
860 int device = ELM_MOUSE_DEVICE;
863 case EVAS_CALLBACK_MOUSE_UP:
865 case EVAS_CALLBACK_MULTI_UP:
866 device = ((Evas_Event_Multi_Up *) event)->device;
872 return eina_list_search_unsorted_list(list, device_in_pending_list,
873 (intptr_t *) device);
879 * This function reports ABORT to all none-detected gestures
880 * Then resets test bits for all desired gesures
881 * and clears input-events history.
882 * note: if no gesture was detected, events from history list
883 * are streamed to the widget because it's unused by layer.
884 * user may cancel refeed of events by setting repeat events.
886 * @param obj The gesture-layer object.
888 * @ingroup Elm_Gesture_Layer
891 _event_history_clear(Evas_Object *obj)
893 Widget_Data *wd = elm_widget_data_get(obj);
894 if (!wd) return EINA_FALSE;
898 Evas *e = evas_object_evas_get(obj);
899 Eina_Bool gesture_found = EINA_FALSE;
900 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
905 if (p->state == ELM_GESTURE_STATE_END)
906 gesture_found = EINA_TRUE;
908 { /* Report ABORT to all gestures that still not finished */
909 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
915 _reset_states(wd); /* we are ready to start testing for gestures again */
917 /* Clear all gestures intermediate data */
918 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
919 { /* We do not clear a long-tap gesture if fingers still on surface */
920 /* and gesture timer still pending to test gesture state */
921 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
922 if ((st) && /* st not allocated if clear occurs before 1st input */
923 ((!eina_list_count(st->touched)) || (!st->timeout)))
924 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
929 ecore_timer_del(wd->dbl_timeout);
930 wd->dbl_timeout = NULL;
933 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
934 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
935 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
936 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
937 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
938 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
939 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
940 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
942 /* Disable gesture layer so refeeded events won't be consumed by it */
943 _unregister_callbacks(obj);
944 while (wd->event_history_list)
947 t = wd->event_history_list;
948 Eina_List *pending = _device_is_pending(wd->pending,
949 wd->event_history_list->event,
950 wd->event_history_list->event_type);
952 /* Refeed events if no gesture matched input */
953 if (pending || ((!gesture_found) && (!wd->repeat_events)))
955 evas_event_refeed_event(e, wd->event_history_list->event,
956 wd->event_history_list->event_type);
960 wd->pending = eina_list_remove_list(wd->pending, pending);
964 wd->pending = _add_device_pending(wd->pending,
965 wd->event_history_list->event,
966 wd->event_history_list->event_type);
970 free(wd->event_history_list->event);
971 wd->event_history_list = (Event_History *) eina_inlist_remove(
972 EINA_INLIST_GET(wd->event_history_list),
973 EINA_INLIST_GET(wd->event_history_list));
976 _register_callbacks(obj);
983 * This function copies input events.
984 * We copy event info before adding it to history.
985 * The memory is freed when we clear history.
987 * @param event the event to copy
988 * @param event_type event type to copy
990 * @ingroup Elm_Gesture_Layer
993 _copy_event_info(void *event, Evas_Callback_Type event_type)
997 case EVAS_CALLBACK_MOUSE_DOWN:
998 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1000 case EVAS_CALLBACK_MOUSE_MOVE:
1001 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1003 case EVAS_CALLBACK_MOUSE_UP:
1004 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1006 case EVAS_CALLBACK_MOUSE_WHEEL:
1007 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1009 case EVAS_CALLBACK_MULTI_DOWN:
1010 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1012 case EVAS_CALLBACK_MULTI_MOVE:
1013 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1015 case EVAS_CALLBACK_MULTI_UP:
1016 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1018 case EVAS_CALLBACK_KEY_DOWN:
1019 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1021 case EVAS_CALLBACK_KEY_UP:
1022 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1030 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1032 Widget_Data *wd = elm_widget_data_get(obj);
1034 if (!wd) return EINA_FALSE;
1036 ev = malloc(sizeof(Event_History));
1037 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1038 ev->event_type = event_type;
1039 wd->event_history_list = (Event_History *) eina_inlist_append(
1040 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1044 /* END - Event history list handling functions */
1047 _del_hook(Evas_Object *obj)
1049 Widget_Data *wd = elm_widget_data_get(obj);
1052 _event_history_clear(obj);
1053 eina_list_free(wd->pending);
1055 Pointer_Event *data;
1056 EINA_LIST_FREE(wd->touched, data)
1059 if (!elm_widget_disabled_get(obj))
1060 _unregister_callbacks(obj);
1062 /* Free all gestures internal data structures */
1064 for (i = 0; i < ELM_GESTURE_LAST; i++)
1067 if (wd->gesture[i]->data)
1068 free(wd->gesture[i]->data);
1070 free(wd->gesture[i]);
1077 compare_match_fingers(const void *data1, const void *data2)
1078 { /* Compare coords of first item in list to cur coords */
1079 const Pointer_Event *pe1 = eina_list_data_get(data1);
1080 const Pointer_Event *pe2 = data2;
1082 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1084 else if (pe1->x < pe2->x)
1088 if (pe1->x == pe2->x)
1089 return pe1->y - pe2->y;
1096 compare_pe_device(const void *data1, const void *data2)
1097 { /* Compare coords of first item in list to cur coords */
1098 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1099 const Pointer_Event *pe2 = data2;
1101 /* Only match if last was a down event */
1102 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1103 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1107 if (pe1->device == pe2->device)
1109 else if (pe1->device < pe2->device)
1116 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1117 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1118 { /* Keep copy of pe and record it in list */
1119 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1120 memcpy(p, pe, sizeof(Pointer_Event));
1121 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1127 /* This will also update middle-point to report to user later */
1128 st->info.x = st->sum_x / st->n_taps;
1129 st->info.y = st->sum_y / st->n_taps;
1130 st->info.timestamp = pe->timestamp;
1134 pe_list = eina_list_append(pe_list, p);
1135 st->l = eina_list_append(st->l, pe_list);
1138 pe_list = eina_list_append(pe_list, p);
1146 * This function sets state a tap-gesture to END or ABORT
1148 * @param data gesture info pointer
1150 * @ingroup Elm_Gesture_Layer
1153 _tap_gesture_finish(void *data)
1154 { /* This function will test each tap gesture when timer expires */
1155 Gesture_Info *gesture = data;
1156 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1157 /* Here we check if taps-gesture was completed successfuly */
1158 /* Count how many taps were recieved on each device then */
1159 /* determine if it matches n_taps_needed defined on START */
1160 Taps_Type *st = gesture->data;
1163 EINA_LIST_FOREACH(st->l, l, pe_list)
1165 if (eina_list_count(pe_list) != st->n_taps_needed)
1166 { /* No match taps number on device, ABORT */
1167 s = ELM_GESTURE_STATE_ABORT;
1172 st->info.n = eina_list_count(st->l);
1173 _set_state(gesture, s, gesture->info, EINA_FALSE);
1174 _tap_gestures_test_reset(gesture);
1180 * when this timer expires we finish tap gestures.
1182 * @param data The gesture-layer object.
1183 * @return cancles callback for this timer.
1185 * @ingroup Elm_Gesture_Layer
1188 _multi_tap_timeout(void *data)
1190 Widget_Data *wd = elm_widget_data_get(data);
1191 if (!wd) return EINA_FALSE;
1193 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1194 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1196 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1197 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1199 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1200 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1202 _clear_if_finished(data);
1203 wd->dbl_timeout = NULL;
1204 return ECORE_CALLBACK_CANCEL;
1210 * when this timer expires we START long tap gesture
1212 * @param data The gesture-layer object.
1213 * @return cancles callback for this timer.
1215 * @ingroup Elm_Gesture_Layer
1218 _long_tap_timeout(void *data)
1220 Gesture_Info *gesture = data;
1221 Long_Tap_Type *st = gesture->data;
1224 _set_state(gesture, ELM_GESTURE_STATE_START,
1225 gesture->data, EINA_FALSE);
1227 return ECORE_CALLBACK_CANCEL;
1234 * This function checks if a tap gesture should start
1236 * @param wd Gesture Layer Widget Data.
1237 * @param pe The recent input event as stored in pe struct.
1238 * @param event_info Original input event pointer.
1239 * @param event_type Type of original input event.
1240 * @param gesture what gesture is tested
1241 * @param how many taps for this gesture (1, 2 or 3)
1243 * @return Flag to determine if we need to set a timer for finish
1245 * @ingroup Elm_Gesture_Layer
1248 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1249 void *event_info, Evas_Callback_Type event_type,
1250 Gesture_Info *gesture, int taps)
1251 { /* Here we fill Tap struct */
1252 Taps_Type *st = gesture->data;
1254 { /* Allocated once on first time */
1255 st = calloc(1, sizeof(Taps_Type));
1257 _tap_gestures_test_reset(gesture);
1260 Eina_List *pe_list = NULL;
1261 Pointer_Event *pe_down = NULL;
1262 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1263 switch (pe->event_type)
1265 case EVAS_CALLBACK_MULTI_DOWN:
1266 case EVAS_CALLBACK_MOUSE_DOWN:
1267 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1268 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1269 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1270 { /* This is the first mouse down we got */
1271 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1272 &st->info, EINA_FALSE);
1273 consume_event(wd, event_info, event_type, ev_flag);
1275 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1282 case EVAS_CALLBACK_MULTI_UP:
1283 case EVAS_CALLBACK_MOUSE_UP:
1284 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1288 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1291 case EVAS_CALLBACK_MULTI_MOVE:
1292 case EVAS_CALLBACK_MOUSE_MOVE:
1293 /* Get first event in first list, this has to be a Mouse Down event */
1294 /* and verify that user didn't move out of this area before next tap */
1295 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1298 pe_down = eina_list_data_get(pe_list);
1299 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1301 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1302 &st->info, EINA_FALSE);
1303 consume_event(wd, event_info, event_type, ev_flag);
1319 * This function checks all click/tap and double/triple taps
1321 * @param obj The gesture-layer object.
1322 * @param pe The recent input event as stored in pe struct.
1323 * @param event_info Original input event pointer.
1324 * @param event_type Type of original input event.
1326 * @ingroup Elm_Gesture_Layer
1329 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1330 void *event_info, Evas_Callback_Type event_type)
1331 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1332 Eina_Bool need_timer = EINA_FALSE;
1333 Widget_Data *wd = elm_widget_data_get(obj);
1336 if (!pe) /* this happens when unhandled event arrived */
1337 return; /* see _make_pointer_event function */
1339 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1340 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1341 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1343 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1344 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1345 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1347 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1348 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1349 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1351 if ((need_timer) && (!wd->dbl_timeout))
1352 { /* Set a timer to finish these gestures */
1353 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1361 * This function computes center-point for long-tap gesture
1363 * @param st Long Tap gesture info pointer
1364 * @param pe The recent input event as stored in pe struct.
1366 * @ingroup Elm_Gesture_Layer
1369 _compute_taps_center(Long_Tap_Type *st,
1370 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1372 if(!eina_list_count(st->touched))
1377 Evas_Coord x = 0, y = 0;
1378 EINA_LIST_FOREACH(st->touched, l, p)
1379 { /* Accumulate all then take avarage */
1380 if (p->device == pe->device)
1381 { /* This will take care of values coming from MOVE event */
1392 *x_out = x / eina_list_count(st->touched);
1393 *y_out = y / eina_list_count(st->touched);
1399 * This function checks N long-tap gesture.
1401 * @param obj The gesture-layer object.
1402 * @param pe The recent input event as stored in pe struct.
1403 * @param event_info Original input event pointer.
1404 * @param event_type Type of original input event.
1405 * @param g_type what Gesture we are testing.
1406 * @param taps How many click/taps we test for.
1408 * @ingroup Elm_Gesture_Layer
1411 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1412 void *event_info, Evas_Callback_Type event_type,
1413 Elm_Gesture_Types g_type)
1414 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1415 Widget_Data *wd = elm_widget_data_get(obj);
1418 if (!pe) /* this happens when unhandled event arrived */
1419 return; /* see _make_pointer_event function */
1420 Gesture_Info *gesture = wd->gesture[g_type];
1421 if (!gesture) return;
1423 Long_Tap_Type *st = gesture->data;
1425 { /* Allocated once on first time */
1426 st = calloc(1, sizeof(Long_Tap_Type));
1428 _n_long_tap_test_reset(gesture);
1431 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1432 switch (pe->event_type)
1434 case EVAS_CALLBACK_MULTI_DOWN:
1435 case EVAS_CALLBACK_MOUSE_DOWN:
1436 st->touched = _add_touched_device(st->touched, pe);
1437 st->info.n = eina_list_count(st->touched);
1438 if (st->info.n > st->max_touched)
1439 st->max_touched = st->info.n;
1441 { /* User removed finger from touch, then put back - ABORT */
1442 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1443 (gesture->state == ELM_GESTURE_STATE_MOVE))
1445 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1446 &st->info, EINA_FALSE);
1447 consume_event(wd, event_info, event_type, ev_flag);
1451 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1452 { /* This is the first mouse down we got */
1453 st->info.timestamp = pe->timestamp;
1455 /* To test long tap */
1456 /* When this timer expires, gesture STARTED */
1458 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1459 _long_tap_timeout, gesture);
1462 consume_event(wd, event_info, event_type, ev_flag);
1463 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1464 st->center_x = st->info.x;
1465 st->center_y = st->info.y;
1468 case EVAS_CALLBACK_MULTI_UP:
1469 case EVAS_CALLBACK_MOUSE_UP:
1470 st->touched = _remove_touched_device(st->touched, pe);
1471 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1473 ((gesture->state == ELM_GESTURE_STATE_START) ||
1474 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1475 { /* Report END only for gesture that STARTed */
1476 if (eina_list_count(st->touched) == 0)
1477 { /* Report END only at last release event */
1478 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1479 &st->info, EINA_FALSE);
1480 consume_event(wd, event_info, event_type, ev_flag);
1484 { /* Stop test, user lifts finger before long-start */
1485 if (st->timeout) ecore_timer_del(st->timeout);
1487 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1488 &st->info, EINA_FALSE);
1489 consume_event(wd, event_info, event_type, ev_flag);
1494 case EVAS_CALLBACK_MULTI_MOVE:
1495 case EVAS_CALLBACK_MOUSE_MOVE:
1497 ((gesture->state == ELM_GESTURE_STATE_START) ||
1498 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1499 { /* Report MOVE only if STARTED */
1502 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1504 _compute_taps_center(st, &x, &y, pe);
1505 /* ABORT if user moved fingers out of tap area */
1506 #if defined(DEBUG_GESTURE_LAYER)
1507 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1509 if (!_inside(x, y, st->center_x, st->center_y))
1510 state_to_report = ELM_GESTURE_STATE_ABORT;
1512 /* Report MOVE if gesture started */
1513 ev_flag = _set_state(gesture, state_to_report,
1514 &st->info, EINA_TRUE);
1515 consume_event(wd, event_info, event_type, ev_flag);
1527 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1528 * This momentum value will be sent to widget when gesture is completed.
1530 * @param momentum pointer to buffer where we record momentum value.
1531 * @param x1 x coord where user started gesture.
1532 * @param y1 y coord where user started gesture.
1533 * @param x2 x coord where user completed gesture.
1534 * @param y2 y coord where user completed gesture.
1535 * @param t1x timestamp for X, when user started gesture.
1536 * @param t1y timestamp for Y, when user started gesture.
1537 * @param t2 timestamp when user completed gesture.
1539 * @ingroup Elm_Gesture_Layer
1542 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1543 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1546 Evas_Coord velx = 0, vely = 0, vel;
1547 Evas_Coord dx = x2 - x1;
1548 Evas_Coord dy = y2 - y1;
1552 velx = (dx * 1000) / dtx;
1555 vely = (dy * 1000) / dty;
1557 vel = sqrt((velx * velx) + (vely * vely));
1559 if ((_elm_config->thumbscroll_friction > 0.0) &&
1560 (vel > _elm_config->thumbscroll_momentum_threshold))
1561 { /* report momentum */
1562 momentum->mx = velx;
1563 momentum->my = vely;
1575 * This function is used for computing rotation angle (DEG).
1577 * @param x1 first finger x location.
1578 * @param y1 first finger y location.
1579 * @param x2 second finger x location.
1580 * @param y2 second finger y location.
1582 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1584 * @ingroup Elm_Gesture_Layer
1587 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1593 if (((int) xx) && ((int) yy))
1600 return RAD_360DEG - a;
1611 return RAD_180DEG + a;
1615 return RAD_180DEG - a;
1621 { /* Horizontal line */
1646 * This function is used for computing the magnitude and direction
1647 * of vector between two points.
1649 * @param x1 first finger x location.
1650 * @param y1 first finger y location.
1651 * @param x2 second finger x location.
1652 * @param y2 second finger y location.
1653 * @param l length computed (output)
1654 * @param a angle computed (output)
1656 * @ingroup Elm_Gesture_Layer
1659 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1660 Evas_Coord *l, double *a)
1665 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1666 *a = get_angle(x1, y1, x2, y2);
1670 _get_direction(Evas_Coord x1, Evas_Coord x2)
1682 * This function tests momentum gesture.
1683 * @param obj The gesture-layer object.
1684 * @param pe The recent input event as stored in pe struct.
1685 * @param event_info recent input event.
1686 * @param event_type recent event type.
1687 * @param g_type what Gesture we are testing.
1689 * @ingroup Elm_Gesture_Layer
1692 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1693 void *event_info, Evas_Callback_Type event_type,
1694 Elm_Gesture_Types g_type)
1696 Widget_Data *wd = elm_widget_data_get(obj);
1698 Gesture_Info *gesture = wd->gesture[g_type];
1699 if (!gesture ) return;
1701 Momentum_Type *st = gesture->data;
1702 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1704 { /* Allocated once on first time */
1705 st = calloc(1, sizeof(Momentum_Type));
1707 _momentum_test_reset(gesture);
1713 /* First make avarage of all touched devices to determine center point */
1716 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1717 int cnt = 1; /* We start counter counting current pe event */
1718 EINA_LIST_FOREACH(wd->touched, l, p)
1719 if (p->device != pe_local.device)
1727 /* Compute avarage to get center point */
1731 /* If user added finger - reset gesture */
1732 if ((st->n_fingers) && (st->n_fingers < cnt))
1733 state_to_report = ELM_GESTURE_STATE_ABORT;
1735 st->n_fingers = cnt;
1737 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1740 case EVAS_CALLBACK_MOUSE_DOWN:
1741 case EVAS_CALLBACK_MULTI_DOWN:
1742 case EVAS_CALLBACK_MOUSE_MOVE:
1743 case EVAS_CALLBACK_MULTI_MOVE:
1746 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1747 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1748 (wd->glayer_continues_enable)) /* start also on MOVE */
1749 { /* We start on MOVE when cont-enabled only */
1750 st->line_st.x = st->line_end.x = pe_local.x;
1751 st->line_st.y = st->line_end.y = pe_local.y;
1752 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1753 st->xdir = st->ydir = 0;
1754 st->info.x2 = st->info.x1 = pe_local.x;
1755 st->info.y2 = st->info.y1 = pe_local.y;
1756 st->info.tx = st->info.ty = pe_local.timestamp;
1757 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1758 &st->info, EINA_FALSE);
1759 consume_event(wd, event_info, event_type, ev_flag);
1766 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1768 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1769 state_to_report = ELM_GESTURE_STATE_ABORT;
1771 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1772 { /* Too long of a wait, reset all values */
1773 st->line_st.x = pe_local.x;
1774 st->line_st.y = pe_local.y;
1775 st->t_st_y = st->t_st_x = pe_local.timestamp;
1776 st->info.tx = st->t_st_x;
1777 st->info.ty = st->t_st_y;
1778 st->xdir = st->ydir = 0;
1783 xdir = _get_direction(st->line_st.x, pe_local.x);
1784 ydir = _get_direction(st->line_st.y, pe_local.y);
1785 if (!xdir || (xdir == (-st->xdir)))
1787 st->line_st.x = st->line_end.x;
1788 st->info.tx = st->t_st_x = st->t_end;
1792 if (!ydir || (ydir == (-st->ydir)))
1794 st->line_st.y = st->line_end.y;
1795 st->info.ty = st->t_st_y = st->t_end;
1800 st->info.x2 = st->line_end.x = pe_local.x;
1801 st->info.y2 = st->line_end.y = pe_local.y;
1802 st->t_end = pe_local.timestamp;
1803 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1804 st->t_st_x, st->t_st_y, pe_local.timestamp);
1805 ev_flag = _set_state(gesture, state_to_report, &st->info,
1807 consume_event(wd, event_info, event_type, ev_flag);
1811 case EVAS_CALLBACK_MOUSE_UP:
1812 case EVAS_CALLBACK_MULTI_UP:
1813 st->t_up = pe_local.timestamp; /* Record recent up event time */
1814 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1815 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1818 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1819 { /* Too long of a wait, reset all values */
1820 st->line_st.x = pe_local.x;
1821 st->line_st.y = pe_local.y;
1822 st->t_st_y = st->t_st_x = pe_local.timestamp;
1823 st->xdir = st->ydir = 0;
1826 st->info.x2 = pe_local.x;
1827 st->info.y2 = pe_local.y;
1828 st->line_end.x = pe_local.x;
1829 st->line_end.y = pe_local.y;
1830 st->t_end = pe_local.timestamp;
1832 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1833 st->t_st_x, st->t_st_y, pe_local.timestamp);
1835 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1837 consume_event(wd, event_info, event_type, ev_flag);
1846 compare_line_device(const void *data1, const void *data2)
1847 { /* Compare device component of line struct */
1848 const Line_Data *ln1 = data1;
1849 const int *device = data2;
1851 if (ln1->t_st) /* Compare only with lines that started */
1852 return (ln1->device - (*device));
1860 * This function construct line struct from input.
1861 * @param info pointer to store line momentum.
1862 * @param st line info to store input data.
1863 * @param pe The recent input event as stored in pe struct.
1865 * @ingroup Elm_Gesture_Layer
1868 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1869 Pointer_Event *pe, Evas_Callback_Type event_type)
1870 { /* Record events and set momentum for line pointed by st */
1876 case EVAS_CALLBACK_MOUSE_DOWN:
1877 case EVAS_CALLBACK_MOUSE_MOVE:
1878 case EVAS_CALLBACK_MULTI_DOWN:
1879 case EVAS_CALLBACK_MULTI_MOVE:
1881 { /* This happens only when line starts */
1882 st->line_st.x = pe->x;
1883 st->line_st.y = pe->y;
1884 st->t_st = pe->timestamp;
1885 st->device = pe->device;
1886 info->momentum.x1 = pe->x;
1887 info->momentum.y1 = pe->y;
1888 info->momentum.tx = pe->timestamp;
1889 info->momentum.ty = pe->timestamp;
1896 case EVAS_CALLBACK_MOUSE_UP:
1897 case EVAS_CALLBACK_MULTI_UP:
1898 /* IGNORE if line info was cleared, like long press, move */
1902 st->line_end.x = pe->x;
1903 st->line_end.y = pe->y;
1904 st->t_end = pe->timestamp;
1913 _line_data_reset(st);
1917 info->momentum.x2 = pe->x;
1918 info->momentum.y2 = pe->y;
1919 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1920 st->t_st, st->t_st, pe->timestamp);
1928 * This function test for (n) line gesture.
1929 * @param obj The gesture-layer object.
1930 * @param pe The recent input event as stored in pe struct.
1931 * @param event_info Original input event pointer.
1932 * @param event_type Type of original input event.
1933 * @param g_type what Gesture we are testing.
1935 * @ingroup Elm_Gesture_Layer
1938 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1939 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1943 Widget_Data *wd = elm_widget_data_get(obj);
1945 Gesture_Info *gesture = wd->gesture[g_type];
1946 if (!gesture ) return;
1948 Line_Type *st = gesture->data;
1951 st = calloc(1, sizeof(Line_Type));
1955 Line_Data *line = NULL;
1956 Eina_List *list = st->list;
1957 unsigned cnt = eina_list_count(list);
1960 { /* list is not empty, locate this device on list */
1961 line = (Line_Data *) eina_list_search_unsorted(st->list,
1962 compare_line_device, &pe->device);
1966 { /* List is empty or device not found, new line-struct on START only */
1967 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1968 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1969 ((wd->glayer_continues_enable) && /* START on MOVE also */
1970 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1971 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
1972 { /* Allocate new item on START only */
1973 line = calloc(1, sizeof(Line_Data));
1974 _line_data_reset(line);
1975 list = eina_list_append(list, line);
1980 if (!line) /* This may happen on MOVE that comes before DOWN */
1981 return; /* No line-struct to work with, can't continue testing */
1983 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
1984 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1986 /* Get direction and magnitude of the line */
1988 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1989 &line->line_length, &angle);
1991 /* These are used later to compare lines length */
1992 Evas_Coord shortest_line_len = line->line_length;
1993 Evas_Coord longest_line_len = line->line_length;
1994 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1996 /* Now update line-state */
1998 { /* Analyze line only if line started */
1999 if (line->line_angle >= 0.0)
2000 { /* if line direction was set, we test if broke tolerance */
2001 double a = fabs(angle - line->line_angle);
2003 double d = (tan(a)) * line->line_length; /* Distance from line */
2004 #if defined(DEBUG_GESTURE_LAYER)
2005 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2007 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2008 { /* Broke tolerance: abort line and start a new one */
2009 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2010 &st->info, EINA_FALSE);
2011 consume_event(wd, event_info, event_type, ev_flag);
2015 if (wd->glayer_continues_enable)
2016 { /* We may finish line if momentum is zero */
2017 /* This is for continues-gesture */
2018 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2019 { /* Finish line on zero momentum for continues gesture */
2020 line->line_end.x = pe->x;
2021 line->line_end.y = pe->y;
2022 line->t_end = pe->timestamp;
2027 { /* Record the line angle as it broke minimum length for line */
2028 if (line->line_length >= wd->line_min_length)
2029 st->info.angle = line->line_angle = angle;
2035 if (line->line_angle < 0.0)
2036 { /* it's not a line, too short more close to a tap */
2037 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2038 &st->info, EINA_FALSE);
2039 consume_event(wd, event_info, event_type, ev_flag);
2045 /* Count how many lines already started / ended */
2048 unsigned int tm_start = pe->timestamp;
2049 unsigned int tm_end = pe->timestamp;
2052 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2053 Eina_Bool lines_parallel = EINA_TRUE;
2054 EINA_LIST_FOREACH(list, l, t_line)
2057 base_angle = t_line->line_angle;
2060 if (t_line->line_angle >= 0)
2061 { /* Compare angle only with lines with direction defined */
2062 if (fabs(base_angle - t_line->line_angle) >
2063 wd->line_angular_tolerance)
2064 lines_parallel = EINA_FALSE;
2068 if (t_line->line_length)
2069 { /* update only if this line is used */
2070 if (shortest_line_len > t_line->line_length)
2071 shortest_line_len = t_line->line_length;
2073 if (longest_line_len < t_line->line_length)
2074 longest_line_len = t_line->line_length;
2080 if (t_line->t_st < tm_start)
2081 tm_start = t_line->t_st;
2087 if (t_line->t_end < tm_end)
2088 tm_end = t_line->t_end;
2092 st->info.n = started;
2096 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2097 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2098 { /* user lift one finger then starts again without line-end - ABORT */
2099 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2101 consume_event(wd, event_info, event_type, ev_flag);
2105 if (!lines_parallel)
2106 { /* Lines are NOT at same direction, abort this gesture */
2107 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2109 consume_event(wd, event_info, event_type, ev_flag);
2114 /* We report ABORT if lines length are NOT matching when fingers are up */
2115 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2117 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2119 consume_event(wd, event_info, event_type, ev_flag);
2123 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2124 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2125 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2127 consume_event(wd, event_info, event_type, ev_flag);
2133 case EVAS_CALLBACK_MOUSE_UP:
2134 case EVAS_CALLBACK_MULTI_UP:
2135 if ((started) && (started == ended))
2137 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2138 &st->info, EINA_FALSE);
2139 consume_event(wd, event_info, event_type, ev_flag);
2144 case EVAS_CALLBACK_MOUSE_DOWN:
2145 case EVAS_CALLBACK_MULTI_DOWN:
2146 case EVAS_CALLBACK_MOUSE_MOVE:
2147 case EVAS_CALLBACK_MULTI_MOVE:
2150 if (wd->glayer_continues_enable && (started == ended))
2151 { /* For continues gesture */
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);
2157 { /* When continues, may START on MOVE event too */
2158 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2160 /* This happens when: on n > 1 lines then one finger up */
2161 /* caused abort, then put finger down. */
2162 /* This will stop line from starting again. */
2163 /* Number of lines, MUST match touched-device in list */
2164 if ((!wd->glayer_continues_enable) &&
2165 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2166 s = ELM_GESTURE_STATE_ABORT;
2168 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2169 s = ELM_GESTURE_STATE_START;
2171 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2172 consume_event(wd, event_info, event_type, ev_flag);
2178 return; /* Unhandeld event type */
2185 * This function is used to check if rotation gesture started.
2186 * @param st Contains current rotation values from user input.
2187 * @return TRUE/FALSE if we need to set rotation START.
2189 * @ingroup Elm_Gesture_Layer
2192 rotation_broke_tolerance(Rotate_Type *st)
2194 if (st->info.base_angle < 0)
2195 return EINA_FALSE; /* Angle has to be computed first */
2197 if (st->rotate_angular_tolerance < 0)
2200 double low = st->info.base_angle - st->rotate_angular_tolerance;
2201 double high = st->info.base_angle + st->rotate_angular_tolerance;
2202 double t = st->info.angle;
2215 if (high > RAD_360DEG)
2226 #if defined(DEBUG_GESTURE_LAYER)
2227 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2229 if ((t < low) || (t > high))
2230 { /* This marks that roation action has started */
2231 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2232 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2242 * This function is used for computing the gap between fingers.
2243 * It returns the length and center point between fingers.
2245 * @param x1 first finger x location.
2246 * @param y1 first finger y location.
2247 * @param x2 second finger x location.
2248 * @param y2 second finger y location.
2249 * @param x Gets center point x cord (output)
2250 * @param y Gets center point y cord (output)
2252 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2254 * @ingroup Elm_Gesture_Layer
2257 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2258 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2260 double a, b, xx, yy, gap;
2263 gap = sqrt(xx*xx + yy*yy);
2265 /* START - Compute zoom center point */
2266 /* The triangle defined as follows:
2274 * http://en.wikipedia.org/wiki/Trigonometric_functions
2275 *************************************/
2276 if (((int) xx) && ((int) yy))
2278 double A = atan((yy / xx));
2279 #if defined(DEBUG_GESTURE_LAYER)
2280 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2282 a = (Evas_Coord) ((gap / 2) * sin(A));
2283 b = (Evas_Coord) ((gap / 2) * cos(A));
2284 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2285 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2290 { /* horiz line, take half width */
2291 #if defined(DEBUG_GESTURE_LAYER)
2292 printf("==== HORIZ ====\n");
2294 *x = (Evas_Coord) (xx / 2);
2295 *y = (Evas_Coord) (y1);
2299 { /* vert line, take half width */
2300 #if defined(DEBUG_GESTURE_LAYER)
2301 printf("==== VERT ====\n");
2303 *x = (Evas_Coord) (x1);
2304 *y = (Evas_Coord) (yy / 2);
2307 /* END - Compute zoom center point */
2309 return (Evas_Coord) gap;
2315 * This function is used for computing zoom value.
2317 * @param st Pointer to zoom data based on user input.
2318 * @param x1 first finger x location.
2319 * @param y1 first finger y location.
2320 * @param x2 second finger x location.
2321 * @param y2 second finger y location.
2322 * @param factor zoom-factor, used to determine how fast zoom works.
2324 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2326 * @ingroup Elm_Gesture_Layer
2328 /* FIXME change float to double */
2330 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2331 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2334 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2335 &st->info.x, &st->info.y);
2337 st->info.radius = diam / 2;
2341 st->zoom_base = diam;
2342 return st->info.zoom;
2345 if (st->zoom_distance_tolerance)
2346 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2347 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2348 { /* avoid jump with zoom value when break tolerance */
2349 st->zoom_base -= st->zoom_distance_tolerance;
2350 st->zoom_distance_tolerance = 0;
2353 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2354 { /* avoid jump with zoom value when break tolerance */
2355 st->zoom_base += st->zoom_distance_tolerance;
2356 st->zoom_distance_tolerance = 0;
2362 /* We use factor only on the difference between gap-base */
2363 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2364 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2365 (float) st->zoom_base) * zoom_finger_factor));
2368 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2369 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2380 * This function handles zoom with mouse wheel.
2381 * thats a combination of wheel + CTRL key.
2382 * @param obj The gesture-layer object.
2383 * @param event_info Original input event pointer.
2384 * @param event_type Type of original input event.
2385 * @param g_type what Gesture we are testing.
2387 * @ingroup Elm_Gesture_Layer
2390 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2391 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2393 Widget_Data *wd = elm_widget_data_get(obj);
2395 if (!wd->gesture[g_type]) return;
2397 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2398 Zoom_Type *st = gesture_zoom->data;
2399 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2401 { /* Allocated once on first time, used for zoom intermediate data */
2402 st = calloc(1, sizeof(Zoom_Type));
2403 gesture_zoom->data = st;
2404 _zoom_test_reset(gesture_zoom);
2409 case EVAS_CALLBACK_KEY_UP:
2411 Evas_Event_Key_Up *p = event_info;
2412 if ((!strcmp(p->keyname, "Control_L")) ||
2413 (!strcmp(p->keyname, "Control_R")))
2414 { /* Test if we ended a zoom gesture when releasing CTRL */
2415 if ((st->zoom_wheel) &&
2416 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2417 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2418 { /* User released CTRL after zooming */
2419 ev_flag = _set_state(gesture_zoom,
2420 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2421 consume_event(wd, event_info, event_type, ev_flag);
2429 case EVAS_CALLBACK_MOUSE_WHEEL:
2432 Elm_Gesture_State s;
2433 if (!evas_key_modifier_is_set(
2434 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2436 { /* if using wheel witout CTRL after starting zoom */
2437 if ((st->zoom_wheel) &&
2438 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2439 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2441 ev_flag = _set_state(gesture_zoom,
2442 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2443 consume_event(wd, event_info, event_type, ev_flag);
2448 return; /* Ignore mouse-wheel without control */
2451 /* Using mouse wheel with CTRL for zoom */
2452 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2453 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2454 we continue a zoom gesture */
2456 s = ELM_GESTURE_STATE_MOVE;
2459 { /* On first wheel event, report START */
2460 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2461 evas_object_evas_get(wd->target), "Control");
2463 s = ELM_GESTURE_STATE_START;
2464 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2465 ERR("Failed to Grabbed CTRL_L");
2466 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2467 ERR("Failed to Grabbed CTRL_R");
2470 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2471 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2472 st->info.x = st->zoom_wheel->canvas.x;
2473 st->info.y = st->zoom_wheel->canvas.y;
2475 if (st->zoom_wheel->z < 0) /* zoom in */
2476 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2478 if (st->zoom_wheel->z > 0) /* zoom out */
2479 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2481 if (st->info.zoom < 0.0)
2482 st->info.zoom = 0.0;
2484 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2485 consume_event(wd, event_info, event_type, ev_flag);
2497 * This function is used to test zoom gesture.
2498 * user may combine zoom, rotation together.
2499 * so its possible that both will be detected from input.
2500 * (both are two-finger movement-oriented gestures)
2502 * @param obj The gesture-layer object.
2503 * @param event_info Pointer to recent input event.
2504 * @param event_type Recent input event type.
2505 * @param g_type what Gesture we are testing.
2507 * @ingroup Elm_Gesture_Layer
2510 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2511 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2515 Widget_Data *wd = elm_widget_data_get(obj);
2517 if (!wd->gesture[g_type]) return;
2519 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2520 Zoom_Type *st = gesture_zoom->data;
2523 { /* Allocated once on first time, used for zoom data */
2524 st = calloc(1, sizeof(Zoom_Type));
2525 gesture_zoom->data = st;
2526 _zoom_test_reset(gesture_zoom);
2530 /* Start - new zoom testing, letting all fingers start */
2531 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2534 case EVAS_CALLBACK_MOUSE_MOVE:
2535 case EVAS_CALLBACK_MULTI_MOVE:
2536 /* if non-continues mode and gesture NOT started, ignore MOVE */
2537 if ((!wd->glayer_continues_enable) &&
2538 (!st->zoom_st.timestamp))
2541 case EVAS_CALLBACK_MOUSE_DOWN:
2542 case EVAS_CALLBACK_MULTI_DOWN:
2543 { /* Here we take care of zoom-start and zoom move */
2547 if(eina_list_count(wd->touched) > 2)
2548 { /* Process zoom only when 2 fingers on surface */
2549 ev_flag = _set_state(gesture_zoom,
2550 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2551 consume_event(wd, event_info, event_type, ev_flag);
2556 if (!st->zoom_st.timestamp)
2557 { /* Now scan touched-devices list and find other finger */
2558 EINA_LIST_FOREACH(wd->touched, l, p)
2559 { /* Device of other finger <> pe device */
2560 if (p->device != pe->device)
2564 if (!p) /* Single finger on touch */
2567 /* Record down fingers */
2568 consume_event(wd, event_info, event_type, ev_flag);
2569 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2570 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2572 /* Set mv field as well to be ready for MOVE events */
2573 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2574 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2576 /* Here we have zoom_st, zoom_st1 set, report START */
2577 /* Set zoom-base after BOTH down events recorded */
2578 /* Compute length of line between fingers zoom start */
2579 st->info.zoom = 1.0;
2580 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2581 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2582 &st->info.x, &st->info.y);
2584 st->info.radius = st->zoom_base / 2;
2586 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2587 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2588 { /* zoom started with mouse-wheel, don't report twice */
2589 ev_flag = _set_state(gesture_zoom,
2590 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2591 consume_event(wd, event_info, event_type, ev_flag);
2594 return; /* Zoom started */
2595 } /* End of ZOOM_START handling */
2598 /* if we got here, we have (exacally) two fingers on surfce */
2599 /* we also after START, report MOVE */
2600 /* First detect which finger moved */
2601 if (pe->device == st->zoom_mv.device)
2602 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2603 else if (pe->device == st->zoom_mv1.device)
2604 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2606 /* Compute change in zoom as fingers move */
2607 st->info.zoom = compute_zoom(st,
2608 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2609 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2610 wd->zoom_finger_factor);
2612 if (!st->zoom_distance_tolerance)
2613 { /* Zoom broke tolerance, report move */
2614 double d = st->info.zoom - st->next_step;
2618 if (d >= wd->zoom_step)
2619 { /* Report move in steps */
2620 st->next_step = st->info.zoom;
2622 ev_flag = _set_state(gesture_zoom,
2623 ELM_GESTURE_STATE_MOVE,
2624 &st->info, EINA_TRUE);
2625 consume_event(wd, event_info, event_type, ev_flag);
2627 } /* End of ZOOM_MOVE handling */
2632 case EVAS_CALLBACK_MOUSE_UP:
2633 case EVAS_CALLBACK_MULTI_UP:
2634 /* Reset timestamp of finger-up.This is used later
2635 by _zoom_test_reset() to retain finger-down data */
2636 consume_event(wd, event_info, event_type, ev_flag);
2637 if (((st->zoom_wheel) || (st->zoom_base)) &&
2638 (st->zoom_distance_tolerance == 0))
2640 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2641 &st->info, EINA_FALSE);
2642 consume_event(wd, event_info, event_type, ev_flag);
2647 /* if we got here not a ZOOM */
2648 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2649 { /* Must be != undefined, if gesture started */
2650 ev_flag = _set_state(gesture_zoom,
2651 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2652 consume_event(wd, event_info, event_type, ev_flag);
2655 _zoom_test_reset(gesture_zoom);
2665 _get_rotate_properties(Rotate_Type *st,
2666 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2667 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2670 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2671 &st->info.x, &st->info.y) / 2;
2673 *angle = get_angle(x1, y1, x2, y2);
2674 #if 0 /* (NOT YET SUPPORTED) */
2675 if (angle == &st->info.angle)
2676 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2677 st->info.momentum = (((*angle) - st->info.base_angle) /
2678 (fabs(tm2 - tm1))) * 1000;
2681 st->info.momentum = 0;
2691 * This function is used to test rotation gesture.
2692 * user may combine zoom, rotation together.
2693 * so its possible that both will be detected from input.
2694 * (both are two-finger movement-oriented gestures)
2696 * @param obj The gesture-layer object.
2697 * @param event_info Pointer to recent input event.
2698 * @param event_type Recent input event type.
2699 * @param g_type what Gesture we are testing.
2701 * @ingroup Elm_Gesture_Layer
2704 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2705 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2710 Widget_Data *wd = elm_widget_data_get(obj);
2712 if (!wd->gesture[g_type]) return;
2714 Gesture_Info *gesture = wd->gesture[g_type];
2715 Rotate_Type *st = gesture->data;
2720 { /* Allocated once on first time */
2721 st = calloc(1, sizeof(Rotate_Type));
2723 _rotate_test_reset(gesture);
2727 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2730 case EVAS_CALLBACK_MOUSE_MOVE:
2731 case EVAS_CALLBACK_MULTI_MOVE:
2732 /* if non-continues mode and gesture NOT started, ignore MOVE */
2733 if ((!wd->glayer_continues_enable) &&
2734 (!st->rotate_st.timestamp))
2737 case EVAS_CALLBACK_MOUSE_DOWN:
2738 case EVAS_CALLBACK_MULTI_DOWN:
2739 { /* Here we take care of rotate-start and rotate move */
2743 if(eina_list_count(wd->touched) > 2)
2744 { /* Process rotate only when 2 fingers on surface */
2745 ev_flag = _set_state(gesture,
2746 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2747 consume_event(wd, event_info, event_type, ev_flag);
2752 if (!st->rotate_st.timestamp)
2753 { /* Now scan touched-devices list and find other finger */
2754 EINA_LIST_FOREACH(wd->touched, l, p)
2755 { /* Device of other finger <> pe device */
2756 if (p->device != pe->device)
2761 return; /* Single finger on touch */
2763 /* Record down fingers */
2764 consume_event(wd, event_info, event_type, ev_flag);
2765 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2766 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2768 /* Set mv field as well to be ready for MOVE events */
2769 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2770 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2772 /* Here we have rotate_st, rotate_st1 set, report START */
2773 /* Set rotate-base after BOTH down events recorded */
2774 /* Compute length of line between fingers rotate start */
2775 _get_rotate_properties(st,
2776 st->rotate_st.x, st->rotate_st.y,
2777 st->rotate_st.timestamp,
2778 st->rotate_st1.x, st->rotate_st1.y,
2779 st->rotate_st1.timestamp, &st->info.base_angle);
2781 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2782 &st->info, EINA_FALSE);
2783 consume_event(wd, event_info, event_type, ev_flag);
2785 return; /* Rotate started */
2786 } /* End of ROTATE_START handling */
2789 /* if we got here, we have (exacally) two fingers on surfce */
2790 /* we also after START, report MOVE */
2791 /* First detect which finger moved */
2792 if (pe->device == st->rotate_mv.device)
2793 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2794 else if (pe->device == st->rotate_mv1.device)
2795 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2797 /* Compute change in rotate as fingers move */
2798 _get_rotate_properties(st,
2799 st->rotate_mv.x, st->rotate_mv.y,
2800 st->rotate_mv.timestamp,
2801 st->rotate_mv1.x, st->rotate_mv1.y,
2802 st->rotate_mv1.timestamp, &st->info.angle);
2804 if (rotation_broke_tolerance(st))
2805 { /* Rotation broke tolerance, report move */
2806 double d = st->info.angle - st->next_step;
2810 if (d >= wd->rotate_step)
2811 { /* Report move in steps */
2812 st->next_step = st->info.angle;
2814 ev_flag = _set_state(gesture,
2815 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2816 consume_event(wd, event_info, event_type, ev_flag);
2818 } /* End of ROTATE_MOVE handling */
2823 case EVAS_CALLBACK_MOUSE_UP:
2824 case EVAS_CALLBACK_MULTI_UP:
2825 consume_event(wd, event_info, event_type, ev_flag);
2826 /* Reset timestamp of finger-up.This is used later
2827 by rotate_test_reset() to retain finger-down data */
2828 if (st->rotate_angular_tolerance < 0)
2830 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2831 &st->info, EINA_FALSE);
2832 consume_event(wd, event_info, event_type, ev_flag);
2837 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2838 { /* Must be != undefined, if gesture started */
2839 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2840 &st->info, EINA_FALSE);
2841 consume_event(wd, event_info, event_type, ev_flag);
2844 _rotate_test_reset(gesture);
2855 * This function is used to save input events in an abstract struct
2856 * to be used later by getsure-testing functions.
2858 * @param data The gesture-layer object.
2859 * @param event_info Pointer to recent input event.
2860 * @param event_type Recent input event type.
2861 * @param pe The abstract data-struct (output).
2863 * @ingroup Elm_Gesture_Layer
2866 _make_pointer_event(void *data, void *event_info,
2867 Evas_Callback_Type event_type, Pointer_Event *pe)
2869 Widget_Data *wd = elm_widget_data_get(data);
2870 if (!wd) return EINA_FALSE;
2872 memset(pe, '\0', sizeof(*pe));
2875 case EVAS_CALLBACK_MOUSE_DOWN:
2876 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2877 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2878 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2879 pe->device = ELM_MOUSE_DEVICE;
2882 case EVAS_CALLBACK_MOUSE_UP:
2883 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2884 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2885 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2886 pe->device = ELM_MOUSE_DEVICE;
2889 case EVAS_CALLBACK_MOUSE_MOVE:
2890 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2891 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2892 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2893 pe->device = ELM_MOUSE_DEVICE;
2896 case EVAS_CALLBACK_MULTI_DOWN:
2897 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2898 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2899 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2900 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2903 case EVAS_CALLBACK_MULTI_UP:
2904 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2905 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2906 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2907 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2910 case EVAS_CALLBACK_MULTI_MOVE:
2911 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2912 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2913 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2914 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2921 pe->event_type = event_type;
2928 * This function restartes line, flick, zoom and rotate gestures
2929 * when gesture-layer continues-gestures enabled.
2930 * Example of continues-gesture:
2931 * When doing a line, user stops moving finger but keeps fingers on touch.
2932 * This will cause line-end, then as user continues moving his finger
2933 * it re-starts line gesture.
2934 * When continue mode is disabled, user has to lift finger from touch
2935 * to end a gesture. Them touch-again to start a new one.
2937 * @param data The gesture-layer object.
2938 * @param wd gesture layer widget data.
2939 * @param states_reset flag that marks gestures were reset in history clear.
2941 * @ingroup Elm_Gesture_Layer
2943 void continues_gestures_restart(void *data, Eina_Bool states_reset)
2945 Widget_Data *wd = elm_widget_data_get(data);
2948 /* Run through events to restart gestures */
2950 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
2951 /* We turn-on flag for finished, aborted, not-started gestures */
2952 g = wd->gesture[ELM_GESTURE_MOMENTUM];
2953 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2954 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2957 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
2958 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2962 g = wd->gesture[ELM_GESTURE_N_LINES];
2963 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2964 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2967 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
2968 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2972 g = wd->gesture[ELM_GESTURE_N_FLICKS];
2973 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2974 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2977 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
2978 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2982 g = wd->gesture[ELM_GESTURE_ZOOM];
2983 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2984 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2987 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
2988 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
2992 g = wd->gesture[ELM_GESTURE_ROTATE];
2993 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2994 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
2997 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
2998 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3006 * This function the core-function where input handling is done.
3007 * Here we get user input and stream it to gesture testing.
3008 * We notify user about any gestures with new state:
3010 * START - gesture started.
3011 * MOVE - gesture is ongoing.
3012 * END - gesture was completed.
3013 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3015 * We also check if a gesture was detected, then reset event history
3016 * If no gestures were found we reset gesture test flag
3017 * after streaming event-history to widget.
3018 * (stream to the widget all events not consumed as a gesture)
3020 * @param data The gesture-layer object.
3021 * @param event_info Pointer to recent input event.
3022 * @param event_type Recent input event type.
3024 * @ingroup Elm_Gesture_Layer
3027 _event_process(void *data, Evas_Object *obj __UNUSED__,
3028 void *event_info, Evas_Callback_Type event_type)
3031 Pointer_Event *pe = NULL;
3032 Widget_Data *wd = elm_widget_data_get(data);
3035 #if defined(DEBUG_GESTURE_LAYER)
3038 printf("Gesture | State | is tested\n");
3039 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3043 printf(" %d %d %d\n", i, g->state, g->test);
3047 /* Start testing candidate gesture from here */
3048 if (_make_pointer_event(data, event_info, event_type, &_pe))
3051 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3052 _n_long_tap_test(data, pe, event_info, event_type,
3053 ELM_GESTURE_N_LONG_TAPS);
3055 /* This takes care of single, double and tripple tap */
3056 _tap_gestures_test(data, pe, event_info, event_type);
3058 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3059 _momentum_test(data, pe, event_info, event_type,
3060 ELM_GESTURE_MOMENTUM);
3062 if (IS_TESTED(ELM_GESTURE_N_LINES))
3063 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3065 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3066 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3068 if (IS_TESTED(ELM_GESTURE_ZOOM))
3069 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3071 if (IS_TESTED(ELM_GESTURE_ZOOM))
3072 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3074 if (IS_TESTED(ELM_GESTURE_ROTATE))
3075 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3077 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3078 _event_history_add(data, event_info, event_type);
3079 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3080 (event_type == EVAS_CALLBACK_MULTI_UP))
3082 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3085 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3086 _event_history_add(data, event_info, event_type);
3090 /* we maintain list of touched devices */
3091 /* We also use move to track current device x.y pos */
3092 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3093 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3094 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3095 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3097 wd->touched = _add_touched_device(wd->touched, pe);
3099 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3100 (event_type == EVAS_CALLBACK_MULTI_UP))
3102 wd->touched = _remove_touched_device(wd->touched, pe);
3105 /* Report current states and clear history if needed */
3106 Eina_Bool states_reset = _clear_if_finished(data);
3107 if (wd->glayer_continues_enable)
3108 continues_gestures_restart(data, states_reset);
3113 * For all _mouse_* / multi_* functions wethen send this event to
3114 * _event_process function.
3116 * @param data The gesture-layer object.
3117 * @param event_info Pointer to recent input event.
3119 * @ingroup Elm_Gesture_Layer
3122 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3125 Widget_Data *wd = elm_widget_data_get(data);
3127 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3128 return; /* We only process left-click at the moment */
3130 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3134 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3137 Widget_Data *wd = elm_widget_data_get(data);
3140 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3144 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3147 Widget_Data *wd = elm_widget_data_get(data);
3150 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3154 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3157 Widget_Data *wd = elm_widget_data_get(data);
3160 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3164 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3167 Widget_Data *wd = elm_widget_data_get(data);
3170 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3171 return; /* We only process left-click at the moment */
3173 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3177 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3180 Widget_Data *wd = elm_widget_data_get(data);
3183 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3187 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3190 Widget_Data *wd = elm_widget_data_get(data);
3193 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3197 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3200 Widget_Data *wd = elm_widget_data_get(data);
3203 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3207 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3210 Widget_Data *wd = elm_widget_data_get(data);
3213 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3217 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3219 Widget_Data *wd = elm_widget_data_get(obj);
3220 if (!wd) return EINA_FALSE;
3222 return !wd->repeat_events;
3226 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3228 Widget_Data *wd = elm_widget_data_get(obj);
3231 wd->repeat_events = !r;
3235 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3237 Widget_Data *wd = elm_widget_data_get(obj);
3247 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3249 Widget_Data *wd = elm_widget_data_get(obj);
3255 wd->rotate_step = s;
3259 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3261 Widget_Data *wd = elm_widget_data_get(obj);
3262 if (!wd) return EINA_FALSE;
3267 /* if was attached before, unregister callbacks first */
3269 _unregister_callbacks(obj);
3273 _register_callbacks(obj);
3278 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3279 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3281 Widget_Data *wd = elm_widget_data_get(obj);
3285 if (!wd->gesture[idx])
3286 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3287 if (!wd->gesture[idx]) return;
3289 p = wd->gesture[idx];
3292 p->fn[cb_type].cb = cb;
3293 p->fn[cb_type].user_data = data;
3294 p->state = ELM_GESTURE_STATE_UNDEFINED;
3299 _disable_hook(Evas_Object *obj)
3301 if (elm_widget_disabled_get(obj))
3302 _unregister_callbacks(obj);
3304 _register_callbacks(obj);
3308 elm_gesture_layer_add(Evas_Object *parent)
3314 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3316 wd = ELM_NEW(Widget_Data);
3317 e = evas_object_evas_get(parent);
3318 if (!e) return NULL;
3319 obj = elm_widget_add(e);
3320 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3321 elm_widget_type_set(obj, "gesture_layer");
3322 elm_widget_sub_object_add(parent, obj);
3323 elm_widget_data_set(obj, wd);
3324 elm_widget_del_hook_set(obj, _del_hook);
3325 elm_widget_disable_hook_set(obj, _disable_hook);
3328 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3329 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3330 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3331 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3332 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3333 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3334 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3335 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3336 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3337 wd->repeat_events = EINA_TRUE;
3338 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3340 #if defined(DEBUG_GESTURE_LAYER)
3341 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3342 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);
3344 memset(wd->gesture, 0, sizeof(wd->gesture));