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_DELAY 25
10 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
11 #define ELM_GESTURE_MULTI_TIMEOUT 50
12 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
14 /* Some Trigo values */
15 #define RAD_90DEG M_PI_2
16 #define RAD_180DEG M_PI
17 #define RAD_270DEG (M_PI_2 * 3)
18 #define RAD_360DEG (M_PI * 2)
19 /* #define DEBUG_GESTURE_LAYER 1 */
21 #define RAD2DEG(x) ((x) * 57.295779513)
22 #define DEG2RAD(x) ((x) / 57.295779513)
25 _glayer_bufdup(void *buf, size_t size)
32 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
35 #define SET_TEST_BIT(P) do { \
36 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; \
39 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
45 * Struct holds callback information.
47 * @ingroup Elm_Gesture_Layer
51 void *user_data; /**< Holds user data to CB (like sd) */
52 Elm_Gesture_Event_Cb cb;
59 * type for callback information
61 * @ingroup Elm_Gesture_Layer
63 typedef struct _Func_Data Func_Data;
68 * @struct _Gesture_Info
69 * Struct holds gesture info
71 * @ingroup Elm_Gesture_Layer
76 void *data; /**< Holds gesture intemidiate processing data */
77 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
79 Elm_Gesture_Types g_type; /**< gesture type */
81 Elm_Gesture_Type g_type; /**< gesture type */
82 >>>>>>> remotes/origin/upstream
83 Elm_Gesture_State state; /**< gesture state */
84 void *info; /**< Data for the state callback */
85 Eina_Bool test; /**< if true this gesture should be tested on input */
91 * @typedef Gesture_Info
92 * Type for _Gesture_Info
94 * @ingroup Elm_Gesture_Layer
96 typedef struct _Gesture_Info Gesture_Info;
101 * @struct _Event_History
102 * Struct holds event history.
103 * These events are repeated if no gesture found.
105 * @ingroup Elm_Gesture_Layer
107 struct _Event_History
111 Evas_Callback_Type event_type;
117 * @typedef Event_History
118 * Type for _Event_History
120 * @ingroup Elm_Gesture_Layer
122 typedef struct _Event_History Event_History;
127 * @struct _Pointer_Event
128 * Struct holds pointer-event info
129 * This is a generic pointer event structure
131 * @ingroup Elm_Gesture_Layer
133 struct _Pointer_Event
136 unsigned int timestamp;
138 Evas_Callback_Type event_type;
144 * @typedef Pointer_Event
145 * Type for generic pointer event structure
147 * @ingroup Elm_Gesture_Layer
149 typedef struct _Pointer_Event Pointer_Event;
151 /* All *Type structs hold result for the user in 'info' field
152 * The rest is gesture processing intermediate data.
153 * NOTE: info field must be FIRST in the struct.
154 * This is used when reporting ABORT in event_history_clear() */
157 Elm_Gesture_Taps_Info info;
160 unsigned int n_taps_needed;
164 typedef struct _Taps_Type Taps_Type;
166 struct _Long_Tap_Type
168 Elm_Gesture_Taps_Info info;
171 unsigned int max_touched;
172 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
175 typedef struct _Long_Tap_Type Long_Tap_Type;
177 struct _Momentum_Type
178 { /* Fields used by _line_test() */
179 Elm_Gesture_Momentum_Info info;
180 Evas_Coord_Point line_st;
181 Evas_Coord_Point line_end;
182 unsigned int t_st_x; /* Time start on X */
183 unsigned int t_st_y; /* Time start on Y */
184 unsigned int t_end; /* Time end */
185 unsigned int t_up; /* Recent up event time */
188 typedef struct _Momentum_Type Momentum_Type;
192 Evas_Coord_Point line_st;
193 Evas_Coord_Point line_end;
194 Evas_Coord line_length;
195 unsigned int t_st; /* Time start */
196 unsigned int t_end; /* Time end */
198 double line_angle; /* Current angle of line */
200 typedef struct _Line_Data Line_Data;
203 { /* Fields used by _line_test() */
204 Elm_Gesture_Line_Info info;
205 Eina_List *list; /* List of Line_Data */
207 typedef struct _Line_Type Line_Type;
210 { /* Fields used by _zoom_test() */
211 Elm_Gesture_Zoom_Info info;
212 Pointer_Event zoom_st;
213 Pointer_Event zoom_mv;
214 Pointer_Event zoom_st1;
215 Pointer_Event zoom_mv1;
216 Evas_Event_Mouse_Wheel *zoom_wheel;
217 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
218 Evas_Coord zoom_distance_tolerance;
219 unsigned int m_st_tm; /* momentum start time */
220 unsigned int m_prev_tm; /* momentum prev time */
221 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
222 double m_base; /* zoom value when momentum starts */
225 typedef struct _Zoom_Type Zoom_Type;
228 { /* Fields used by _rotation_test() */
229 Elm_Gesture_Rotate_Info info;
230 Pointer_Event rotate_st;
231 Pointer_Event rotate_mv;
232 Pointer_Event rotate_st1;
233 Pointer_Event rotate_mv1;
234 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
235 double prev_momentum; /* Snapshot of momentum 0.01 sec ago */
236 double accum_momentum;
237 double rotate_angular_tolerance;
240 typedef struct _Rotate_Type Rotate_Type;
244 Evas_Object *target; /* Target Widget */
245 Event_History *event_history_list;
248 Evas_Coord zoom_distance_tolerance;
249 Evas_Coord line_distance_tolerance;
250 double line_angular_tolerance;
251 double zoom_wheel_factor; /* mouse wheel zoom steps */
252 double zoom_finger_factor; /* used for zoom factor */
253 double rotate_angular_tolerance;
254 unsigned int flick_time_limit_ms;
255 double long_tap_start_timeout;
256 Eina_Bool glayer_continues_enable;
261 Gesture_Info *gesture[ELM_GESTURE_LAST];
262 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
263 Eina_List *pending; /* List of devices need to refeed *UP event */
264 Eina_List *touched; /* Information of touched devices */
266 Eina_Bool repeat_events : 1;
268 typedef struct _Widget_Data Widget_Data;
270 static const char *widtype = NULL;
271 static void _del_hook(Evas_Object *obj);
273 static Eina_Bool _event_history_clear(Evas_Object *obj);
274 static void _reset_states(Widget_Data *wd);
275 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
276 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
278 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
280 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Type g_type);
281 >>>>>>> remotes/origin/upstream
282 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
283 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
284 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
285 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
287 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
288 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
289 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
291 /* START - Functions to manage touched-device list */
294 * This function is used to find if device is touched
296 * @ingroup Elm_Gesture_Layer
299 compare_device(const void *data1, const void *data2)
300 { /* Compare the two device numbers */
301 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
307 * Remove Pointer Event from touched device list
308 * @param list Pointer to touched device list.
309 * @param Pointer_Event Pointer to PE.
311 * @ingroup Elm_Gesture_Layer
314 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
316 Eina_List *lst = NULL;
317 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
320 lst = eina_list_remove(list, p);
331 * Recoed Pointer Event in touched device list
332 * Note: This fuction allocates memory for PE event
333 * This memory is released in _remove_touched_device()
334 * @param list Pointer to touched device list.
335 * @param Pointer_Event Pointer to PE.
337 * @ingroup Elm_Gesture_Layer
340 _add_touched_device(Eina_List *list, Pointer_Event *pe)
342 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
344 { /* We like to track device touch-position, overwrite info */
345 memcpy(p, pe, sizeof(Pointer_Event));
349 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
350 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN))
351 { /* Add touched device on DOWN event only */
352 p = malloc(sizeof(Pointer_Event));
353 /* Freed in _remove_touched_device() */
354 memcpy(p, pe, sizeof(Pointer_Event));
355 return eina_list_append(list, p);
360 /* END - Functions to manage touched-device list */
366 * @param event_info pointer to event.
368 * @ingroup Elm_Gesture_Layer
370 static Evas_Event_Flags
371 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
375 case EVAS_CALLBACK_MOUSE_IN:
376 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
377 case EVAS_CALLBACK_MOUSE_OUT:
378 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
379 case EVAS_CALLBACK_MOUSE_DOWN:
380 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
381 case EVAS_CALLBACK_MOUSE_MOVE:
382 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
383 case EVAS_CALLBACK_MOUSE_UP:
384 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
385 case EVAS_CALLBACK_MOUSE_WHEEL:
386 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
387 case EVAS_CALLBACK_MULTI_DOWN:
388 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
389 case EVAS_CALLBACK_MULTI_MOVE:
390 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
391 case EVAS_CALLBACK_MULTI_UP:
392 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
393 case EVAS_CALLBACK_KEY_DOWN:
394 return ((Evas_Event_Key_Down *) event_info)->event_flags;
395 case EVAS_CALLBACK_KEY_UP:
396 return ((Evas_Event_Key_Up *) event_info)->event_flags;
398 return EVAS_EVENT_FLAG_NONE;
405 * Sets event flag to value returned from user callback
406 * @param wd Widget Data
407 * @param event_info pointer to event.
408 * @param event_type what type was ev (mouse down, etc...)
409 * @param ev_flags event flags
411 * @ingroup Elm_Gesture_Layer
414 consume_event(Widget_Data *wd, void *event_info,
415 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
416 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
417 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
418 /* should not refeed this event. */
420 return; /* This happens when restarting gestures */
422 if ((ev_flags) || (!wd->repeat_events))
426 case EVAS_CALLBACK_MOUSE_DOWN:
427 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
429 case EVAS_CALLBACK_MOUSE_MOVE:
430 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
432 case EVAS_CALLBACK_MOUSE_UP:
433 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
435 case EVAS_CALLBACK_MOUSE_WHEEL:
436 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
438 case EVAS_CALLBACK_MULTI_DOWN:
439 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
441 case EVAS_CALLBACK_MULTI_MOVE:
442 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
444 case EVAS_CALLBACK_MULTI_UP:
445 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
447 case EVAS_CALLBACK_KEY_DOWN:
448 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
450 case EVAS_CALLBACK_KEY_UP:
451 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
462 * Report current state of a gesture by calling user callback.
463 * @param gesture what gesture state we report.
464 * @param info inforamtion for user callback
466 * @ingroup Elm_Gesture_Layer
468 static Evas_Event_Flags
469 _report_state(Gesture_Info *gesture, void *info)
470 { /* We report current state (START, MOVE, END, ABORT), once */
471 #if defined(DEBUG_GESTURE_LAYER)
472 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
475 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
476 (gesture->fn[gesture->state].cb))
477 { /* Fill state-info struct and send ptr to user callback */
478 return gesture->fn[gesture->state].cb(
479 gesture->fn[gesture->state].user_data, info);
482 return EVAS_EVENT_FLAG_NONE;
488 * Update state for a given gesture.
489 * We may update gesture state to:
490 * UNDEFINED - current input did not start gesure yet.
491 * START - gesture started according to input.
492 * MOVE - gusture in progress.
493 * END - gesture completed according to input.
494 * ABORT - input does not matches gesure.
495 * note that we may move from UNDEFINED to ABORT
496 * because we may detect that gesture will not START
497 * with a given input.
499 * @param g given gesture to change state.
500 * @param s gesure new state.
501 * @param info buffer to be sent to user callback on report_state.
502 * @param force makes report_state to report the new-state even
503 * if its same as current state. Works for MOVE - gesture in progress.
505 * @ingroup Elm_Gesture_Layer
507 static Evas_Event_Flags
508 _set_state(Gesture_Info *g, Elm_Gesture_State s,
509 void *info, Eina_Bool force)
511 Elm_Gesture_State old_state;
512 if ((g->state == s) && (!force))
513 return EVAS_EVENT_FLAG_NONE;
515 old_state = g->state;
518 g->info = info; /* Information for user callback */
519 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
520 (g->state == ELM_GESTURE_STATE_END))
521 g->test = EINA_FALSE;
523 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
524 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
525 (s == ELM_GESTURE_STATE_ABORT))))
526 return _report_state(g, g->info);
528 return EVAS_EVENT_FLAG_NONE;
534 * This resets all gesture states and sets test-bit.
535 * this is used for restarting gestures to listen to input.
536 * happens after we complete a gesture or no gesture was detected.
537 * @param wd Widget data of the gesture-layer object.
539 * @ingroup Elm_Gesture_Layer
542 _reset_states(Widget_Data *wd)
546 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
551 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
560 * if gesture was NOT detected AND we only have gestures in ABORT state
561 * we clear history immediately to be ready for input.
563 * @param obj The gesture-layer object.
564 * @return TRUE on event history_clear
566 * @ingroup Elm_Gesture_Layer
569 _clear_if_finished(Evas_Object *obj)
571 Widget_Data *wd = elm_widget_data_get(obj);
572 if (!wd) return EINA_FALSE;
575 /* Clear history if all we have aborted gestures */
576 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
577 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
578 { /* If no gesture started and all we have aborted gestures, reset all */
579 Gesture_Info *p = wd->gesture[i];
580 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
582 if ((p->state == ELM_GESTURE_STATE_START) ||
583 (p->state == ELM_GESTURE_STATE_MOVE))
584 reset_s = EINA_FALSE;
586 all_undefined = EINA_FALSE;
590 if (reset_s && (!all_undefined))
591 return _event_history_clear(obj);
598 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
600 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
612 _inside(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2)
614 int w = _elm_config->finger_size >> 1; /* Finger size devided by 2 */
625 >>>>>>> remotes/origin/upstream
631 /* All *test_reset() funcs are called to clear
632 * gesture intermediate data.
633 * This happens when we need to reset our tests.
634 * for example when gesture is detected or all ABORTed. */
636 _tap_gestures_test_reset(Gesture_Info *gesture)
641 Widget_Data *wd = elm_widget_data_get(gesture->obj);
642 wd->dbl_timeout = NULL;
649 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
650 EINA_LIST_FREE(data, pe)
653 memset(gesture->data, 0, sizeof(Taps_Type));
656 /* All *test_reset() funcs are called to clear
657 * gesture intermediate data.
658 * This happens when we need to reset our tests.
659 * for example when gesture is detected or all ABORTed. */
661 _n_long_tap_test_reset(Gesture_Info *gesture)
669 Long_Tap_Type *st = gesture->data;
672 EINA_LIST_FOREACH(st->touched, l, p)
676 eina_list_free(st->touched);
677 if (st->timeout) ecore_timer_del(st->timeout);
681 eina_list_free(st->touched);
684 ecore_timer_del(st->timeout);
687 >>>>>>> remotes/origin/upstream
688 memset(gesture->data, 0, sizeof(Long_Tap_Type));
692 _momentum_test_reset(Gesture_Info *gesture)
700 memset(gesture->data, 0, sizeof(Momentum_Type));
704 _line_data_reset(Line_Data *st)
709 memset(st, 0, sizeof(Line_Data));
710 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
714 _line_test_reset(Gesture_Info *gesture)
722 Line_Type *st = gesture->data;
723 Eina_List *list = st->list;
726 EINA_LIST_FOREACH(list, l, t_line)
729 eina_list_free(list);
734 _zoom_test_reset(Gesture_Info *gesture)
742 Widget_Data *wd = elm_widget_data_get(gesture->obj);
743 Zoom_Type *st = gesture->data;
744 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
745 evas_object_evas_get(wd->target), "Control");
746 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
747 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
749 memset(st, 0, sizeof(Zoom_Type));
750 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
755 _rotate_test_reset(Gesture_Info *gesture)
763 Widget_Data *wd = elm_widget_data_get(gesture->obj);
764 Rotate_Type *st = gesture->data;
766 memset(st, 0, sizeof(Rotate_Type));
767 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
768 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
775 * We register callbacks when gesture layer is attached to an object
776 * or when its enabled after disable.
778 * @param obj The gesture-layer object.
780 * @ingroup Elm_Gesture_Layer
783 _register_callbacks(Evas_Object *obj)
785 Widget_Data *wd = elm_widget_data_get(obj);
790 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
792 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
794 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
797 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
800 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
802 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
804 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
807 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
809 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
817 * We unregister callbacks when gesture layer is disabled.
819 * @param obj The gesture-layer object.
821 * @ingroup Elm_Gesture_Layer
824 _unregister_callbacks(Evas_Object *obj)
826 Widget_Data *wd = elm_widget_data_get(obj);
831 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
833 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
835 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
838 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
841 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
844 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
847 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
850 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
852 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
857 /* START - Event history list handling functions */
860 * This function is used to find if device number
861 * is found in a list of devices.
862 * The list contains devices for refeeding *UP event
864 * @ingroup Elm_Gesture_Layer
867 device_in_pending_list(const void *data1, const void *data2)
868 { /* Compare the two device numbers */
869 return (((intptr_t) data1) - ((intptr_t) data2));
875 * This functions adds device to refeed-pending device list
876 * @ingroup Elm_Gesture_Layer
879 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
881 int device = ELM_MOUSE_DEVICE;
884 case EVAS_CALLBACK_MOUSE_DOWN:
886 case EVAS_CALLBACK_MULTI_DOWN:
887 device = ((Evas_Event_Multi_Down *) event)->device;
893 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
897 return eina_list_append(list, (intptr_t*) device);
899 (void *)(intptr_t)device))
901 return eina_list_append(list, (void *)(intptr_t)device);
902 >>>>>>> remotes/origin/upstream
911 * This functions returns pending-device node
912 * @ingroup Elm_Gesture_Layer
915 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
917 int device = ELM_MOUSE_DEVICE;
920 case EVAS_CALLBACK_MOUSE_UP:
922 case EVAS_CALLBACK_MULTI_UP:
923 device = ((Evas_Event_Multi_Up *) event)->device;
929 return eina_list_search_unsorted_list(list, device_in_pending_list,
931 (intptr_t *) device);
933 (void *)(intptr_t)device);
934 >>>>>>> remotes/origin/upstream
940 * This function reports ABORT to all none-detected gestures
941 * Then resets test bits for all desired gesures
942 * and clears input-events history.
943 * note: if no gesture was detected, events from history list
944 * are streamed to the widget because it's unused by layer.
945 * user may cancel refeed of events by setting repeat events.
947 * @param obj The gesture-layer object.
949 * @ingroup Elm_Gesture_Layer
952 _event_history_clear(Evas_Object *obj)
954 Widget_Data *wd = elm_widget_data_get(obj);
955 if (!wd) return EINA_FALSE;
959 Evas *e = evas_object_evas_get(obj);
960 Eina_Bool gesture_found = EINA_FALSE;
962 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
964 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
965 >>>>>>> remotes/origin/upstream
970 if (p->state == ELM_GESTURE_STATE_END)
971 gesture_found = EINA_TRUE;
973 { /* Report ABORT to all gestures that still not finished */
974 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
980 _reset_states(wd); /* we are ready to start testing for gestures again */
982 /* Clear all gestures intermediate data */
983 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
984 { /* We do not clear a long-tap gesture if fingers still on surface */
985 /* and gesture timer still pending to test gesture state */
986 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
987 if ((st) && /* st not allocated if clear occurs before 1st input */
988 ((!eina_list_count(st->touched)) || (!st->timeout)))
989 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
994 ecore_timer_del(wd->dbl_timeout);
995 wd->dbl_timeout = NULL;
998 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
999 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1000 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1001 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
1002 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
1003 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
1004 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
1005 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
1007 /* Disable gesture layer so refeeded events won't be consumed by it */
1008 _unregister_callbacks(obj);
1009 while (wd->event_history_list)
1012 t = wd->event_history_list;
1013 Eina_List *pending = _device_is_pending(wd->pending,
1014 wd->event_history_list->event,
1015 wd->event_history_list->event_type);
1017 /* Refeed events if no gesture matched input */
1018 if (pending || ((!gesture_found) && (!wd->repeat_events)))
1020 evas_event_refeed_event(e, wd->event_history_list->event,
1021 wd->event_history_list->event_type);
1025 wd->pending = eina_list_remove_list(wd->pending, pending);
1029 wd->pending = _add_device_pending(wd->pending,
1030 wd->event_history_list->event,
1031 wd->event_history_list->event_type);
1035 free(wd->event_history_list->event);
1036 wd->event_history_list = (Event_History *) eina_inlist_remove(
1037 EINA_INLIST_GET(wd->event_history_list),
1038 EINA_INLIST_GET(wd->event_history_list));
1041 _register_callbacks(obj);
1048 * This function copies input events.
1049 * We copy event info before adding it to history.
1050 * The memory is freed when we clear history.
1052 * @param event the event to copy
1053 * @param event_type event type to copy
1055 * @ingroup Elm_Gesture_Layer
1058 _copy_event_info(void *event, Evas_Callback_Type event_type)
1062 case EVAS_CALLBACK_MOUSE_DOWN:
1063 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1065 case EVAS_CALLBACK_MOUSE_MOVE:
1066 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1068 case EVAS_CALLBACK_MOUSE_UP:
1069 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1071 case EVAS_CALLBACK_MOUSE_WHEEL:
1072 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1074 case EVAS_CALLBACK_MULTI_DOWN:
1075 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1077 case EVAS_CALLBACK_MULTI_MOVE:
1078 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1080 case EVAS_CALLBACK_MULTI_UP:
1081 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1083 case EVAS_CALLBACK_KEY_DOWN:
1084 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1086 case EVAS_CALLBACK_KEY_UP:
1087 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1095 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1097 Widget_Data *wd = elm_widget_data_get(obj);
1099 if (!wd) return EINA_FALSE;
1101 ev = malloc(sizeof(Event_History));
1102 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1103 ev->event_type = event_type;
1104 wd->event_history_list = (Event_History *) eina_inlist_append(
1105 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1109 /* END - Event history list handling functions */
1112 _del_hook(Evas_Object *obj)
1114 Widget_Data *wd = elm_widget_data_get(obj);
1117 _event_history_clear(obj);
1118 eina_list_free(wd->pending);
1120 Pointer_Event *data;
1121 EINA_LIST_FREE(wd->touched, data)
1126 >>>>>>> remotes/origin/upstream
1128 if (!elm_widget_disabled_get(obj))
1129 _unregister_callbacks(obj);
1131 /* Free all gestures internal data structures */
1133 for (i = 0; i < ELM_GESTURE_LAST; i++)
1136 if (wd->gesture[i]->data)
1137 free(wd->gesture[i]->data);
1139 free(wd->gesture[i]);
1146 compare_match_fingers(const void *data1, const void *data2)
1147 { /* Compare coords of first item in list to cur coords */
1148 const Pointer_Event *pe1 = eina_list_data_get(data1);
1149 const Pointer_Event *pe2 = data2;
1151 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1153 else if (pe1->x < pe2->x)
1157 if (pe1->x == pe2->x)
1158 return pe1->y - pe2->y;
1165 compare_pe_device(const void *data1, const void *data2)
1166 { /* Compare device of first item in list to our pe device */
1167 const Pointer_Event *pe1 = eina_list_data_get(data1);
1168 const Pointer_Event *pe2 = data2;
1170 /* Only match if last was a down event */
1171 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1172 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1178 >>>>>>> remotes/origin/upstream
1179 if (pe1->device == pe2->device)
1181 else if (pe1->device < pe2->device)
1188 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1189 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1190 { /* Keep copy of pe and record it in list */
1191 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1192 memcpy(p, pe, sizeof(Pointer_Event));
1193 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1199 /* This will also update middle-point to report to user later */
1200 st->info.x = st->sum_x / st->n_taps;
1201 st->info.y = st->sum_y / st->n_taps;
1202 st->info.timestamp = pe->timestamp;
1206 pe_list = eina_list_append(pe_list, p);
1207 st->l = eina_list_append(st->l, pe_list);
1210 pe_list = eina_list_append(pe_list, p);
1218 * This function sets state a tap-gesture to END or ABORT
1220 * @param data gesture info pointer
1222 * @ingroup Elm_Gesture_Layer
1225 _tap_gesture_finish(void *data)
1226 { /* This function will test each tap gesture when timer expires */
1227 Gesture_Info *gesture = data;
1228 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1229 /* Here we check if taps-gesture was completed successfuly */
1230 /* Count how many taps were recieved on each device then */
1231 /* determine if it matches n_taps_needed defined on START */
1232 Taps_Type *st = gesture->data;
1235 EINA_LIST_FOREACH(st->l, l, pe_list)
1237 if (eina_list_count(pe_list) != st->n_taps_needed)
1238 { /* No match taps number on device, ABORT */
1239 s = ELM_GESTURE_STATE_ABORT;
1244 st->info.n = eina_list_count(st->l);
1245 _set_state(gesture, s, gesture->info, EINA_FALSE);
1246 _tap_gestures_test_reset(gesture);
1252 * when this timer expires we finish tap gestures.
1254 * @param data The gesture-layer object.
1255 * @return cancles callback for this timer.
1257 * @ingroup Elm_Gesture_Layer
1260 _multi_tap_timeout(void *data)
1262 Widget_Data *wd = elm_widget_data_get(data);
1263 if (!wd) return EINA_FALSE;
1265 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1266 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1268 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1269 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1271 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1272 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1274 _clear_if_finished(data);
1275 wd->dbl_timeout = NULL;
1276 return ECORE_CALLBACK_CANCEL;
1282 * when this timer expires we START long tap gesture
1284 * @param data The gesture-layer object.
1285 * @return cancles callback for this timer.
1287 * @ingroup Elm_Gesture_Layer
1290 _long_tap_timeout(void *data)
1292 Gesture_Info *gesture = data;
1293 Long_Tap_Type *st = gesture->data;
1296 _set_state(gesture, ELM_GESTURE_STATE_START,
1297 gesture->data, EINA_FALSE);
1299 return ECORE_CALLBACK_CANCEL;
1306 * This function checks if a tap gesture should start
1308 * @param wd Gesture Layer Widget Data.
1309 * @param pe The recent input event as stored in pe struct.
1310 * @param event_info Original input event pointer.
1311 * @param event_type Type of original input event.
1312 * @param gesture what gesture is tested
1313 * @param how many taps for this gesture (1, 2 or 3)
1315 * @return Flag to determine if we need to set a timer for finish
1317 * @ingroup Elm_Gesture_Layer
1320 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1321 void *event_info, Evas_Callback_Type event_type,
1322 Gesture_Info *gesture, int taps)
1323 { /* Here we fill Tap struct */
1324 Taps_Type *st = gesture->data;
1326 { /* Allocated once on first time */
1327 st = calloc(1, sizeof(Taps_Type));
1329 _tap_gestures_test_reset(gesture);
1332 Eina_List *pe_list = NULL;
1333 Pointer_Event *pe_down = NULL;
1334 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1335 switch (pe->event_type)
1337 case EVAS_CALLBACK_MULTI_DOWN:
1338 case EVAS_CALLBACK_MOUSE_DOWN:
1339 /* Check if got tap on same cord was tapped before */
1340 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1343 eina_list_search_unsorted(st->l, compare_pe_device, pe))
1344 { /* This device was touched in other cord before completion */
1345 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1346 &st->info, EINA_FALSE);
1347 consume_event(wd, event_info, event_type, ev_flag);
1352 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1353 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1354 { /* This is the first mouse down we got */
1355 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1356 &st->info, EINA_FALSE);
1357 consume_event(wd, event_info, event_type, ev_flag);
1359 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1366 case EVAS_CALLBACK_MULTI_UP:
1367 case EVAS_CALLBACK_MOUSE_UP:
1368 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1372 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1375 case EVAS_CALLBACK_MULTI_MOVE:
1376 case EVAS_CALLBACK_MOUSE_MOVE:
1377 /* Get first event in first list, this has to be a Mouse Down event */
1378 /* and verify that user didn't move out of this area before next tap */
1379 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1382 pe_down = eina_list_data_get(pe_list);
1383 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1385 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1386 &st->info, EINA_FALSE);
1387 consume_event(wd, event_info, event_type, ev_flag);
1403 * This function checks all click/tap and double/triple taps
1405 * @param obj The gesture-layer object.
1406 * @param pe The recent input event as stored in pe struct.
1407 * @param event_info Original input event pointer.
1408 * @param event_type Type of original input event.
1410 * @ingroup Elm_Gesture_Layer
1413 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1414 void *event_info, Evas_Callback_Type event_type)
1415 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1416 Eina_Bool need_timer = EINA_FALSE;
1417 Widget_Data *wd = elm_widget_data_get(obj);
1420 if (!pe) /* this happens when unhandled event arrived */
1421 return; /* see _make_pointer_event function */
1423 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1424 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1425 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1427 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1428 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1429 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1431 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1432 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1433 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1435 if ((need_timer) && (!wd->dbl_timeout))
1436 { /* Set a timer to finish these gestures */
1437 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1445 * This function computes center-point for long-tap gesture
1447 * @param st Long Tap gesture info pointer
1448 * @param pe The recent input event as stored in pe struct.
1450 * @ingroup Elm_Gesture_Layer
1453 _compute_taps_center(Long_Tap_Type *st,
1454 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1456 if(!eina_list_count(st->touched))
1461 Evas_Coord x = 0, y = 0;
1462 EINA_LIST_FOREACH(st->touched, l, p)
1463 { /* Accumulate all then take avarage */
1464 if (p->device == pe->device)
1465 { /* This will take care of values coming from MOVE event */
1476 *x_out = x / eina_list_count(st->touched);
1477 *y_out = y / eina_list_count(st->touched);
1483 * This function checks N long-tap gesture.
1485 * @param obj The gesture-layer object.
1486 * @param pe The recent input event as stored in pe struct.
1487 * @param event_info Original input event pointer.
1488 * @param event_type Type of original input event.
1489 * @param g_type what Gesture we are testing.
1490 * @param taps How many click/taps we test for.
1492 * @ingroup Elm_Gesture_Layer
1495 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1496 void *event_info, Evas_Callback_Type event_type,
1498 Elm_Gesture_Types g_type)
1500 Elm_Gesture_Type g_type)
1501 >>>>>>> remotes/origin/upstream
1502 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1503 Widget_Data *wd = elm_widget_data_get(obj);
1506 if (!pe) /* this happens when unhandled event arrived */
1507 return; /* see _make_pointer_event function */
1508 Gesture_Info *gesture = wd->gesture[g_type];
1509 if (!gesture) return;
1511 Long_Tap_Type *st = gesture->data;
1513 { /* Allocated once on first time */
1514 st = calloc(1, sizeof(Long_Tap_Type));
1516 _n_long_tap_test_reset(gesture);
1519 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1520 switch (pe->event_type)
1522 case EVAS_CALLBACK_MULTI_DOWN:
1523 case EVAS_CALLBACK_MOUSE_DOWN:
1524 st->touched = _add_touched_device(st->touched, pe);
1525 st->info.n = eina_list_count(st->touched);
1526 if (st->info.n > st->max_touched)
1527 st->max_touched = st->info.n;
1529 { /* User removed finger from touch, then put back - ABORT */
1530 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1531 (gesture->state == ELM_GESTURE_STATE_MOVE))
1533 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1534 &st->info, EINA_FALSE);
1535 consume_event(wd, event_info, event_type, ev_flag);
1539 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1540 { /* This is the first mouse down we got */
1541 st->info.timestamp = pe->timestamp;
1543 /* To test long tap */
1544 /* When this timer expires, gesture STARTED */
1546 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1547 _long_tap_timeout, gesture);
1550 consume_event(wd, event_info, event_type, ev_flag);
1551 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1552 st->center_x = st->info.x;
1553 st->center_y = st->info.y;
1556 case EVAS_CALLBACK_MULTI_UP:
1557 case EVAS_CALLBACK_MOUSE_UP:
1558 st->touched = _remove_touched_device(st->touched, pe);
1559 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1561 ((gesture->state == ELM_GESTURE_STATE_START) ||
1562 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1563 { /* Report END only for gesture that STARTed */
1564 if (eina_list_count(st->touched) == 0)
1565 { /* Report END only at last release event */
1566 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1567 &st->info, EINA_FALSE);
1568 consume_event(wd, event_info, event_type, ev_flag);
1572 { /* Stop test, user lifts finger before long-start */
1573 if (st->timeout) ecore_timer_del(st->timeout);
1575 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1576 &st->info, EINA_FALSE);
1577 consume_event(wd, event_info, event_type, ev_flag);
1582 case EVAS_CALLBACK_MULTI_MOVE:
1583 case EVAS_CALLBACK_MOUSE_MOVE:
1585 ((gesture->state == ELM_GESTURE_STATE_START) ||
1586 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1587 { /* Report MOVE only if STARTED */
1590 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1592 _compute_taps_center(st, &x, &y, pe);
1593 /* ABORT if user moved fingers out of tap area */
1594 #if defined(DEBUG_GESTURE_LAYER)
1595 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1597 if (!_inside(x, y, st->center_x, st->center_y))
1598 state_to_report = ELM_GESTURE_STATE_ABORT;
1600 /* Report MOVE if gesture started */
1601 ev_flag = _set_state(gesture, state_to_report,
1602 &st->info, EINA_TRUE);
1603 consume_event(wd, event_info, event_type, ev_flag);
1615 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1616 * This momentum value will be sent to widget when gesture is completed.
1618 * @param momentum pointer to buffer where we record momentum value.
1619 * @param x1 x coord where user started gesture.
1620 * @param y1 y coord where user started gesture.
1621 * @param x2 x coord where user completed gesture.
1622 * @param y2 y coord where user completed gesture.
1623 * @param t1x timestamp for X, when user started gesture.
1624 * @param t1y timestamp for Y, when user started gesture.
1625 * @param t2 timestamp when user completed gesture.
1627 * @ingroup Elm_Gesture_Layer
1631 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1632 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1635 Evas_Coord velx = 0, vely = 0, vel;
1636 Evas_Coord dx = x2 - x1;
1637 Evas_Coord dy = y2 - y1;
1639 _set_momentum(Elm_Gesture_Momentum_Info *momentum,
1640 Evas_Coord xx1, Evas_Coord yy1,
1641 Evas_Coord xx2, Evas_Coord yy2,
1642 unsigned int t1x, unsigned int t1y, unsigned int t2)
1644 Evas_Coord velx = 0, vely = 0, vel;
1645 Evas_Coord dx = xx2 - xx1;
1646 Evas_Coord dy = yy2 - yy1;
1647 >>>>>>> remotes/origin/upstream
1651 velx = (dx * 1000) / dtx;
1654 vely = (dy * 1000) / dty;
1656 vel = sqrt((velx * velx) + (vely * vely));
1658 if ((_elm_config->thumbscroll_friction > 0.0) &&
1659 (vel > _elm_config->thumbscroll_momentum_threshold))
1660 { /* report momentum */
1661 momentum->mx = velx;
1662 momentum->my = vely;
1674 * This function is used for computing rotation angle (DEG).
1676 * @param x1 first finger x location.
1677 * @param y1 first finger y location.
1678 * @param x2 second finger x location.
1679 * @param y2 second finger y location.
1681 * @return angle of the line between (x1,y1), (x2,y2) in Deg.
1682 * Angles now are given in DEG, not RAD.
1683 * ZERO angle at 12-oclock, growing clockwise.
1685 * @ingroup Elm_Gesture_Layer
1689 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1691 double a, xx, yy, rt = (-1);
1695 if (((int) xx) && ((int) yy))
1697 rt = a = RAD2DEG(atan(yy / xx));
1720 get_angle(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2)
1722 double a, xx, yy, rt = (-1);
1723 xx = fabs(xx2 - xx1);
1724 yy = fabs(yy2 - yy1);
1726 if (((int)xx) && ((int)yy))
1728 rt = a = RAD2DEG(atan(yy / xx));
1731 if (yy1 < yy2) rt = 360 - a;
1736 if (yy1 < yy2) rt = 180 + a;
1738 >>>>>>> remotes/origin/upstream
1743 { /* Do this only if rt is not set */
1746 { /* Horizontal line */
1757 { /* Vertical line */
1768 { /* Horizontal line */
1769 if (xx2 < xx1) rt = 180;
1773 { /* Vertical line */
1774 if (yy2 < yy1) rt = 90;
1776 >>>>>>> remotes/origin/upstream
1780 /* Now we want to change from:
1782 * original circle 180 0 We want: 270 90
1792 if (rt >= 360) rt -= 360;
1793 >>>>>>> remotes/origin/upstream
1801 * This function is used for computing the magnitude and direction
1802 * of vector between two points.
1804 * @param x1 first finger x location.
1805 * @param y1 first finger y location.
1806 * @param x2 second finger x location.
1807 * @param y2 second finger y location.
1808 * @param l length computed (output)
1809 * @param a angle computed (output)
1811 * @ingroup Elm_Gesture_Layer
1815 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1816 Evas_Coord *l, double *a)
1821 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1822 *a = get_angle(x1, y1, x2, y2);
1826 _get_direction(Evas_Coord x1, Evas_Coord x2)
1835 get_vector(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2,
1836 Evas_Coord *l, double *a)
1841 *l = (Evas_Coord) sqrt((xx * xx) + (yy * yy));
1842 *a = get_angle(xx1, yy1, xx2, yy2);
1846 _get_direction(Evas_Coord xx1, Evas_Coord xx2)
1848 if (xx2 < xx1) return -1;
1849 if (xx2 > xx1) return 1;
1850 >>>>>>> remotes/origin/upstream
1856 * This function tests momentum gesture.
1857 * @param obj The gesture-layer object.
1858 * @param pe The recent input event as stored in pe struct.
1859 * @param event_info recent input event.
1860 * @param event_type recent event type.
1861 * @param g_type what Gesture we are testing.
1863 * @ingroup Elm_Gesture_Layer
1866 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1868 void *event_info, Evas_Callback_Type event_type,
1869 Elm_Gesture_Types g_type)
1871 void *event_info, Evas_Callback_Type event_type,
1872 Elm_Gesture_Type g_type)
1873 >>>>>>> remotes/origin/upstream
1875 Widget_Data *wd = elm_widget_data_get(obj);
1877 Gesture_Info *gesture = wd->gesture[g_type];
1878 if (!gesture ) return;
1880 /* When continues enable = TRUE a gesture may START on MOVE event */
1881 /* We don't allow this to happen with the if-statement below. */
1882 /* When continues enable = FALSE a gesture may START on DOWN only */
1883 /* Therefor it would NOT start on MOVE event. */
1884 /* NOTE that touched list is updated AFTER this function returns */
1885 /* so (count == 0) when we get here on first touch on surface. */
1886 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1887 return; /* Got move on mouse-over move */
1889 Momentum_Type *st = gesture->data;
1890 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1892 { /* Allocated once on first time */
1893 st = calloc(1, sizeof(Momentum_Type));
1895 _momentum_test_reset(gesture);
1901 /* First make avarage of all touched devices to determine center point */
1904 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1905 unsigned int cnt = 1; /* We start counter counting current pe event */
1906 EINA_LIST_FOREACH(wd->touched, l, p)
1907 if (p->device != pe_local.device)
1915 /* Compute avarage to get center point */
1919 /* If user added finger - reset gesture */
1920 if ((st->info.n) && (st->info.n < cnt))
1921 state_to_report = ELM_GESTURE_STATE_ABORT;
1924 if (st->info.n < cnt)
1927 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1930 case EVAS_CALLBACK_MOUSE_DOWN:
1931 case EVAS_CALLBACK_MULTI_DOWN:
1932 case EVAS_CALLBACK_MOUSE_MOVE:
1933 case EVAS_CALLBACK_MULTI_MOVE:
1936 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1937 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1938 (wd->glayer_continues_enable)) /* start also on MOVE */
1939 { /* We start on MOVE when cont-enabled only */
1940 st->line_st.x = st->line_end.x = pe_local.x;
1941 st->line_st.y = st->line_end.y = pe_local.y;
1942 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1943 st->xdir = st->ydir = 0;
1944 st->info.x2 = st->info.x1 = pe_local.x;
1945 st->info.y2 = st->info.y1 = pe_local.y;
1946 st->info.tx = st->info.ty = pe_local.timestamp;
1947 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1948 &st->info, EINA_FALSE);
1949 consume_event(wd, event_info, event_type, ev_flag);
1958 Eina_Bool force = EINA_TRUE; /* for move state */
1959 if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
1960 { /* ABORT if got DOWN or MOVE event after UP+timeout */
1961 state_to_report = ELM_GESTURE_STATE_ABORT;
1965 /* We report state but don't compute momentum now */
1966 ev_flag = _set_state(gesture, state_to_report, &st->info,
1968 consume_event(wd, event_info, event_type, ev_flag);
1969 return; /* Stop computing when user remove finger */
1972 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1973 { /* Too long of a wait, reset all values */
1974 st->line_st.x = pe_local.x;
1975 st->line_st.y = pe_local.y;
1976 st->t_st_y = st->t_st_x = pe_local.timestamp;
1977 st->info.tx = st->t_st_x;
1978 st->info.ty = st->t_st_y;
1979 st->xdir = st->ydir = 0;
1984 xdir = _get_direction(st->line_end.x, pe_local.x);
1985 ydir = _get_direction(st->line_end.y, pe_local.y);
1986 if (xdir && (xdir != st->xdir))
1988 st->line_st.x = st->line_end.x;
1989 st->info.tx = st->t_st_x = st->t_end;
1993 if (ydir && (ydir != st->ydir))
1995 st->line_st.y = st->line_end.y;
1996 st->info.ty = st->t_st_y = st->t_end;
2001 st->info.x2 = st->line_end.x = pe_local.x;
2002 st->info.y2 = st->line_end.y = pe_local.y;
2003 st->t_end = pe_local.timestamp;
2004 _set_momentum(&st->info, st->line_st.x, st->line_st.y,
2005 pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2006 pe_local.timestamp);
2008 ev_flag = _set_state(gesture, state_to_report, &st->info,
2010 consume_event(wd, event_info, event_type, ev_flag);
2014 case EVAS_CALLBACK_MOUSE_UP:
2015 case EVAS_CALLBACK_MULTI_UP:
2016 st->t_up = pe_local.timestamp; /* Record recent up event time */
2017 if ((cnt > 1) || /* Ignore if more fingers touch surface */
2018 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2021 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2022 { /* Too long of a wait, reset all values */
2023 st->line_st.x = pe_local.x;
2024 st->line_st.y = pe_local.y;
2025 st->t_st_y = st->t_st_x = pe_local.timestamp;
2026 st->xdir = st->ydir = 0;
2029 st->info.x2 = pe_local.x;
2030 st->info.y2 = pe_local.y;
2031 st->line_end.x = pe_local.x;
2032 st->line_end.y = pe_local.y;
2033 st->t_end = pe_local.timestamp;
2035 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2036 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2037 state_to_report = ELM_GESTURE_STATE_END;
2039 state_to_report = ELM_GESTURE_STATE_ABORT;
2041 ev_flag = _set_state(gesture, state_to_report, &st->info,
2043 consume_event(wd, event_info, event_type, ev_flag);
2052 compare_line_device(const void *data1, const void *data2)
2053 { /* Compare device component of line struct */
2054 const Line_Data *ln1 = data1;
2055 const int *device = data2;
2057 if (ln1->t_st) /* Compare only with lines that started */
2058 return (ln1->device - (*device));
2066 * This function construct line struct from input.
2067 * @param info pointer to store line momentum.
2068 * @param st line info to store input data.
2069 * @param pe The recent input event as stored in pe struct.
2071 * @ingroup Elm_Gesture_Layer
2074 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
2075 Pointer_Event *pe, Evas_Callback_Type event_type)
2076 { /* Record events and set momentum for line pointed by st */
2082 case EVAS_CALLBACK_MOUSE_DOWN:
2083 case EVAS_CALLBACK_MOUSE_MOVE:
2084 case EVAS_CALLBACK_MULTI_DOWN:
2085 case EVAS_CALLBACK_MULTI_MOVE:
2087 { /* This happens only when line starts */
2088 st->line_st.x = pe->x;
2089 st->line_st.y = pe->y;
2090 st->t_st = pe->timestamp;
2091 st->device = pe->device;
2092 info->momentum.x1 = pe->x;
2093 info->momentum.y1 = pe->y;
2094 info->momentum.tx = pe->timestamp;
2095 info->momentum.ty = pe->timestamp;
2102 case EVAS_CALLBACK_MOUSE_UP:
2103 case EVAS_CALLBACK_MULTI_UP:
2104 /* IGNORE if line info was cleared, like long press, move */
2108 st->line_end.x = pe->x;
2109 st->line_end.y = pe->y;
2110 st->t_end = pe->timestamp;
2119 _line_data_reset(st);
2123 info->momentum.x2 = pe->x;
2124 info->momentum.y2 = pe->y;
2125 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2126 st->t_st, st->t_st, pe->timestamp);
2134 * This function test for (n) line gesture.
2135 * @param obj The gesture-layer object.
2136 * @param pe The recent input event as stored in pe struct.
2137 * @param event_info Original input event pointer.
2138 * @param event_type Type of original input event.
2139 * @param g_type what Gesture we are testing.
2141 * @ingroup Elm_Gesture_Layer
2144 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2146 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2148 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2149 >>>>>>> remotes/origin/upstream
2153 Widget_Data *wd = elm_widget_data_get(obj);
2155 Gesture_Info *gesture = wd->gesture[g_type];
2156 if (!gesture ) return;
2158 /* When continues enable = TRUE a gesture may START on MOVE event */
2159 /* We don't allow this to happen with the if-statement below. */
2160 /* When continues enable = FALSE a gesture may START on DOWN only */
2161 /* Therefor it would NOT start on MOVE event. */
2162 /* NOTE that touched list is updated AFTER this function returns */
2163 /* so (count == 0) when we get here on first touch on surface. */
2164 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
2165 return; /* Got move on mouse-over move */
2167 Line_Type *st = gesture->data;
2170 st = calloc(1, sizeof(Line_Type));
2174 Line_Data *line = NULL;
2175 Eina_List *list = st->list;
2176 unsigned cnt = eina_list_count(list);
2179 { /* list is not empty, locate this device on list */
2180 line = (Line_Data *) eina_list_search_unsorted(st->list,
2181 compare_line_device, &pe->device);
2185 { /* List is empty or device not found, new line-struct on START only */
2186 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2187 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2188 ((wd->glayer_continues_enable) && /* START on MOVE also */
2189 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2190 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2191 { /* Allocate new item on START only */
2192 line = calloc(1, sizeof(Line_Data));
2193 _line_data_reset(line);
2194 list = eina_list_append(list, line);
2199 if (!line) /* This may happen on MOVE that comes before DOWN */
2200 return; /* No line-struct to work with, can't continue testing */
2202 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2203 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2205 /* Get direction and magnitude of the line */
2207 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2208 &line->line_length, &angle);
2210 /* These are used later to compare lines length */
2211 Evas_Coord shortest_line_len = line->line_length;
2212 Evas_Coord longest_line_len = line->line_length;
2213 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2215 /* Now update line-state */
2217 { /* Analyze line only if line started */
2218 if (line->line_angle >= 0.0)
2219 { /* if line direction was set, we test if broke tolerance */
2220 double a = fabs(angle - line->line_angle);
2222 double d = (tan(DEG2RAD(a))) * line->line_length; /* Distance from line */
2223 #if defined(DEBUG_GESTURE_LAYER)
2224 printf("%s a=<%f> d=<%f>\n", __func__, a, d);
2226 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2227 { /* Broke tolerance: abort line and start a new one */
2228 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2229 &st->info, EINA_FALSE);
2230 consume_event(wd, event_info, event_type, ev_flag);
2234 if (wd->glayer_continues_enable)
2235 { /* We may finish line if momentum is zero */
2236 /* This is for continues-gesture */
2237 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2238 { /* Finish line on zero momentum for continues gesture */
2239 line->line_end.x = pe->x;
2240 line->line_end.y = pe->y;
2241 line->t_end = pe->timestamp;
2246 { /* Record the line angle as it broke minimum length for line */
2247 if (line->line_length >= wd->line_min_length)
2248 st->info.angle = line->line_angle = angle;
2254 if (line->line_angle < 0.0)
2255 { /* it's not a line, too short more close to a tap */
2256 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2257 &st->info, EINA_FALSE);
2258 consume_event(wd, event_info, event_type, ev_flag);
2264 /* Count how many lines already started / ended */
2267 unsigned int tm_start = pe->timestamp;
2268 unsigned int tm_end = pe->timestamp;
2271 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2272 Eina_Bool lines_parallel = EINA_TRUE;
2273 EINA_LIST_FOREACH(list, l, t_line)
2276 base_angle = t_line->line_angle;
2279 if (t_line->line_angle >= 0)
2280 { /* Compare angle only with lines with direction defined */
2281 if (fabs(base_angle - t_line->line_angle) >
2282 wd->line_angular_tolerance)
2283 lines_parallel = EINA_FALSE;
2287 if (t_line->line_length)
2288 { /* update only if this line is used */
2289 if (shortest_line_len > t_line->line_length)
2290 shortest_line_len = t_line->line_length;
2292 if (longest_line_len < t_line->line_length)
2293 longest_line_len = t_line->line_length;
2299 if (t_line->t_st < tm_start)
2300 tm_start = t_line->t_st;
2306 if (t_line->t_end < tm_end)
2307 tm_end = t_line->t_end;
2311 st->info.momentum.n = started;
2315 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2316 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2317 { /* user lift one finger then starts again without line-end - ABORT */
2318 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2320 consume_event(wd, event_info, event_type, ev_flag);
2324 if (!lines_parallel)
2325 { /* Lines are NOT at same direction, abort this gesture */
2326 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2328 consume_event(wd, event_info, event_type, ev_flag);
2333 /* We report ABORT if lines length are NOT matching when fingers are up */
2335 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2337 if ((longest_line_len - shortest_line_len) > (_elm_config->finger_size * 2))
2338 >>>>>>> remotes/origin/upstream
2340 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2342 consume_event(wd, event_info, event_type, ev_flag);
2346 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2347 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2348 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2350 consume_event(wd, event_info, event_type, ev_flag);
2356 case EVAS_CALLBACK_MOUSE_UP:
2357 case EVAS_CALLBACK_MULTI_UP:
2358 if ((started) && (started == ended))
2360 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2361 &st->info, EINA_FALSE);
2362 consume_event(wd, event_info, event_type, ev_flag);
2367 case EVAS_CALLBACK_MOUSE_DOWN:
2368 case EVAS_CALLBACK_MULTI_DOWN:
2369 case EVAS_CALLBACK_MOUSE_MOVE:
2370 case EVAS_CALLBACK_MULTI_MOVE:
2373 if (wd->glayer_continues_enable && (started == ended))
2374 { /* For continues gesture */
2375 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2376 &st->info, EINA_FALSE);
2377 consume_event(wd, event_info, event_type, ev_flag);
2380 { /* When continues, may START on MOVE event too */
2381 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2383 /* This happens when: on n > 1 lines then one finger up */
2384 /* caused abort, then put finger down. */
2385 /* This will stop line from starting again. */
2386 /* Number of lines, MUST match touched-device in list */
2387 if ((!wd->glayer_continues_enable) &&
2388 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2389 s = ELM_GESTURE_STATE_ABORT;
2391 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2392 s = ELM_GESTURE_STATE_START;
2394 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2395 consume_event(wd, event_info, event_type, ev_flag);
2401 return; /* Unhandeld event type */
2408 * This function is used to check if rotation gesture started.
2409 * @param st Contains current rotation values from user input.
2410 * @return TRUE/FALSE if we need to set rotation START.
2412 * @ingroup Elm_Gesture_Layer
2415 rotation_broke_tolerance(Rotate_Type *st)
2417 if (st->info.base_angle < 0)
2418 return EINA_FALSE; /* Angle has to be computed first */
2420 if (st->rotate_angular_tolerance < 0)
2423 double low = st->info.base_angle - st->rotate_angular_tolerance;
2424 double high = st->info.base_angle + st->rotate_angular_tolerance;
2425 double t = st->info.angle;
2449 #if defined(DEBUG_GESTURE_LAYER)
2450 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2452 if ((t < low) || (t > high))
2453 { /* This marks that roation action has started */
2454 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2455 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2465 * This function is used for computing the gap between fingers.
2466 * It returns the length and center point between fingers.
2468 * @param x1 first finger x location.
2469 * @param y1 first finger y location.
2470 * @param x2 second finger x location.
2471 * @param y2 second finger y location.
2472 * @param x Gets center point x cord (output)
2473 * @param y Gets center point y cord (output)
2475 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2477 * @ingroup Elm_Gesture_Layer
2481 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2482 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2484 double a, b, xx, yy, gap;
2487 gap = sqrt(xx*xx + yy*yy);
2489 get_finger_gap_length(Evas_Coord xx1, Evas_Coord yy1,
2490 Evas_Coord xx2, Evas_Coord yy2,
2491 Evas_Coord *x, Evas_Coord *y)
2493 double a, b, xx, yy, gap;
2494 xx = fabs(xx2 - xx1);
2495 yy = fabs(yy2 - yy1);
2496 gap = sqrt((xx * xx) + (yy * yy));
2497 >>>>>>> remotes/origin/upstream
2499 /* START - Compute zoom center point */
2500 /* The triangle defined as follows:
2508 * http://en.wikipedia.org/wiki/Trigonometric_functions
2509 *************************************/
2511 if (((int) xx) && ((int) yy))
2513 if (((int)xx) && ((int)yy))
2514 >>>>>>> remotes/origin/upstream
2516 double A = atan((yy / xx));
2517 #if defined(DEBUG_GESTURE_LAYER)
2518 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2520 a = (Evas_Coord) ((gap / 2) * sin(A));
2521 b = (Evas_Coord) ((gap / 2) * cos(A));
2523 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2524 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2530 *x = (Evas_Coord) ((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
2531 *y = (Evas_Coord) ((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
2536 >>>>>>> remotes/origin/upstream
2537 { /* horiz line, take half width */
2538 #if defined(DEBUG_GESTURE_LAYER)
2539 printf("==== HORIZ ====\n");
2542 *x = (Evas_Coord) (xx / 2);
2543 *y = (Evas_Coord) (y1);
2548 *x = (Evas_Coord) ((xx1 + xx2) / 2);
2549 *y = (Evas_Coord) (yy1);
2553 >>>>>>> remotes/origin/upstream
2554 { /* vert line, take half width */
2555 #if defined(DEBUG_GESTURE_LAYER)
2556 printf("==== VERT ====\n");
2559 *x = (Evas_Coord) (x1);
2560 *y = (Evas_Coord) (yy / 2);
2562 *x = (Evas_Coord) (xx1);
2563 *y = (Evas_Coord) ((yy1 + yy2) / 2);
2564 >>>>>>> remotes/origin/upstream
2567 /* END - Compute zoom center point */
2569 return (Evas_Coord) gap;
2575 * This function is used for computing zoom value.
2577 * @param st Pointer to zoom data based on user input.
2578 * @param tm_end Recent input event timestamp.
2579 * @param zoom_val Current computed zoom value.
2581 * @return zoom momentum
2583 * @ingroup Elm_Gesture_Layer
2586 _zoom_momentum_get(Zoom_Type *st, unsigned int tm_end, double zoom_val)
2588 unsigned int tm_total;
2590 { /* Init, and we don't start computing momentum yet */
2591 st->m_st_tm = st->m_prev_tm = tm_end;
2592 st->m_base = zoom_val;
2596 if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
2597 return 0.0; /* we don't start to compute momentum yet */
2600 { /* if direction was already defined, check if changed */
2601 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2602 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2603 { /* Direction changed, reset momentum */
2605 st->dir = (-st->dir);
2610 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2612 if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
2614 st->m_st_tm = 0; /* Rest momentum when waiting too long */
2618 st->m_prev_tm = tm_end;
2619 tm_total = tm_end - st->m_st_tm;
2622 return ((zoom_val - st->m_base) * 1000) / tm_total;
2630 * This function is used for computing zoom value.
2632 * @param st Pointer to zoom data based on user input.
2633 * @param x1 first finger x location.
2634 * @param y1 first finger y location.
2635 * @param x2 second finger x location.
2636 * @param y2 second finger y location.
2637 * @param factor zoom-factor, used to determine how fast zoom works.
2639 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2641 * @ingroup Elm_Gesture_Layer
2645 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1,
2646 Evas_Coord x2, Evas_Coord y2, double zoom_finger_factor)
2649 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2650 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2652 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2653 &st->info.x, &st->info.y);
2655 compute_zoom(Zoom_Type *st,
2656 Evas_Coord xx1, Evas_Coord yy1,
2657 Evas_Coord xx2, Evas_Coord yy2,
2658 double zoom_finger_factor)
2661 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2662 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2664 Evas_Coord diam = get_finger_gap_length(xx1, yy1, xx2, yy2,
2665 &st->info.x, &st->info.y);
2666 >>>>>>> remotes/origin/upstream
2668 st->info.radius = diam / 2;
2672 st->zoom_base = diam;
2673 return st->info.zoom;
2676 if (st->zoom_distance_tolerance)
2677 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2678 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2679 { /* avoid jump with zoom value when break tolerance */
2680 st->zoom_base -= st->zoom_distance_tolerance;
2681 st->zoom_distance_tolerance = 0;
2684 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2685 { /* avoid jump with zoom value when break tolerance */
2686 st->zoom_base += st->zoom_distance_tolerance;
2687 st->zoom_distance_tolerance = 0;
2693 /* We use factor only on the difference between gap-base */
2694 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2695 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2697 (float) st->zoom_base) * zoom_finger_factor));
2699 (float) st->zoom_base) * zoom_finger_factor));
2700 >>>>>>> remotes/origin/upstream
2702 /* Momentum: zoom per second: */
2703 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
2711 * This function handles zoom with mouse wheel.
2712 * thats a combination of wheel + CTRL key.
2713 * @param obj The gesture-layer object.
2714 * @param event_info Original input event pointer.
2715 * @param event_type Type of original input event.
2716 * @param g_type what Gesture we are testing.
2718 * @ingroup Elm_Gesture_Layer
2721 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2723 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2725 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2726 >>>>>>> remotes/origin/upstream
2728 Widget_Data *wd = elm_widget_data_get(obj);
2730 if (!wd->gesture[g_type]) return;
2732 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2733 Zoom_Type *st = gesture_zoom->data;
2734 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2736 { /* Allocated once on first time, used for zoom intermediate data */
2737 st = calloc(1, sizeof(Zoom_Type));
2738 gesture_zoom->data = st;
2739 _zoom_test_reset(gesture_zoom);
2744 case EVAS_CALLBACK_KEY_UP:
2746 Evas_Event_Key_Up *p = event_info;
2747 if ((!strcmp(p->keyname, "Control_L")) ||
2748 (!strcmp(p->keyname, "Control_R")))
2749 { /* Test if we ended a zoom gesture when releasing CTRL */
2750 if ((st->zoom_wheel) &&
2751 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2752 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2753 { /* User released CTRL after zooming */
2754 st->info.momentum = _zoom_momentum_get(st,
2755 p->timestamp, st->info.zoom);
2757 ev_flag = _set_state(gesture_zoom,
2758 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2759 consume_event(wd, event_info, event_type, ev_flag);
2767 case EVAS_CALLBACK_MOUSE_WHEEL:
2770 Elm_Gesture_State s;
2771 if (!evas_key_modifier_is_set(
2772 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2774 { /* if using wheel witout CTRL after starting zoom */
2775 if ((st->zoom_wheel) &&
2776 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2777 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2779 ev_flag = _set_state(gesture_zoom,
2780 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2781 consume_event(wd, event_info, event_type, ev_flag);
2786 return; /* Ignore mouse-wheel without control */
2789 /* Using mouse wheel with CTRL for zoom */
2790 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2791 { /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2792 we continue a zoom gesture */
2794 s = ELM_GESTURE_STATE_MOVE;
2797 { /* On first wheel event, report START */
2798 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2799 evas_object_evas_get(wd->target), "Control");
2801 s = ELM_GESTURE_STATE_START;
2802 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2803 ERR("Failed to Grabbed CTRL_L");
2804 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2805 ERR("Failed to Grabbed CTRL_R");
2808 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2809 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2810 st->info.x = st->zoom_wheel->canvas.x;
2811 st->info.y = st->zoom_wheel->canvas.y;
2813 if (st->zoom_wheel->z < 0) /* zoom in */
2814 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2816 if (st->zoom_wheel->z > 0) /* zoom out */
2817 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2819 if (st->info.zoom < 0.0)
2820 st->info.zoom = 0.0;
2822 st->info.momentum = _zoom_momentum_get(st,
2823 st->zoom_wheel->timestamp, st->info.zoom);
2825 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2826 consume_event(wd, event_info, event_type, ev_flag);
2838 * This function is used to test zoom gesture.
2839 * user may combine zoom, rotation together.
2840 * so its possible that both will be detected from input.
2841 * (both are two-finger movement-oriented gestures)
2843 * @param obj The gesture-layer object.
2844 * @param event_info Pointer to recent input event.
2845 * @param event_type Recent input event type.
2846 * @param g_type what Gesture we are testing.
2848 * @ingroup Elm_Gesture_Layer
2851 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2853 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2855 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2856 >>>>>>> remotes/origin/upstream
2860 Widget_Data *wd = elm_widget_data_get(obj);
2862 if (!wd->gesture[g_type]) return;
2864 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2865 Zoom_Type *st = gesture_zoom->data;
2868 { /* Allocated once on first time, used for zoom data */
2869 st = calloc(1, sizeof(Zoom_Type));
2870 gesture_zoom->data = st;
2871 _zoom_test_reset(gesture_zoom);
2875 /* Start - new zoom testing, letting all fingers start */
2876 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2879 case EVAS_CALLBACK_MOUSE_MOVE:
2880 case EVAS_CALLBACK_MULTI_MOVE:
2881 /* if non-continues mode and gesture NOT started, ignore MOVE */
2882 if ((!wd->glayer_continues_enable) &&
2883 (!st->zoom_st.timestamp))
2886 case EVAS_CALLBACK_MOUSE_DOWN:
2887 case EVAS_CALLBACK_MULTI_DOWN:
2888 { /* Here we take care of zoom-start and zoom move */
2892 if(eina_list_count(wd->touched) > 2)
2893 { /* Process zoom only when 2 fingers on surface */
2894 ev_flag = _set_state(gesture_zoom,
2895 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2896 consume_event(wd, event_info, event_type, ev_flag);
2901 if (!st->zoom_st.timestamp)
2902 { /* Now scan touched-devices list and find other finger */
2903 EINA_LIST_FOREACH(wd->touched, l, p)
2904 { /* Device of other finger <> pe device */
2905 if (p->device != pe->device)
2909 if (!p) /* Single finger on touch */
2912 /* Record down fingers */
2913 consume_event(wd, event_info, event_type, ev_flag);
2914 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2915 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2917 /* Set mv field as well to be ready for MOVE events */
2918 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2919 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2921 /* Here we have zoom_st, zoom_st1 set, report START */
2922 /* Set zoom-base after BOTH down events recorded */
2923 /* Compute length of line between fingers zoom start */
2924 st->info.zoom = 1.0;
2925 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2926 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2927 &st->info.x, &st->info.y);
2929 st->info.radius = st->zoom_base / 2;
2931 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2932 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2933 { /* zoom started with mouse-wheel, don't report twice */
2934 ev_flag = _set_state(gesture_zoom,
2935 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2936 consume_event(wd, event_info, event_type, ev_flag);
2939 return; /* Zoom started */
2940 } /* End of ZOOM_START handling */
2943 /* if we got here, we have (exacally) two fingers on surfce */
2944 /* we also after START, report MOVE */
2945 /* First detect which finger moved */
2946 if (pe->device == st->zoom_mv.device)
2947 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2948 else if (pe->device == st->zoom_mv1.device)
2949 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2951 /* Compute change in zoom as fingers move */
2952 st->info.zoom = compute_zoom(st,
2953 st->zoom_mv.x, st->zoom_mv.y,
2954 st->zoom_mv1.x, st->zoom_mv1.y,
2955 wd->zoom_finger_factor);
2957 if (!st->zoom_distance_tolerance)
2958 { /* Zoom broke tolerance, report move */
2959 double d = st->info.zoom - st->next_step;
2963 if (d >= wd->zoom_step)
2964 { /* Report move in steps */
2965 st->next_step = st->info.zoom;
2967 ev_flag = _set_state(gesture_zoom,
2968 ELM_GESTURE_STATE_MOVE,
2969 &st->info, EINA_TRUE);
2970 consume_event(wd, event_info, event_type, ev_flag);
2972 } /* End of ZOOM_MOVE handling */
2977 case EVAS_CALLBACK_MOUSE_UP:
2978 case EVAS_CALLBACK_MULTI_UP:
2979 /* Reset timestamp of finger-up.This is used later
2980 by _zoom_test_reset() to retain finger-down data */
2981 consume_event(wd, event_info, event_type, ev_flag);
2982 if (((st->zoom_wheel) || (st->zoom_base)) &&
2983 (st->zoom_distance_tolerance == 0))
2985 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2986 &st->info, EINA_FALSE);
2987 consume_event(wd, event_info, event_type, ev_flag);
2992 /* if we got here not a ZOOM */
2993 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2994 { /* Must be != undefined, if gesture started */
2995 ev_flag = _set_state(gesture_zoom,
2996 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2997 consume_event(wd, event_info, event_type, ev_flag);
3000 _zoom_test_reset(gesture_zoom);
3010 _get_rotate_properties(Rotate_Type *st,
3012 Evas_Coord x1, Evas_Coord y1,
3013 Evas_Coord x2, Evas_Coord y2,
3015 { /* FIXME: Fix momentum computation, it's wrong */
3016 double prev_angle = *angle;
3017 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
3018 &st->info.x, &st->info.y) / 2;
3020 *angle = get_angle(x1, y1, x2, y2);
3023 Evas_Coord xx1, Evas_Coord yy1,
3024 Evas_Coord xx2, Evas_Coord yy2,
3026 { /* FIXME: Fix momentum computation, it's wrong */
3027 double prev_angle = *angle;
3028 st->info.radius = get_finger_gap_length(xx1, yy1, xx2, yy2,
3029 &st->info.x, &st->info.y) / 2;
3031 *angle = get_angle(xx1, yy1, xx2, yy2);
3033 >>>>>>> remotes/origin/upstream
3034 if (angle == &st->info.angle)
3035 { /* Fingers are moving, compute momentum */
3036 unsigned int tm_start =
3037 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3038 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
3039 unsigned int tm_end =
3040 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3041 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3043 unsigned int tm_total = tm_end - tm_start;
3045 { /* Momentum computed as:
3046 accumulated roation angle (deg) divided by time */
3048 if (((prev_angle < 90) && ((*angle) > 270)) ||
3049 ((prev_angle > 270) && ((*angle) < 90)))
3050 { /* We circle passing ZERO point */
3051 prev_angle = (*angle);
3053 else m = prev_angle - (*angle);
3055 st->accum_momentum += m;
3057 if ((tm_end - st->prev_momentum_tm) < 100)
3058 st->prev_momentum += m;
3061 if (fabs(st->prev_momentum) < 0.002)
3062 st->accum_momentum = 0.0; /* reset momentum */
3064 st->prev_momentum = 0.0; /* Start again */
3067 st->prev_momentum_tm = tm_end;
3068 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3072 st->info.momentum = 0;
3078 * This function is used to test rotation gesture.
3079 * user may combine zoom, rotation together.
3080 * so its possible that both will be detected from input.
3081 * (both are two-finger movement-oriented gestures)
3083 * @param obj The gesture-layer object.
3084 * @param event_info Pointer to recent input event.
3085 * @param event_type Recent input event type.
3086 * @param g_type what Gesture we are testing.
3088 * @ingroup Elm_Gesture_Layer
3091 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
3093 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
3095 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
3096 >>>>>>> remotes/origin/upstream
3101 Widget_Data *wd = elm_widget_data_get(obj);
3103 if (!wd->gesture[g_type]) return;
3105 Gesture_Info *gesture = wd->gesture[g_type];
3111 { /* Allocated once on first time */
3112 st = calloc(1, sizeof(Rotate_Type));
3114 _rotate_test_reset(gesture);
3118 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3121 case EVAS_CALLBACK_MOUSE_MOVE:
3122 case EVAS_CALLBACK_MULTI_MOVE:
3123 /* if non-continues mode and gesture NOT started, ignore MOVE */
3124 if ((!wd->glayer_continues_enable) &&
3125 (!st->rotate_st.timestamp))
3128 case EVAS_CALLBACK_MOUSE_DOWN:
3129 case EVAS_CALLBACK_MULTI_DOWN:
3130 { /* Here we take care of rotate-start and rotate move */
3134 if(eina_list_count(wd->touched) > 2)
3135 { /* Process rotate only when 2 fingers on surface */
3136 ev_flag = _set_state(gesture,
3137 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3138 consume_event(wd, event_info, event_type, ev_flag);
3143 if (!st->rotate_st.timestamp)
3144 { /* Now scan touched-devices list and find other finger */
3145 EINA_LIST_FOREACH(wd->touched, l, p)
3146 { /* Device of other finger <> pe device */
3147 if (p->device != pe->device)
3152 return; /* Single finger on touch */
3154 /* Record down fingers */
3155 consume_event(wd, event_info, event_type, ev_flag);
3156 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3157 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3159 /* Set mv field as well to be ready for MOVE events */
3160 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3161 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3163 /* Here we have rotate_st, rotate_st1 set, report START */
3164 /* Set rotate-base after BOTH down events recorded */
3165 /* Compute length of line between fingers rotate start */
3166 _get_rotate_properties(st,
3167 st->rotate_st.x, st->rotate_st.y,
3168 st->rotate_st1.x, st->rotate_st1.y,
3169 &st->info.base_angle);
3171 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
3172 &st->info, EINA_FALSE);
3173 consume_event(wd, event_info, event_type, ev_flag);
3175 return; /* Rotate started */
3176 } /* End of ROTATE_START handling */
3179 /* if we got here, we have (exacally) two fingers on surfce */
3180 /* we also after START, report MOVE */
3181 /* First detect which finger moved */
3182 if (pe->device == st->rotate_mv.device)
3183 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3184 else if (pe->device == st->rotate_mv1.device)
3185 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3187 /* Compute change in rotate as fingers move */
3188 _get_rotate_properties(st,
3189 st->rotate_mv.x, st->rotate_mv.y,
3190 st->rotate_mv1.x, st->rotate_mv1.y,
3193 if (rotation_broke_tolerance(st))
3194 { /* Rotation broke tolerance, report move */
3195 double d = st->info.angle - st->next_step;
3200 >>>>>>> remotes/origin/upstream
3203 if (d >= wd->rotate_step)
3204 { /* Report move in steps */
3205 st->next_step = st->info.angle;
3207 ev_flag = _set_state(gesture,
3208 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3209 consume_event(wd, event_info, event_type, ev_flag);
3211 } /* End of ROTATE_MOVE handling */
3216 case EVAS_CALLBACK_MOUSE_UP:
3217 case EVAS_CALLBACK_MULTI_UP:
3218 consume_event(wd, event_info, event_type, ev_flag);
3219 /* Reset timestamp of finger-up.This is used later
3220 by rotate_test_reset() to retain finger-down data */
3221 if (st->rotate_angular_tolerance < 0)
3223 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
3224 &st->info, EINA_FALSE);
3225 consume_event(wd, event_info, event_type, ev_flag);
3230 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3231 { /* Must be != undefined, if gesture started */
3232 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
3233 &st->info, EINA_FALSE);
3234 consume_event(wd, event_info, event_type, ev_flag);
3237 _rotate_test_reset(gesture);
3248 * This function is used to save input events in an abstract struct
3249 * to be used later by getsure-testing functions.
3251 * @param data The gesture-layer object.
3252 * @param event_info Pointer to recent input event.
3253 * @param event_type Recent input event type.
3254 * @param pe The abstract data-struct (output).
3256 * @ingroup Elm_Gesture_Layer
3259 _make_pointer_event(void *data, void *event_info,
3260 Evas_Callback_Type event_type, Pointer_Event *pe)
3262 Widget_Data *wd = elm_widget_data_get(data);
3263 if (!wd) return EINA_FALSE;
3265 memset(pe, '\0', sizeof(*pe));
3268 case EVAS_CALLBACK_MOUSE_DOWN:
3269 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
3270 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
3271 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
3272 pe->device = ELM_MOUSE_DEVICE;
3275 case EVAS_CALLBACK_MOUSE_UP:
3276 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
3277 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
3278 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
3279 pe->device = ELM_MOUSE_DEVICE;
3282 case EVAS_CALLBACK_MOUSE_MOVE:
3283 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
3284 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
3285 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
3286 pe->device = ELM_MOUSE_DEVICE;
3289 case EVAS_CALLBACK_MULTI_DOWN:
3290 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
3291 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
3292 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
3293 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
3296 case EVAS_CALLBACK_MULTI_UP:
3297 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
3298 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
3299 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
3300 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
3303 case EVAS_CALLBACK_MULTI_MOVE:
3304 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
3305 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
3306 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
3307 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
3314 pe->event_type = event_type;
3321 * This function restartes line, flick, zoom and rotate gestures
3322 * when gesture-layer continues-gestures enabled.
3323 * Example of continues-gesture:
3324 * When doing a line, user stops moving finger but keeps fingers on touch.
3325 * This will cause line-end, then as user continues moving his finger
3326 * it re-starts line gesture.
3327 * When continue mode is disabled, user has to lift finger from touch
3328 * to end a gesture. Them touch-again to start a new one.
3330 * @param data The gesture-layer object.
3331 * @param wd gesture layer widget data.
3332 * @param states_reset flag that marks gestures were reset in history clear.
3334 * @ingroup Elm_Gesture_Layer
3337 void continues_gestures_restart(void *data, Eina_Bool states_reset)
3340 continues_gestures_restart(void *data, Eina_Bool states_reset)
3341 >>>>>>> remotes/origin/upstream
3343 Widget_Data *wd = elm_widget_data_get(data);
3346 /* Run through events to restart gestures */
3348 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
3349 /* We turn-on flag for finished, aborted, not-started gestures */
3350 g = wd->gesture[ELM_GESTURE_MOMENTUM];
3351 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3352 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3355 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
3356 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3360 g = wd->gesture[ELM_GESTURE_N_LINES];
3361 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3362 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3365 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3366 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3370 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3371 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3372 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3375 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3376 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3380 g = wd->gesture[ELM_GESTURE_ZOOM];
3381 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3382 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3385 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3386 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3390 g = wd->gesture[ELM_GESTURE_ROTATE];
3391 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3392 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3395 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3396 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3404 * This function the core-function where input handling is done.
3405 * Here we get user input and stream it to gesture testing.
3406 * We notify user about any gestures with new state:
3408 * START - gesture started.
3409 * MOVE - gesture is ongoing.
3410 * END - gesture was completed.
3411 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3413 * We also check if a gesture was detected, then reset event history
3414 * If no gestures were found we reset gesture test flag
3415 * after streaming event-history to widget.
3416 * (stream to the widget all events not consumed as a gesture)
3418 * @param data The gesture-layer object.
3419 * @param event_info Pointer to recent input event.
3420 * @param event_type Recent input event type.
3422 * @ingroup Elm_Gesture_Layer
3425 _event_process(void *data, Evas_Object *obj __UNUSED__,
3426 void *event_info, Evas_Callback_Type event_type)
3429 Pointer_Event *pe = NULL;
3430 Widget_Data *wd = elm_widget_data_get(data);
3434 >>>>>>> remotes/origin/upstream
3436 #if defined(DEBUG_GESTURE_LAYER)
3439 printf("Gesture | State | is tested\n");
3440 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3444 printf(" %d %d %d\n", i, g->state, g->test);
3448 /* Start testing candidate gesture from here */
3449 if (_make_pointer_event(data, event_info, event_type, &_pe))
3452 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3453 _n_long_tap_test(data, pe, event_info, event_type,
3454 ELM_GESTURE_N_LONG_TAPS);
3456 /* This takes care of single, double and tripple tap */
3457 _tap_gestures_test(data, pe, event_info, event_type);
3459 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3460 _momentum_test(data, pe, event_info, event_type,
3461 ELM_GESTURE_MOMENTUM);
3463 if (IS_TESTED(ELM_GESTURE_N_LINES))
3464 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3466 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3467 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3469 if (_elm_config->glayer_zoom_finger_enable && IS_TESTED(ELM_GESTURE_ZOOM))
3470 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3472 if (IS_TESTED(ELM_GESTURE_ZOOM))
3473 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3475 if (_elm_config->glayer_rotate_finger_enable && IS_TESTED(ELM_GESTURE_ROTATE))
3476 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3478 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3479 _event_history_add(data, event_info, event_type);
3480 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3481 (event_type == EVAS_CALLBACK_MULTI_UP))
3483 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3486 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3487 _event_history_add(data, event_info, event_type);
3491 /* we maintain list of touched devices */
3492 /* We also use move to track current device x.y pos */
3493 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3494 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3495 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3496 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3498 wd->touched = _add_touched_device(wd->touched, pe);
3500 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3501 (event_type == EVAS_CALLBACK_MULTI_UP))
3503 wd->touched = _remove_touched_device(wd->touched, pe);
3506 /* Report current states and clear history if needed */
3507 Eina_Bool states_reset = _clear_if_finished(data);
3508 if (wd->glayer_continues_enable)
3509 continues_gestures_restart(data, states_reset);
3514 * For all _mouse_* / multi_* functions wethen send this event to
3515 * _event_process function.
3517 * @param data The gesture-layer object.
3518 * @param event_info Pointer to recent input event.
3520 * @ingroup Elm_Gesture_Layer
3523 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3526 Widget_Data *wd = elm_widget_data_get(data);
3528 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3529 return; /* We only process left-click at the moment */
3531 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3535 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3538 Widget_Data *wd = elm_widget_data_get(data);
3541 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3545 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3548 Widget_Data *wd = elm_widget_data_get(data);
3551 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3555 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3558 Widget_Data *wd = elm_widget_data_get(data);
3561 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3565 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3568 Widget_Data *wd = elm_widget_data_get(data);
3571 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3572 return; /* We only process left-click at the moment */
3574 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3578 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3581 Widget_Data *wd = elm_widget_data_get(data);
3584 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3588 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3591 Widget_Data *wd = elm_widget_data_get(data);
3594 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3598 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3601 Widget_Data *wd = elm_widget_data_get(data);
3604 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3608 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3611 Widget_Data *wd = elm_widget_data_get(data);
3614 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3619 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3622 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3624 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3626 >>>>>>> remotes/origin/upstream
3627 Widget_Data *wd = elm_widget_data_get(obj);
3628 if (!wd) return EINA_FALSE;
3630 return !wd->repeat_events;
3635 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3637 Widget_Data *wd = elm_widget_data_get(obj);
3640 wd->repeat_events = !r;
3644 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3646 Widget_Data *wd = elm_widget_data_get(obj);
3656 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3658 Widget_Data *wd = elm_widget_data_get(obj);
3664 wd->rotate_step = s;
3668 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3670 Widget_Data *wd = elm_widget_data_get(obj);
3671 if (!wd) return EINA_FALSE;
3676 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool hold_events)
3678 ELM_CHECK_WIDTYPE(obj, widtype);
3680 Widget_Data *wd = elm_widget_data_get(obj);
3683 wd->repeat_events = !(!!hold_events);
3687 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3689 ELM_CHECK_WIDTYPE(obj, widtype) 0;
3691 Widget_Data *wd = elm_widget_data_get(obj);
3694 return wd->zoom_step;
3698 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double step)
3700 ELM_CHECK_WIDTYPE(obj, widtype);
3702 Widget_Data *wd = elm_widget_data_get(obj);
3705 if (step < 0) return;
3707 wd->zoom_step = step;
3711 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3713 ELM_CHECK_WIDTYPE(obj, widtype) 0;
3715 Widget_Data *wd = elm_widget_data_get(obj);
3718 return wd->rotate_step;
3722 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double step)
3724 ELM_CHECK_WIDTYPE(obj, widtype);
3726 Widget_Data *wd = elm_widget_data_get(obj);
3729 if (step < 0) return;
3731 wd->rotate_step = step;
3735 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *target)
3737 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3739 Widget_Data *wd = elm_widget_data_get(obj);
3740 if (!wd) return EINA_FALSE;
3742 if (!target) return EINA_FALSE;
3743 >>>>>>> remotes/origin/upstream
3745 /* if was attached before, unregister callbacks first */
3747 _unregister_callbacks(obj);
3752 wd->target = target;
3753 >>>>>>> remotes/origin/upstream
3755 _register_callbacks(obj);
3761 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3762 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3765 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Type idx,
3766 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3768 ELM_CHECK_WIDTYPE(obj, widtype);
3770 >>>>>>> remotes/origin/upstream
3771 Widget_Data *wd = elm_widget_data_get(obj);
3775 if (!wd->gesture[idx])
3776 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3777 if (!wd->gesture[idx]) return;
3779 p = wd->gesture[idx];
3782 p->fn[cb_type].cb = cb;
3783 p->fn[cb_type].user_data = data;
3784 p->state = ELM_GESTURE_STATE_UNDEFINED;
3789 _disable_hook(Evas_Object *obj)
3791 if (elm_widget_disabled_get(obj))
3792 _unregister_callbacks(obj);
3794 _register_callbacks(obj);
3798 elm_gesture_layer_add(Evas_Object *parent)
3804 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3806 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3807 elm_widget_type_set(obj, "gesture_layer");
3808 elm_widget_sub_object_add(parent, obj);
3809 elm_widget_data_set(obj, wd);
3810 elm_widget_del_hook_set(obj, _del_hook);
3811 elm_widget_disable_hook_set(obj, _disable_hook);
3815 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3816 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3817 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3819 wd->line_min_length =_elm_config->glayer_line_min_length * _elm_config->finger_size;
3820 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * _elm_config->finger_size;
3821 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * _elm_config->finger_size;
3822 >>>>>>> remotes/origin/upstream
3823 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3824 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3825 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3826 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3827 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3828 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3829 wd->repeat_events = EINA_TRUE;
3830 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3832 #if defined(DEBUG_GESTURE_LAYER)
3833 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3834 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);
3836 memset(wd->gesture, 0, sizeof(wd->gesture));