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 */
78 Elm_Gesture_Type g_type; /**< gesture type */
79 Elm_Gesture_State state; /**< gesture state */
80 void *info; /**< Data for the state callback */
81 Eina_Bool test; /**< if true this gesture should be tested on input */
87 * @typedef Gesture_Info
88 * Type for _Gesture_Info
90 * @ingroup Elm_Gesture_Layer
92 typedef struct _Gesture_Info Gesture_Info;
97 * @struct _Event_History
98 * Struct holds event history.
99 * These events are repeated if no gesture found.
101 * @ingroup Elm_Gesture_Layer
103 struct _Event_History
107 Evas_Callback_Type event_type;
113 * @typedef Event_History
114 * Type for _Event_History
116 * @ingroup Elm_Gesture_Layer
118 typedef struct _Event_History Event_History;
123 * @struct _Pointer_Event
124 * Struct holds pointer-event info
125 * This is a generic pointer event structure
127 * @ingroup Elm_Gesture_Layer
129 struct _Pointer_Event
132 unsigned int timestamp;
134 Evas_Callback_Type event_type;
140 * @typedef Pointer_Event
141 * Type for generic pointer event structure
143 * @ingroup Elm_Gesture_Layer
145 typedef struct _Pointer_Event Pointer_Event;
147 /* All *Type structs hold result for the user in 'info' field
148 * The rest is gesture processing intermediate data.
149 * NOTE: info field must be FIRST in the struct.
150 * This is used when reporting ABORT in event_history_clear() */
153 Elm_Gesture_Taps_Info info;
156 unsigned int n_taps_needed;
160 typedef struct _Taps_Type Taps_Type;
162 struct _Long_Tap_Type
164 Elm_Gesture_Taps_Info info;
167 unsigned int max_touched;
168 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
171 typedef struct _Long_Tap_Type Long_Tap_Type;
173 struct _Momentum_Type
174 { /* Fields used by _line_test() */
175 Elm_Gesture_Momentum_Info info;
176 Evas_Coord_Point line_st;
177 Evas_Coord_Point line_end;
178 unsigned int t_st_x; /* Time start on X */
179 unsigned int t_st_y; /* Time start on Y */
180 unsigned int t_end; /* Time end */
181 unsigned int t_up; /* Recent up event time */
184 typedef struct _Momentum_Type Momentum_Type;
188 Evas_Coord_Point line_st;
189 Evas_Coord_Point line_end;
190 Evas_Coord line_length;
191 unsigned int t_st; /* Time start */
192 unsigned int t_end; /* Time end */
194 double line_angle; /* Current angle of line */
196 typedef struct _Line_Data Line_Data;
199 { /* Fields used by _line_test() */
200 Elm_Gesture_Line_Info info;
201 Eina_List *list; /* List of Line_Data */
203 typedef struct _Line_Type Line_Type;
206 { /* Fields used by _zoom_test() */
207 Elm_Gesture_Zoom_Info info;
208 Pointer_Event zoom_st;
209 Pointer_Event zoom_mv;
210 Pointer_Event zoom_st1;
211 Pointer_Event zoom_mv1;
212 Evas_Event_Mouse_Wheel *zoom_wheel;
213 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
214 Evas_Coord zoom_distance_tolerance;
215 unsigned int m_st_tm; /* momentum start time */
216 unsigned int m_prev_tm; /* momentum prev time */
217 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
218 double m_base; /* zoom value when momentum starts */
221 typedef struct _Zoom_Type Zoom_Type;
224 { /* Fields used by _rotation_test() */
225 Elm_Gesture_Rotate_Info info;
226 Pointer_Event rotate_st;
227 Pointer_Event rotate_mv;
228 Pointer_Event rotate_st1;
229 Pointer_Event rotate_mv1;
230 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
231 double prev_momentum; /* Snapshot of momentum 0.01 sec ago */
232 double accum_momentum;
233 double rotate_angular_tolerance;
236 typedef struct _Rotate_Type Rotate_Type;
240 Evas_Object *target; /* Target Widget */
241 Event_History *event_history_list;
244 Evas_Coord zoom_distance_tolerance;
245 Evas_Coord line_distance_tolerance;
246 double line_angular_tolerance;
247 double zoom_wheel_factor; /* mouse wheel zoom steps */
248 double zoom_finger_factor; /* used for zoom factor */
249 double rotate_angular_tolerance;
250 unsigned int flick_time_limit_ms;
251 double long_tap_start_timeout;
252 Eina_Bool glayer_continues_enable;
257 Gesture_Info *gesture[ELM_GESTURE_LAST];
258 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
259 Eina_List *pending; /* List of devices need to refeed *UP event */
260 Eina_List *touched; /* Information of touched devices */
262 Eina_Bool repeat_events : 1;
264 typedef struct _Widget_Data Widget_Data;
266 static const char *widtype = NULL;
267 static void _del_hook(Evas_Object *obj);
269 static Eina_Bool _event_history_clear(Evas_Object *obj);
270 static void _reset_states(Widget_Data *wd);
271 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
272 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
273 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Type g_type);
274 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
275 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
276 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
277 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
279 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
280 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
281 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
283 /* START - Functions to manage touched-device list */
286 * This function is used to find if device is touched
288 * @ingroup Elm_Gesture_Layer
291 compare_device(const void *data1, const void *data2)
292 { /* Compare the two device numbers */
293 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
299 * Remove Pointer Event from touched device list
300 * @param list Pointer to touched device list.
301 * @param Pointer_Event Pointer to PE.
303 * @ingroup Elm_Gesture_Layer
306 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
308 Eina_List *lst = NULL;
309 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
312 lst = eina_list_remove(list, p);
323 * Recoed Pointer Event in touched device list
324 * Note: This fuction allocates memory for PE event
325 * This memory is released in _remove_touched_device()
326 * @param list Pointer to touched device list.
327 * @param Pointer_Event Pointer to PE.
329 * @ingroup Elm_Gesture_Layer
332 _add_touched_device(Eina_List *list, Pointer_Event *pe)
334 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
336 { /* We like to track device touch-position, overwrite info */
337 memcpy(p, pe, sizeof(Pointer_Event));
341 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
342 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN))
343 { /* Add touched device on DOWN event only */
344 p = malloc(sizeof(Pointer_Event));
345 /* Freed in _remove_touched_device() */
346 memcpy(p, pe, sizeof(Pointer_Event));
347 return eina_list_append(list, p);
352 /* END - Functions to manage touched-device list */
358 * @param event_info pointer to event.
360 * @ingroup Elm_Gesture_Layer
362 static Evas_Event_Flags
363 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
367 case EVAS_CALLBACK_MOUSE_IN:
368 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
369 case EVAS_CALLBACK_MOUSE_OUT:
370 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
371 case EVAS_CALLBACK_MOUSE_DOWN:
372 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
373 case EVAS_CALLBACK_MOUSE_MOVE:
374 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
375 case EVAS_CALLBACK_MOUSE_UP:
376 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
377 case EVAS_CALLBACK_MOUSE_WHEEL:
378 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
379 case EVAS_CALLBACK_MULTI_DOWN:
380 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
381 case EVAS_CALLBACK_MULTI_MOVE:
382 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
383 case EVAS_CALLBACK_MULTI_UP:
384 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
385 case EVAS_CALLBACK_KEY_DOWN:
386 return ((Evas_Event_Key_Down *) event_info)->event_flags;
387 case EVAS_CALLBACK_KEY_UP:
388 return ((Evas_Event_Key_Up *) event_info)->event_flags;
390 return EVAS_EVENT_FLAG_NONE;
397 * Sets event flag to value returned from user callback
398 * @param wd Widget Data
399 * @param event_info pointer to event.
400 * @param event_type what type was ev (mouse down, etc...)
401 * @param ev_flags event flags
403 * @ingroup Elm_Gesture_Layer
406 consume_event(Widget_Data *wd, void *event_info,
407 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
408 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
409 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
410 /* should not refeed this event. */
412 return; /* This happens when restarting gestures */
414 if ((ev_flags) || (!wd->repeat_events))
418 case EVAS_CALLBACK_MOUSE_DOWN:
419 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
421 case EVAS_CALLBACK_MOUSE_MOVE:
422 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
424 case EVAS_CALLBACK_MOUSE_UP:
425 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
427 case EVAS_CALLBACK_MOUSE_WHEEL:
428 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
430 case EVAS_CALLBACK_MULTI_DOWN:
431 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
433 case EVAS_CALLBACK_MULTI_MOVE:
434 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
436 case EVAS_CALLBACK_MULTI_UP:
437 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
439 case EVAS_CALLBACK_KEY_DOWN:
440 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
442 case EVAS_CALLBACK_KEY_UP:
443 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
454 * Report current state of a gesture by calling user callback.
455 * @param gesture what gesture state we report.
456 * @param info inforamtion for user callback
458 * @ingroup Elm_Gesture_Layer
460 static Evas_Event_Flags
461 _report_state(Gesture_Info *gesture, void *info)
462 { /* We report current state (START, MOVE, END, ABORT), once */
463 #if defined(DEBUG_GESTURE_LAYER)
464 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
467 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
468 (gesture->fn[gesture->state].cb))
469 { /* Fill state-info struct and send ptr to user callback */
470 return gesture->fn[gesture->state].cb(
471 gesture->fn[gesture->state].user_data, info);
474 return EVAS_EVENT_FLAG_NONE;
480 * Update state for a given gesture.
481 * We may update gesture state to:
482 * UNDEFINED - current input did not start gesure yet.
483 * START - gesture started according to input.
484 * MOVE - gusture in progress.
485 * END - gesture completed according to input.
486 * ABORT - input does not matches gesure.
487 * note that we may move from UNDEFINED to ABORT
488 * because we may detect that gesture will not START
489 * with a given input.
491 * @param g given gesture to change state.
492 * @param s gesure new state.
493 * @param info buffer to be sent to user callback on report_state.
494 * @param force makes report_state to report the new-state even
495 * if its same as current state. Works for MOVE - gesture in progress.
497 * @ingroup Elm_Gesture_Layer
499 static Evas_Event_Flags
500 _set_state(Gesture_Info *g, Elm_Gesture_State s,
501 void *info, Eina_Bool force)
503 Elm_Gesture_State old_state;
504 if ((g->state == s) && (!force))
505 return EVAS_EVENT_FLAG_NONE;
507 old_state = g->state;
510 g->info = info; /* Information for user callback */
511 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
512 (g->state == ELM_GESTURE_STATE_END))
513 g->test = EINA_FALSE;
515 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
516 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
517 (s == ELM_GESTURE_STATE_ABORT))))
518 return _report_state(g, g->info);
520 return EVAS_EVENT_FLAG_NONE;
526 * This resets all gesture states and sets test-bit.
527 * this is used for restarting gestures to listen to input.
528 * happens after we complete a gesture or no gesture was detected.
529 * @param wd Widget data of the gesture-layer object.
531 * @ingroup Elm_Gesture_Layer
534 _reset_states(Widget_Data *wd)
538 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
543 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
552 * if gesture was NOT detected AND we only have gestures in ABORT state
553 * we clear history immediately to be ready for input.
555 * @param obj The gesture-layer object.
556 * @return TRUE on event history_clear
558 * @ingroup Elm_Gesture_Layer
561 _clear_if_finished(Evas_Object *obj)
563 Widget_Data *wd = elm_widget_data_get(obj);
564 if (!wd) return EINA_FALSE;
567 /* Clear history if all we have aborted gestures */
568 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
569 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
570 { /* If no gesture started and all we have aborted gestures, reset all */
571 Gesture_Info *p = wd->gesture[i];
572 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
574 if ((p->state == ELM_GESTURE_STATE_START) ||
575 (p->state == ELM_GESTURE_STATE_MOVE))
576 reset_s = EINA_FALSE;
578 all_undefined = EINA_FALSE;
582 if (reset_s && (!all_undefined))
583 return _event_history_clear(obj);
589 _inside(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2)
591 int w = _elm_config->finger_size >> 1; /* Finger size devided by 2 */
607 /* All *test_reset() funcs are called to clear
608 * gesture intermediate data.
609 * This happens when we need to reset our tests.
610 * for example when gesture is detected or all ABORTed. */
612 _tap_gestures_test_reset(Gesture_Info *gesture)
617 Widget_Data *wd = elm_widget_data_get(gesture->obj);
623 ecore_timer_del(wd->dbl_timeout);
624 wd->dbl_timeout = NULL;
630 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
631 EINA_LIST_FREE(data, pe)
634 memset(gesture->data, 0, sizeof(Taps_Type));
637 /* All *test_reset() funcs are called to clear
638 * gesture intermediate data.
639 * This happens when we need to reset our tests.
640 * for example when gesture is detected or all ABORTed. */
642 _n_long_tap_test_reset(Gesture_Info *gesture)
650 Long_Tap_Type *st = gesture->data;
653 EINA_LIST_FOREACH(st->touched, l, p)
656 eina_list_free(st->touched);
659 ecore_timer_del(st->timeout);
662 memset(gesture->data, 0, sizeof(Long_Tap_Type));
666 _momentum_test_reset(Gesture_Info *gesture)
674 memset(gesture->data, 0, sizeof(Momentum_Type));
678 _line_data_reset(Line_Data *st)
683 memset(st, 0, sizeof(Line_Data));
684 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
688 _line_test_reset(Gesture_Info *gesture)
696 Line_Type *st = gesture->data;
697 Eina_List *list = st->list;
700 EINA_LIST_FOREACH(list, l, t_line)
703 eina_list_free(list);
708 _zoom_test_reset(Gesture_Info *gesture)
716 Widget_Data *wd = elm_widget_data_get(gesture->obj);
717 Zoom_Type *st = gesture->data;
718 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
719 evas_object_evas_get(wd->target), "Control");
720 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
721 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
723 memset(st, 0, sizeof(Zoom_Type));
724 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
729 _rotate_test_reset(Gesture_Info *gesture)
737 Widget_Data *wd = elm_widget_data_get(gesture->obj);
738 Rotate_Type *st = gesture->data;
740 memset(st, 0, sizeof(Rotate_Type));
741 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
742 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
749 * We register callbacks when gesture layer is attached to an object
750 * or when its enabled after disable.
752 * @param obj The gesture-layer object.
754 * @ingroup Elm_Gesture_Layer
757 _register_callbacks(Evas_Object *obj)
759 Widget_Data *wd = elm_widget_data_get(obj);
764 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
766 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
768 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
771 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
774 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
776 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
778 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
781 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
783 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
791 * We unregister callbacks when gesture layer is disabled.
793 * @param obj The gesture-layer object.
795 * @ingroup Elm_Gesture_Layer
798 _unregister_callbacks(Evas_Object *obj)
800 Widget_Data *wd = elm_widget_data_get(obj);
805 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
807 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
809 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
812 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
815 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
818 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
821 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
824 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
826 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
831 /* START - Event history list handling functions */
834 * This function is used to find if device number
835 * is found in a list of devices.
836 * The list contains devices for refeeding *UP event
838 * @ingroup Elm_Gesture_Layer
841 device_in_pending_list(const void *data1, const void *data2)
842 { /* Compare the two device numbers */
843 return (((intptr_t) data1) - ((intptr_t) data2));
849 * This functions adds device to refeed-pending device list
850 * @ingroup Elm_Gesture_Layer
853 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
855 int device = ELM_MOUSE_DEVICE;
858 case EVAS_CALLBACK_MOUSE_DOWN:
860 case EVAS_CALLBACK_MULTI_DOWN:
861 device = ((Evas_Event_Multi_Down *) event)->device;
867 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
868 (void *)(intptr_t)device))
870 return eina_list_append(list, (void *)(intptr_t)device);
879 * This functions returns pending-device node
880 * @ingroup Elm_Gesture_Layer
883 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
885 int device = ELM_MOUSE_DEVICE;
888 case EVAS_CALLBACK_MOUSE_UP:
890 case EVAS_CALLBACK_MULTI_UP:
891 device = ((Evas_Event_Multi_Up *) event)->device;
897 return eina_list_search_unsorted_list(list, device_in_pending_list,
898 (void *)(intptr_t)device);
904 * This function reports ABORT to all none-detected gestures
905 * Then resets test bits for all desired gesures
906 * and clears input-events history.
907 * note: if no gesture was detected, events from history list
908 * are streamed to the widget because it's unused by layer.
909 * user may cancel refeed of events by setting repeat events.
911 * @param obj The gesture-layer object.
913 * @ingroup Elm_Gesture_Layer
916 _event_history_clear(Evas_Object *obj)
918 Widget_Data *wd = elm_widget_data_get(obj);
919 if (!wd) return EINA_FALSE;
923 Evas *e = evas_object_evas_get(obj);
924 Eina_Bool gesture_found = EINA_FALSE;
925 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
930 if (p->state == ELM_GESTURE_STATE_END)
931 gesture_found = EINA_TRUE;
933 { /* Report ABORT to all gestures that still not finished */
934 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
940 _reset_states(wd); /* we are ready to start testing for gestures again */
942 /* Clear all gestures intermediate data */
943 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
944 { /* We do not clear a long-tap gesture if fingers still on surface */
945 /* and gesture timer still pending to test gesture state */
946 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
947 if ((st) && /* st not allocated if clear occurs before 1st input */
948 ((!eina_list_count(st->touched)) || (!st->timeout)))
949 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
954 ecore_timer_del(wd->dbl_timeout);
955 wd->dbl_timeout = NULL;
958 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
959 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
960 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
961 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
962 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
963 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
964 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
965 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
967 /* Disable gesture layer so refeeded events won't be consumed by it */
968 _unregister_callbacks(obj);
969 while (wd->event_history_list)
972 t = wd->event_history_list;
973 Eina_List *pending = _device_is_pending(wd->pending,
974 wd->event_history_list->event,
975 wd->event_history_list->event_type);
977 /* Refeed events if no gesture matched input */
978 if (pending || ((!gesture_found) && (!wd->repeat_events)))
980 evas_event_refeed_event(e, wd->event_history_list->event,
981 wd->event_history_list->event_type);
985 wd->pending = eina_list_remove_list(wd->pending, pending);
989 wd->pending = _add_device_pending(wd->pending,
990 wd->event_history_list->event,
991 wd->event_history_list->event_type);
995 free(wd->event_history_list->event);
996 wd->event_history_list = (Event_History *) eina_inlist_remove(
997 EINA_INLIST_GET(wd->event_history_list),
998 EINA_INLIST_GET(wd->event_history_list));
1001 _register_callbacks(obj);
1008 * This function copies input events.
1009 * We copy event info before adding it to history.
1010 * The memory is freed when we clear history.
1012 * @param event the event to copy
1013 * @param event_type event type to copy
1015 * @ingroup Elm_Gesture_Layer
1018 _copy_event_info(void *event, Evas_Callback_Type event_type)
1022 case EVAS_CALLBACK_MOUSE_DOWN:
1023 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1025 case EVAS_CALLBACK_MOUSE_MOVE:
1026 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1028 case EVAS_CALLBACK_MOUSE_UP:
1029 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1031 case EVAS_CALLBACK_MOUSE_WHEEL:
1032 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1034 case EVAS_CALLBACK_MULTI_DOWN:
1035 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1037 case EVAS_CALLBACK_MULTI_MOVE:
1038 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1040 case EVAS_CALLBACK_MULTI_UP:
1041 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1043 case EVAS_CALLBACK_KEY_DOWN:
1044 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1046 case EVAS_CALLBACK_KEY_UP:
1047 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1055 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1057 Widget_Data *wd = elm_widget_data_get(obj);
1059 if (!wd) return EINA_FALSE;
1061 ev = malloc(sizeof(Event_History));
1062 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1063 ev->event_type = event_type;
1064 wd->event_history_list = (Event_History *) eina_inlist_append(
1065 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1069 /* END - Event history list handling functions */
1072 _del_hook(Evas_Object *obj)
1074 Widget_Data *wd = elm_widget_data_get(obj);
1077 _event_history_clear(obj);
1078 eina_list_free(wd->pending);
1080 Pointer_Event *data;
1081 EINA_LIST_FREE(wd->touched, data)
1084 if (!elm_widget_disabled_get(obj))
1085 _unregister_callbacks(obj);
1087 /* Free all gestures internal data structures */
1089 for (i = 0; i < ELM_GESTURE_LAST; i++)
1092 if (wd->gesture[i]->data)
1093 free(wd->gesture[i]->data);
1095 free(wd->gesture[i]);
1102 compare_match_fingers(const void *data1, const void *data2)
1103 { /* Compare coords of first item in list to cur coords */
1104 const Pointer_Event *pe1 = eina_list_data_get(data1);
1105 const Pointer_Event *pe2 = data2;
1107 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1109 else if (pe1->x < pe2->x)
1113 if (pe1->x == pe2->x)
1114 return pe1->y - pe2->y;
1121 compare_pe_device(const void *data1, const void *data2)
1122 { /* Compare device of first item in list to our pe device */
1123 const Pointer_Event *pe1 = eina_list_data_get(data1);
1124 const Pointer_Event *pe2 = data2;
1126 /* Only match if last was a down event */
1127 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1128 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1131 if (pe1->device == pe2->device)
1133 else if (pe1->device < pe2->device)
1140 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1141 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1142 { /* Keep copy of pe and record it in list */
1143 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1144 memcpy(p, pe, sizeof(Pointer_Event));
1145 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1151 /* This will also update middle-point to report to user later */
1152 st->info.x = st->sum_x / st->n_taps;
1153 st->info.y = st->sum_y / st->n_taps;
1154 st->info.timestamp = pe->timestamp;
1158 pe_list = eina_list_append(pe_list, p);
1159 st->l = eina_list_append(st->l, pe_list);
1162 pe_list = eina_list_append(pe_list, p);
1170 * This function checks if the tap gesture is done.
1172 * @param data gesture info pointer
1173 * @return EINA_TRUE if it is done.
1175 * @ingroup Elm_Gesture_Layer
1178 _tap_gesture_check_finish(Gesture_Info *gesture)
1180 /* Here we check if taps-gesture was completed successfuly */
1181 /* Count how many taps were recieved on each device then */
1182 /* determine if it matches n_taps_needed defined on START */
1183 Taps_Type *st = gesture->data;
1186 EINA_LIST_FOREACH(st->l, l, pe_list)
1188 if (eina_list_count(pe_list) != st->n_taps_needed)
1189 { /* No match taps number on device, ABORT */
1200 * This function sets state a tap-gesture to END or ABORT
1202 * @param data gesture info pointer
1204 * @ingroup Elm_Gesture_Layer
1207 _tap_gesture_finish(void *data)
1208 { /* This function will test each tap gesture when timer expires */
1209 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1210 Gesture_Info *gesture = data;
1211 Taps_Type *st = gesture->data;
1213 if (!_tap_gesture_check_finish(data))
1214 s = ELM_GESTURE_STATE_ABORT;
1216 st->info.n = eina_list_count(st->l);
1217 _set_state(gesture, s, gesture->info, EINA_FALSE);
1218 _tap_gestures_test_reset(gesture);
1224 * when this timer expires we finish tap gestures.
1226 * @param data The gesture-layer object.
1227 * @return cancles callback for this timer.
1229 * @ingroup Elm_Gesture_Layer
1232 _multi_tap_timeout(void *data)
1234 Widget_Data *wd = elm_widget_data_get(data);
1235 if (!wd) return EINA_FALSE;
1237 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1238 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1240 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1241 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1243 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1244 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1246 _clear_if_finished(data);
1247 wd->dbl_timeout = NULL;
1248 return ECORE_CALLBACK_CANCEL;
1254 * when this timer expires we START long tap gesture
1256 * @param data The gesture-layer object.
1257 * @return cancles callback for this timer.
1259 * @ingroup Elm_Gesture_Layer
1262 _long_tap_timeout(void *data)
1264 Gesture_Info *gesture = data;
1265 Long_Tap_Type *st = gesture->data;
1268 _set_state(gesture, ELM_GESTURE_STATE_START,
1269 gesture->data, EINA_FALSE);
1271 return ECORE_CALLBACK_CANCEL;
1278 * This function checks if a tap gesture should start
1280 * @param wd Gesture Layer Widget Data.
1281 * @param pe The recent input event as stored in pe struct.
1282 * @param event_info Original input event pointer.
1283 * @param event_type Type of original input event.
1284 * @param gesture what gesture is tested
1285 * @param how many taps for this gesture (1, 2 or 3)
1287 * @return Flag to determine if we need to set a timer for finish
1289 * @ingroup Elm_Gesture_Layer
1292 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1293 void *event_info, Evas_Callback_Type event_type,
1294 Gesture_Info *gesture, int taps)
1295 { /* Here we fill Tap struct */
1296 Taps_Type *st = gesture->data;
1298 { /* Allocated once on first time */
1299 st = calloc(1, sizeof(Taps_Type));
1301 _tap_gestures_test_reset(gesture);
1304 Eina_List *pe_list = NULL;
1305 Pointer_Event *pe_down = NULL;
1306 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1307 switch (pe->event_type)
1309 case EVAS_CALLBACK_MULTI_DOWN:
1310 case EVAS_CALLBACK_MOUSE_DOWN:
1311 /* Check if got tap on same cord was tapped before */
1312 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1315 eina_list_search_unsorted(st->l, compare_pe_device, pe))
1316 { /* This device was touched in other cord before completion */
1317 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1318 &st->info, EINA_FALSE);
1319 consume_event(wd, event_info, event_type, ev_flag);
1324 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1325 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1326 { /* This is the first mouse down we got */
1327 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1328 &st->info, EINA_FALSE);
1329 consume_event(wd, event_info, event_type, ev_flag);
1331 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1338 case EVAS_CALLBACK_MULTI_UP:
1339 case EVAS_CALLBACK_MOUSE_UP:
1340 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1344 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1346 if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1347 !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1348 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1349 ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1350 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1352 if (_tap_gesture_check_finish(gesture))
1354 _tap_gesture_finish(gesture);
1361 case EVAS_CALLBACK_MULTI_MOVE:
1362 case EVAS_CALLBACK_MOUSE_MOVE:
1363 /* Get first event in first list, this has to be a Mouse Down event */
1364 /* and verify that user didn't move out of this area before next tap */
1365 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1368 pe_down = eina_list_data_get(pe_list);
1369 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1371 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1372 &st->info, EINA_FALSE);
1373 consume_event(wd, event_info, event_type, ev_flag);
1389 * This function checks all click/tap and double/triple taps
1391 * @param obj The gesture-layer object.
1392 * @param pe The recent input event as stored in pe struct.
1393 * @param event_info Original input event pointer.
1394 * @param event_type Type of original input event.
1396 * @ingroup Elm_Gesture_Layer
1399 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1400 void *event_info, Evas_Callback_Type event_type)
1401 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1402 Eina_Bool need_timer = EINA_FALSE;
1403 Widget_Data *wd = elm_widget_data_get(obj);
1406 if (!pe) /* this happens when unhandled event arrived */
1407 return; /* see _make_pointer_event function */
1409 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1410 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1411 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1413 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1414 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1415 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1417 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1418 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1419 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1421 if ((need_timer) && (!wd->dbl_timeout))
1422 { /* Set a timer to finish these gestures */
1423 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1431 * This function computes center-point for long-tap gesture
1433 * @param st Long Tap gesture info pointer
1434 * @param pe The recent input event as stored in pe struct.
1436 * @ingroup Elm_Gesture_Layer
1439 _compute_taps_center(Long_Tap_Type *st,
1440 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1442 if (!eina_list_count(st->touched))
1447 Evas_Coord x = 0, y = 0;
1448 EINA_LIST_FOREACH(st->touched, l, p)
1449 { /* Accumulate all then take avarage */
1450 if (p->device == pe->device)
1451 { /* This will take care of values coming from MOVE event */
1462 *x_out = x / eina_list_count(st->touched);
1463 *y_out = y / eina_list_count(st->touched);
1469 * This function checks N long-tap gesture.
1471 * @param obj The gesture-layer object.
1472 * @param pe The recent input event as stored in pe struct.
1473 * @param event_info Original input event pointer.
1474 * @param event_type Type of original input event.
1475 * @param g_type what Gesture we are testing.
1476 * @param taps How many click/taps we test for.
1478 * @ingroup Elm_Gesture_Layer
1481 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1482 void *event_info, Evas_Callback_Type event_type,
1483 Elm_Gesture_Type g_type)
1484 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1485 Widget_Data *wd = elm_widget_data_get(obj);
1488 if (!pe) /* this happens when unhandled event arrived */
1489 return; /* see _make_pointer_event function */
1490 Gesture_Info *gesture = wd->gesture[g_type];
1491 if (!gesture) return;
1493 Long_Tap_Type *st = gesture->data;
1495 { /* Allocated once on first time */
1496 st = calloc(1, sizeof(Long_Tap_Type));
1498 _n_long_tap_test_reset(gesture);
1501 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1502 switch (pe->event_type)
1504 case EVAS_CALLBACK_MULTI_DOWN:
1505 case EVAS_CALLBACK_MOUSE_DOWN:
1506 st->touched = _add_touched_device(st->touched, pe);
1507 st->info.n = eina_list_count(st->touched);
1508 if (st->info.n > st->max_touched)
1509 st->max_touched = st->info.n;
1511 { /* User removed finger from touch, then put back - ABORT */
1512 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1513 (gesture->state == ELM_GESTURE_STATE_MOVE))
1515 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1516 &st->info, EINA_FALSE);
1517 consume_event(wd, event_info, event_type, ev_flag);
1521 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1522 { /* This is the first mouse down we got */
1523 st->info.timestamp = pe->timestamp;
1525 /* To test long tap */
1526 /* When this timer expires, gesture STARTED */
1528 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1529 _long_tap_timeout, gesture);
1532 consume_event(wd, event_info, event_type, ev_flag);
1533 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1534 st->center_x = st->info.x;
1535 st->center_y = st->info.y;
1538 case EVAS_CALLBACK_MULTI_UP:
1539 case EVAS_CALLBACK_MOUSE_UP:
1540 st->touched = _remove_touched_device(st->touched, pe);
1541 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1543 ((gesture->state == ELM_GESTURE_STATE_START) ||
1544 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1545 { /* Report END only for gesture that STARTed */
1546 if (eina_list_count(st->touched) == 0)
1547 { /* Report END only at last release event */
1548 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1549 &st->info, EINA_FALSE);
1550 consume_event(wd, event_info, event_type, ev_flag);
1554 { /* Stop test, user lifts finger before long-start */
1555 if (st->timeout) ecore_timer_del(st->timeout);
1557 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1558 &st->info, EINA_FALSE);
1559 consume_event(wd, event_info, event_type, ev_flag);
1564 case EVAS_CALLBACK_MULTI_MOVE:
1565 case EVAS_CALLBACK_MOUSE_MOVE:
1567 ((gesture->state == ELM_GESTURE_STATE_START) ||
1568 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1569 { /* Report MOVE only if STARTED */
1572 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1574 _compute_taps_center(st, &x, &y, pe);
1575 /* ABORT if user moved fingers out of tap area */
1576 #if defined(DEBUG_GESTURE_LAYER)
1577 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1579 if (!_inside(x, y, st->center_x, st->center_y))
1580 state_to_report = ELM_GESTURE_STATE_ABORT;
1582 /* Report MOVE if gesture started */
1583 ev_flag = _set_state(gesture, state_to_report,
1584 &st->info, EINA_TRUE);
1585 consume_event(wd, event_info, event_type, ev_flag);
1597 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1598 * This momentum value will be sent to widget when gesture is completed.
1600 * @param momentum pointer to buffer where we record momentum value.
1601 * @param x1 x coord where user started gesture.
1602 * @param y1 y coord where user started gesture.
1603 * @param x2 x coord where user completed gesture.
1604 * @param y2 y coord where user completed gesture.
1605 * @param t1x timestamp for X, when user started gesture.
1606 * @param t1y timestamp for Y, when user started gesture.
1607 * @param t2 timestamp when user completed gesture.
1609 * @ingroup Elm_Gesture_Layer
1612 _set_momentum(Elm_Gesture_Momentum_Info *momentum,
1613 Evas_Coord xx1, Evas_Coord yy1,
1614 Evas_Coord xx2, Evas_Coord yy2,
1615 unsigned int t1x, unsigned int t1y, unsigned int t2)
1617 Evas_Coord velx = 0, vely = 0, vel;
1618 Evas_Coord dx = xx2 - xx1;
1619 Evas_Coord dy = yy2 - yy1;
1623 velx = (dx * 1000) / dtx;
1626 vely = (dy * 1000) / dty;
1628 vel = sqrt((velx * velx) + (vely * vely));
1630 if ((_elm_config->thumbscroll_friction > 0.0) &&
1631 (vel > _elm_config->thumbscroll_momentum_threshold))
1632 { /* report momentum */
1633 momentum->mx = velx;
1634 momentum->my = vely;
1646 * This function is used for computing rotation angle (DEG).
1648 * @param x1 first finger x location.
1649 * @param y1 first finger y location.
1650 * @param x2 second finger x location.
1651 * @param y2 second finger y location.
1653 * @return angle of the line between (x1,y1), (x2,y2) in Deg.
1654 * Angles now are given in DEG, not RAD.
1655 * ZERO angle at 12-oclock, growing clockwise.
1657 * @ingroup Elm_Gesture_Layer
1660 get_angle(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2)
1662 double a, xx, yy, rt = (-1);
1663 xx = fabs(xx2 - xx1);
1664 yy = fabs(yy2 - yy1);
1666 if (((int)xx) && ((int)yy))
1668 rt = a = RAD2DEG(atan(yy / xx));
1671 if (yy1 < yy2) rt = 360 - a;
1676 if (yy1 < yy2) rt = 180 + a;
1682 { /* Do this only if rt is not set */
1684 { /* Horizontal line */
1685 if (xx2 < xx1) rt = 180;
1689 { /* Vertical line */
1690 if (yy2 < yy1) rt = 90;
1695 /* Now we want to change from:
1697 * original circle 180 0 We want: 270 90
1701 if (rt >= 360) rt -= 360;
1709 * This function is used for computing the magnitude and direction
1710 * of vector between two points.
1712 * @param x1 first finger x location.
1713 * @param y1 first finger y location.
1714 * @param x2 second finger x location.
1715 * @param y2 second finger y location.
1716 * @param l length computed (output)
1717 * @param a angle computed (output)
1719 * @ingroup Elm_Gesture_Layer
1722 get_vector(Evas_Coord xx1, Evas_Coord yy1, Evas_Coord xx2, Evas_Coord yy2,
1723 Evas_Coord *l, double *a)
1728 *l = (Evas_Coord) sqrt((xx * xx) + (yy * yy));
1729 *a = get_angle(xx1, yy1, xx2, yy2);
1733 _get_direction(Evas_Coord xx1, Evas_Coord xx2)
1735 if (xx2 < xx1) return -1;
1736 if (xx2 > xx1) return 1;
1742 * This function tests momentum gesture.
1743 * @param obj The gesture-layer object.
1744 * @param pe The recent input event as stored in pe struct.
1745 * @param event_info recent input event.
1746 * @param event_type recent event type.
1747 * @param g_type what Gesture we are testing.
1749 * @ingroup Elm_Gesture_Layer
1752 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1753 void *event_info, Evas_Callback_Type event_type,
1754 Elm_Gesture_Type g_type)
1756 Widget_Data *wd = elm_widget_data_get(obj);
1758 Gesture_Info *gesture = wd->gesture[g_type];
1759 if (!gesture ) return;
1761 /* When continues enable = TRUE a gesture may START on MOVE event */
1762 /* We don't allow this to happen with the if-statement below. */
1763 /* When continues enable = FALSE a gesture may START on DOWN only */
1764 /* Therefor it would NOT start on MOVE event. */
1765 /* NOTE that touched list is updated AFTER this function returns */
1766 /* so (count == 0) when we get here on first touch on surface. */
1767 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1768 return; /* Got move on mouse-over move */
1770 Momentum_Type *st = gesture->data;
1771 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1773 { /* Allocated once on first time */
1774 st = calloc(1, sizeof(Momentum_Type));
1776 _momentum_test_reset(gesture);
1782 /* First make avarage of all touched devices to determine center point */
1785 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1786 unsigned int cnt = 1; /* We start counter counting current pe event */
1787 EINA_LIST_FOREACH(wd->touched, l, p)
1788 if (p->device != pe_local.device)
1796 /* Compute avarage to get center point */
1800 /* If user added finger - reset gesture */
1801 if ((st->info.n) && (st->info.n < cnt))
1802 state_to_report = ELM_GESTURE_STATE_ABORT;
1805 if (st->info.n < cnt)
1808 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1811 case EVAS_CALLBACK_MOUSE_DOWN:
1812 case EVAS_CALLBACK_MULTI_DOWN:
1813 case EVAS_CALLBACK_MOUSE_MOVE:
1814 case EVAS_CALLBACK_MULTI_MOVE:
1817 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1818 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1819 (wd->glayer_continues_enable)) /* start also on MOVE */
1820 { /* We start on MOVE when cont-enabled only */
1821 st->line_st.x = st->line_end.x = pe_local.x;
1822 st->line_st.y = st->line_end.y = pe_local.y;
1823 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1824 st->xdir = st->ydir = 0;
1825 st->info.x2 = st->info.x1 = pe_local.x;
1826 st->info.y2 = st->info.y1 = pe_local.y;
1827 st->info.tx = st->info.ty = pe_local.timestamp;
1828 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1829 &st->info, EINA_FALSE);
1830 consume_event(wd, event_info, event_type, ev_flag);
1839 Eina_Bool force = EINA_TRUE; /* for move state */
1840 if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
1841 { /* ABORT if got DOWN or MOVE event after UP+timeout */
1842 state_to_report = ELM_GESTURE_STATE_ABORT;
1846 /* We report state but don't compute momentum now */
1847 ev_flag = _set_state(gesture, state_to_report, &st->info,
1849 consume_event(wd, event_info, event_type, ev_flag);
1850 return; /* Stop computing when user remove finger */
1853 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1854 { /* Too long of a wait, reset all values */
1855 st->line_st.x = pe_local.x;
1856 st->line_st.y = pe_local.y;
1857 st->t_st_y = st->t_st_x = pe_local.timestamp;
1858 st->info.tx = st->t_st_x;
1859 st->info.ty = st->t_st_y;
1860 st->xdir = st->ydir = 0;
1865 xdir = _get_direction(st->line_end.x, pe_local.x);
1866 ydir = _get_direction(st->line_end.y, pe_local.y);
1867 if (xdir && (xdir != st->xdir))
1869 st->line_st.x = st->line_end.x;
1870 st->info.tx = st->t_st_x = st->t_end;
1874 if (ydir && (ydir != st->ydir))
1876 st->line_st.y = st->line_end.y;
1877 st->info.ty = st->t_st_y = st->t_end;
1882 st->info.x2 = st->line_end.x = pe_local.x;
1883 st->info.y2 = st->line_end.y = pe_local.y;
1884 st->t_end = pe_local.timestamp;
1885 _set_momentum(&st->info, st->line_st.x, st->line_st.y,
1886 pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
1887 pe_local.timestamp);
1889 ev_flag = _set_state(gesture, state_to_report, &st->info,
1891 consume_event(wd, event_info, event_type, ev_flag);
1895 case EVAS_CALLBACK_MOUSE_UP:
1896 case EVAS_CALLBACK_MULTI_UP:
1897 st->t_up = pe_local.timestamp; /* Record recent up event time */
1898 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1899 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1902 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1903 { /* Too long of a wait, reset all values */
1904 st->line_st.x = pe_local.x;
1905 st->line_st.y = pe_local.y;
1906 st->t_st_y = st->t_st_x = pe_local.timestamp;
1907 st->xdir = st->ydir = 0;
1910 st->info.x2 = pe_local.x;
1911 st->info.y2 = pe_local.y;
1912 st->line_end.x = pe_local.x;
1913 st->line_end.y = pe_local.y;
1914 st->t_end = pe_local.timestamp;
1916 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
1917 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
1918 state_to_report = ELM_GESTURE_STATE_END;
1920 state_to_report = ELM_GESTURE_STATE_ABORT;
1922 ev_flag = _set_state(gesture, state_to_report, &st->info,
1924 consume_event(wd, event_info, event_type, ev_flag);
1933 compare_line_device(const void *data1, const void *data2)
1934 { /* Compare device component of line struct */
1935 const Line_Data *ln1 = data1;
1936 const int *device = data2;
1938 if (ln1->t_st) /* Compare only with lines that started */
1939 return (ln1->device - (*device));
1947 * This function construct line struct from input.
1948 * @param info pointer to store line momentum.
1949 * @param st line info to store input data.
1950 * @param pe The recent input event as stored in pe struct.
1952 * @ingroup Elm_Gesture_Layer
1955 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1956 Pointer_Event *pe, Evas_Callback_Type event_type)
1957 { /* Record events and set momentum for line pointed by st */
1963 case EVAS_CALLBACK_MOUSE_DOWN:
1964 case EVAS_CALLBACK_MOUSE_MOVE:
1965 case EVAS_CALLBACK_MULTI_DOWN:
1966 case EVAS_CALLBACK_MULTI_MOVE:
1968 { /* This happens only when line starts */
1969 st->line_st.x = pe->x;
1970 st->line_st.y = pe->y;
1971 st->t_st = pe->timestamp;
1972 st->device = pe->device;
1973 info->momentum.x1 = pe->x;
1974 info->momentum.y1 = pe->y;
1975 info->momentum.tx = pe->timestamp;
1976 info->momentum.ty = pe->timestamp;
1983 case EVAS_CALLBACK_MOUSE_UP:
1984 case EVAS_CALLBACK_MULTI_UP:
1985 /* IGNORE if line info was cleared, like long press, move */
1989 st->line_end.x = pe->x;
1990 st->line_end.y = pe->y;
1991 st->t_end = pe->timestamp;
2000 _line_data_reset(st);
2004 info->momentum.x2 = pe->x;
2005 info->momentum.y2 = pe->y;
2006 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2007 st->t_st, st->t_st, pe->timestamp);
2015 * This function test for (n) line gesture.
2016 * @param obj The gesture-layer object.
2017 * @param pe The recent input event as stored in pe struct.
2018 * @param event_info Original input event pointer.
2019 * @param event_type Type of original input event.
2020 * @param g_type what Gesture we are testing.
2022 * @ingroup Elm_Gesture_Layer
2025 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2026 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2030 Widget_Data *wd = elm_widget_data_get(obj);
2032 Gesture_Info *gesture = wd->gesture[g_type];
2033 if (!gesture ) return;
2035 /* When continues enable = TRUE a gesture may START on MOVE event */
2036 /* We don't allow this to happen with the if-statement below. */
2037 /* When continues enable = FALSE a gesture may START on DOWN only */
2038 /* Therefor it would NOT start on MOVE event. */
2039 /* NOTE that touched list is updated AFTER this function returns */
2040 /* so (count == 0) when we get here on first touch on surface. */
2041 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
2042 return; /* Got move on mouse-over move */
2044 Line_Type *st = gesture->data;
2047 st = calloc(1, sizeof(Line_Type));
2051 Line_Data *line = NULL;
2052 Eina_List *list = st->list;
2053 unsigned cnt = eina_list_count(list);
2056 { /* list is not empty, locate this device on list */
2057 line = (Line_Data *) eina_list_search_unsorted(st->list,
2058 compare_line_device, &pe->device);
2062 { /* List is empty or device not found, new line-struct on START only */
2063 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2064 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2065 ((wd->glayer_continues_enable) && /* START on MOVE also */
2066 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2067 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2068 { /* Allocate new item on START only */
2069 line = calloc(1, sizeof(Line_Data));
2070 _line_data_reset(line);
2071 list = eina_list_append(list, line);
2076 if (!line) /* This may happen on MOVE that comes before DOWN */
2077 return; /* No line-struct to work with, can't continue testing */
2079 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2080 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2082 /* Get direction and magnitude of the line */
2084 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2085 &line->line_length, &angle);
2087 /* These are used later to compare lines length */
2088 Evas_Coord shortest_line_len = line->line_length;
2089 Evas_Coord longest_line_len = line->line_length;
2090 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2092 /* Now update line-state */
2094 { /* Analyze line only if line started */
2095 if (line->line_angle >= 0.0)
2096 { /* if line direction was set, we test if broke tolerance */
2097 double a = fabs(angle - line->line_angle);
2099 double d = (tan(DEG2RAD(a))) * line->line_length; /* Distance from line */
2100 #if defined(DEBUG_GESTURE_LAYER)
2101 printf("%s a=<%f> d=<%f>\n", __func__, a, d);
2103 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2104 { /* Broke tolerance: abort line and start a new one */
2105 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2106 &st->info, EINA_FALSE);
2107 consume_event(wd, event_info, event_type, ev_flag);
2111 if (wd->glayer_continues_enable)
2112 { /* We may finish line if momentum is zero */
2113 /* This is for continues-gesture */
2114 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2115 { /* Finish line on zero momentum for continues gesture */
2116 line->line_end.x = pe->x;
2117 line->line_end.y = pe->y;
2118 line->t_end = pe->timestamp;
2123 { /* Record the line angle as it broke minimum length for line */
2124 if (line->line_length >= wd->line_min_length)
2125 st->info.angle = line->line_angle = angle;
2131 if (line->line_angle < 0.0)
2132 { /* it's not a line, too short more close to a tap */
2133 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2134 &st->info, EINA_FALSE);
2135 consume_event(wd, event_info, event_type, ev_flag);
2141 /* Count how many lines already started / ended */
2144 unsigned int tm_start = pe->timestamp;
2145 unsigned int tm_end = pe->timestamp;
2148 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2149 Eina_Bool lines_parallel = EINA_TRUE;
2150 EINA_LIST_FOREACH(list, l, t_line)
2153 base_angle = t_line->line_angle;
2156 if (t_line->line_angle >= 0)
2157 { /* Compare angle only with lines with direction defined */
2158 if (fabs(base_angle - t_line->line_angle) >
2159 wd->line_angular_tolerance)
2160 lines_parallel = EINA_FALSE;
2164 if (t_line->line_length)
2165 { /* update only if this line is used */
2166 if (shortest_line_len > t_line->line_length)
2167 shortest_line_len = t_line->line_length;
2169 if (longest_line_len < t_line->line_length)
2170 longest_line_len = t_line->line_length;
2176 if (t_line->t_st < tm_start)
2177 tm_start = t_line->t_st;
2183 if (t_line->t_end < tm_end)
2184 tm_end = t_line->t_end;
2188 st->info.momentum.n = started;
2192 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2193 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2194 { /* user lift one finger then starts again without line-end - ABORT */
2195 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2197 consume_event(wd, event_info, event_type, ev_flag);
2201 if (!lines_parallel)
2202 { /* Lines are NOT at same direction, abort this gesture */
2203 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2205 consume_event(wd, event_info, event_type, ev_flag);
2210 /* We report ABORT if lines length are NOT matching when fingers are up */
2211 if ((longest_line_len - shortest_line_len) > (_elm_config->finger_size * 2))
2213 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2215 consume_event(wd, event_info, event_type, ev_flag);
2219 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2220 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2221 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2223 consume_event(wd, event_info, event_type, ev_flag);
2229 case EVAS_CALLBACK_MOUSE_UP:
2230 case EVAS_CALLBACK_MULTI_UP:
2231 if ((started) && (started == ended))
2233 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2234 &st->info, EINA_FALSE);
2235 consume_event(wd, event_info, event_type, ev_flag);
2240 case EVAS_CALLBACK_MOUSE_DOWN:
2241 case EVAS_CALLBACK_MULTI_DOWN:
2242 case EVAS_CALLBACK_MOUSE_MOVE:
2243 case EVAS_CALLBACK_MULTI_MOVE:
2246 if (wd->glayer_continues_enable && (started == ended))
2247 { /* For continues gesture */
2248 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2249 &st->info, EINA_FALSE);
2250 consume_event(wd, event_info, event_type, ev_flag);
2253 { /* When continues, may START on MOVE event too */
2254 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2256 /* This happens when: on n > 1 lines then one finger up */
2257 /* caused abort, then put finger down. */
2258 /* This will stop line from starting again. */
2259 /* Number of lines, MUST match touched-device in list */
2260 if ((!wd->glayer_continues_enable) &&
2261 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2262 s = ELM_GESTURE_STATE_ABORT;
2264 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2265 s = ELM_GESTURE_STATE_START;
2267 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2268 consume_event(wd, event_info, event_type, ev_flag);
2274 return; /* Unhandeld event type */
2281 * This function is used to check if rotation gesture started.
2282 * @param st Contains current rotation values from user input.
2283 * @return TRUE/FALSE if we need to set rotation START.
2285 * @ingroup Elm_Gesture_Layer
2288 rotation_broke_tolerance(Rotate_Type *st)
2290 if (st->info.base_angle < 0)
2291 return EINA_FALSE; /* Angle has to be computed first */
2293 if (st->rotate_angular_tolerance < 0)
2296 double low = st->info.base_angle - st->rotate_angular_tolerance;
2297 double high = st->info.base_angle + st->rotate_angular_tolerance;
2298 double t = st->info.angle;
2322 #if defined(DEBUG_GESTURE_LAYER)
2323 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2325 if ((t < low) || (t > high))
2326 { /* This marks that roation action has started */
2327 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2328 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2338 * This function is used for computing the gap between fingers.
2339 * It returns the length and center point between fingers.
2341 * @param x1 first finger x location.
2342 * @param y1 first finger y location.
2343 * @param x2 second finger x location.
2344 * @param y2 second finger y location.
2345 * @param x Gets center point x cord (output)
2346 * @param y Gets center point y cord (output)
2348 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2350 * @ingroup Elm_Gesture_Layer
2353 get_finger_gap_length(Evas_Coord xx1, Evas_Coord yy1,
2354 Evas_Coord xx2, Evas_Coord yy2,
2355 Evas_Coord *x, Evas_Coord *y)
2357 double a, b, xx, yy, gap;
2358 xx = fabs(xx2 - xx1);
2359 yy = fabs(yy2 - yy1);
2360 gap = sqrt((xx * xx) + (yy * yy));
2362 /* START - Compute zoom center point */
2363 /* The triangle defined as follows:
2371 * http://en.wikipedia.org/wiki/Trigonometric_functions
2372 *************************************/
2373 if (((int)xx) && ((int)yy))
2375 double A = atan((yy / xx));
2376 #if defined(DEBUG_GESTURE_LAYER)
2377 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2379 a = (Evas_Coord) ((gap / 2) * sin(A));
2380 b = (Evas_Coord) ((gap / 2) * cos(A));
2381 *x = (Evas_Coord) ((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
2382 *y = (Evas_Coord) ((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
2387 { /* horiz line, take half width */
2388 #if defined(DEBUG_GESTURE_LAYER)
2389 printf("==== HORIZ ====\n");
2391 *x = (Evas_Coord) ((xx1 + xx2) / 2);
2392 *y = (Evas_Coord) (yy1);
2396 { /* vert line, take half width */
2397 #if defined(DEBUG_GESTURE_LAYER)
2398 printf("==== VERT ====\n");
2400 *x = (Evas_Coord) (xx1);
2401 *y = (Evas_Coord) ((yy1 + yy2) / 2);
2404 /* END - Compute zoom center point */
2406 return (Evas_Coord) gap;
2412 * This function is used for computing zoom value.
2414 * @param st Pointer to zoom data based on user input.
2415 * @param tm_end Recent input event timestamp.
2416 * @param zoom_val Current computed zoom value.
2418 * @return zoom momentum
2420 * @ingroup Elm_Gesture_Layer
2423 _zoom_momentum_get(Zoom_Type *st, unsigned int tm_end, double zoom_val)
2425 unsigned int tm_total;
2427 { /* Init, and we don't start computing momentum yet */
2428 st->m_st_tm = st->m_prev_tm = tm_end;
2429 st->m_base = zoom_val;
2433 if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
2434 return 0.0; /* we don't start to compute momentum yet */
2437 { /* if direction was already defined, check if changed */
2438 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2439 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2440 { /* Direction changed, reset momentum */
2442 st->dir = (-st->dir);
2447 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2449 if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
2451 st->m_st_tm = 0; /* Rest momentum when waiting too long */
2455 st->m_prev_tm = tm_end;
2456 tm_total = tm_end - st->m_st_tm;
2459 return ((zoom_val - st->m_base) * 1000) / tm_total;
2467 * This function is used for computing zoom value.
2469 * @param st Pointer to zoom data based on user input.
2470 * @param x1 first finger x location.
2471 * @param y1 first finger y location.
2472 * @param x2 second finger x location.
2473 * @param y2 second finger y location.
2474 * @param factor zoom-factor, used to determine how fast zoom works.
2476 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2478 * @ingroup Elm_Gesture_Layer
2481 compute_zoom(Zoom_Type *st,
2482 Evas_Coord xx1, Evas_Coord yy1,
2483 Evas_Coord xx2, Evas_Coord yy2,
2484 double zoom_finger_factor)
2487 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2488 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2490 Evas_Coord diam = get_finger_gap_length(xx1, yy1, xx2, yy2,
2491 &st->info.x, &st->info.y);
2493 st->info.radius = diam / 2;
2497 st->zoom_base = diam;
2498 return st->info.zoom;
2501 if (st->zoom_distance_tolerance)
2502 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2503 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2504 { /* avoid jump with zoom value when break tolerance */
2505 st->zoom_base -= st->zoom_distance_tolerance;
2506 st->zoom_distance_tolerance = 0;
2509 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2510 { /* avoid jump with zoom value when break tolerance */
2511 st->zoom_base += st->zoom_distance_tolerance;
2512 st->zoom_distance_tolerance = 0;
2518 /* We use factor only on the difference between gap-base */
2519 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2520 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2521 (float) st->zoom_base) * zoom_finger_factor));
2523 /* Momentum: zoom per second: */
2524 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
2532 * This function handles zoom with mouse wheel.
2533 * thats a combination of wheel + CTRL key.
2534 * @param obj The gesture-layer object.
2535 * @param event_info Original input event pointer.
2536 * @param event_type Type of original input event.
2537 * @param g_type what Gesture we are testing.
2539 * @ingroup Elm_Gesture_Layer
2542 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2543 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2545 Widget_Data *wd = elm_widget_data_get(obj);
2547 if (!wd->gesture[g_type]) return;
2549 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2550 Zoom_Type *st = gesture_zoom->data;
2551 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2553 { /* Allocated once on first time, used for zoom intermediate data */
2554 st = calloc(1, sizeof(Zoom_Type));
2555 gesture_zoom->data = st;
2556 _zoom_test_reset(gesture_zoom);
2561 case EVAS_CALLBACK_KEY_UP:
2563 Evas_Event_Key_Up *p = event_info;
2564 if ((!strcmp(p->keyname, "Control_L")) ||
2565 (!strcmp(p->keyname, "Control_R")))
2566 { /* Test if we ended a zoom gesture when releasing CTRL */
2567 if ((st->zoom_wheel) &&
2568 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2569 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2570 { /* User released CTRL after zooming */
2571 st->info.momentum = _zoom_momentum_get(st,
2572 p->timestamp, st->info.zoom);
2574 ev_flag = _set_state(gesture_zoom,
2575 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2576 consume_event(wd, event_info, event_type, ev_flag);
2584 case EVAS_CALLBACK_MOUSE_WHEEL:
2587 Elm_Gesture_State s;
2588 if (!evas_key_modifier_is_set(
2589 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2591 { /* if using wheel witout CTRL after starting zoom */
2592 if ((st->zoom_wheel) &&
2593 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2594 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2596 ev_flag = _set_state(gesture_zoom,
2597 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2598 consume_event(wd, event_info, event_type, ev_flag);
2603 return; /* Ignore mouse-wheel without control */
2606 /* Using mouse wheel with CTRL for zoom */
2607 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2608 { /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2609 we continue a zoom gesture */
2611 s = ELM_GESTURE_STATE_MOVE;
2614 { /* On first wheel event, report START */
2615 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2616 evas_object_evas_get(wd->target), "Control");
2618 s = ELM_GESTURE_STATE_START;
2619 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2620 ERR("Failed to Grabbed CTRL_L");
2621 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2622 ERR("Failed to Grabbed CTRL_R");
2625 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2626 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2627 st->info.x = st->zoom_wheel->canvas.x;
2628 st->info.y = st->zoom_wheel->canvas.y;
2630 if (st->zoom_wheel->z < 0) /* zoom in */
2631 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2633 if (st->zoom_wheel->z > 0) /* zoom out */
2634 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2636 if (st->info.zoom < 0.0)
2637 st->info.zoom = 0.0;
2639 st->info.momentum = _zoom_momentum_get(st,
2640 st->zoom_wheel->timestamp, st->info.zoom);
2642 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2643 consume_event(wd, event_info, event_type, ev_flag);
2655 * This function is used to test zoom gesture.
2656 * user may combine zoom, rotation together.
2657 * so its possible that both will be detected from input.
2658 * (both are two-finger movement-oriented gestures)
2660 * @param obj The gesture-layer object.
2661 * @param event_info Pointer to recent input event.
2662 * @param event_type Recent input event type.
2663 * @param g_type what Gesture we are testing.
2665 * @ingroup Elm_Gesture_Layer
2668 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2669 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2673 Widget_Data *wd = elm_widget_data_get(obj);
2675 if (!wd->gesture[g_type]) return;
2677 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2678 Zoom_Type *st = gesture_zoom->data;
2681 { /* Allocated once on first time, used for zoom data */
2682 st = calloc(1, sizeof(Zoom_Type));
2683 gesture_zoom->data = st;
2684 _zoom_test_reset(gesture_zoom);
2688 /* Start - new zoom testing, letting all fingers start */
2689 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2692 case EVAS_CALLBACK_MOUSE_MOVE:
2693 case EVAS_CALLBACK_MULTI_MOVE:
2694 /* if non-continues mode and gesture NOT started, ignore MOVE */
2695 if ((!wd->glayer_continues_enable) &&
2696 (!st->zoom_st.timestamp))
2699 case EVAS_CALLBACK_MOUSE_DOWN:
2700 case EVAS_CALLBACK_MULTI_DOWN:
2701 { /* Here we take care of zoom-start and zoom move */
2705 if (eina_list_count(wd->touched) > 2)
2706 { /* Process zoom only when 2 fingers on surface */
2707 ev_flag = _set_state(gesture_zoom,
2708 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2709 consume_event(wd, event_info, event_type, ev_flag);
2714 if (!st->zoom_st.timestamp)
2715 { /* Now scan touched-devices list and find other finger */
2716 EINA_LIST_FOREACH(wd->touched, l, p)
2717 { /* Device of other finger <> pe device */
2718 if (p->device != pe->device)
2722 if (!p) /* Single finger on touch */
2725 /* Record down fingers */
2726 consume_event(wd, event_info, event_type, ev_flag);
2727 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2728 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2730 /* Set mv field as well to be ready for MOVE events */
2731 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2732 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2734 /* Here we have zoom_st, zoom_st1 set, report START */
2735 /* Set zoom-base after BOTH down events recorded */
2736 /* Compute length of line between fingers zoom start */
2737 st->info.zoom = 1.0;
2738 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2739 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2740 &st->info.x, &st->info.y);
2742 st->info.radius = st->zoom_base / 2;
2744 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2745 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2746 { /* zoom started with mouse-wheel, don't report twice */
2747 ev_flag = _set_state(gesture_zoom,
2748 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2749 consume_event(wd, event_info, event_type, ev_flag);
2752 return; /* Zoom started */
2753 } /* End of ZOOM_START handling */
2756 /* if we got here, we have (exacally) two fingers on surfce */
2757 /* we also after START, report MOVE */
2758 /* First detect which finger moved */
2759 if (pe->device == st->zoom_mv.device)
2760 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2761 else if (pe->device == st->zoom_mv1.device)
2762 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2764 /* Compute change in zoom as fingers move */
2765 st->info.zoom = compute_zoom(st,
2766 st->zoom_mv.x, st->zoom_mv.y,
2767 st->zoom_mv1.x, st->zoom_mv1.y,
2768 wd->zoom_finger_factor);
2770 if (!st->zoom_distance_tolerance)
2771 { /* Zoom broke tolerance, report move */
2772 double d = st->info.zoom - st->next_step;
2776 if (d >= wd->zoom_step)
2777 { /* Report move in steps */
2778 st->next_step = st->info.zoom;
2780 ev_flag = _set_state(gesture_zoom,
2781 ELM_GESTURE_STATE_MOVE,
2782 &st->info, EINA_TRUE);
2783 consume_event(wd, event_info, event_type, ev_flag);
2785 } /* End of ZOOM_MOVE handling */
2790 case EVAS_CALLBACK_MOUSE_UP:
2791 case EVAS_CALLBACK_MULTI_UP:
2792 /* Reset timestamp of finger-up.This is used later
2793 by _zoom_test_reset() to retain finger-down data */
2794 consume_event(wd, event_info, event_type, ev_flag);
2795 if (((st->zoom_wheel) || (st->zoom_base)) &&
2796 (st->zoom_distance_tolerance == 0))
2798 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2799 &st->info, EINA_FALSE);
2800 consume_event(wd, event_info, event_type, ev_flag);
2805 /* if we got here not a ZOOM */
2806 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2807 { /* Must be != undefined, if gesture started */
2808 ev_flag = _set_state(gesture_zoom,
2809 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2810 consume_event(wd, event_info, event_type, ev_flag);
2813 _zoom_test_reset(gesture_zoom);
2823 _get_rotate_properties(Rotate_Type *st,
2824 Evas_Coord xx1, Evas_Coord yy1,
2825 Evas_Coord xx2, Evas_Coord yy2,
2827 { /* FIXME: Fix momentum computation, it's wrong */
2828 double prev_angle = *angle;
2829 st->info.radius = get_finger_gap_length(xx1, yy1, xx2, yy2,
2830 &st->info.x, &st->info.y) / 2;
2832 *angle = get_angle(xx1, yy1, xx2, yy2);
2834 if (angle == &st->info.angle)
2835 { /* Fingers are moving, compute momentum */
2836 unsigned int tm_start =
2837 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
2838 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
2839 unsigned int tm_end =
2840 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
2841 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
2843 unsigned int tm_total = tm_end - tm_start;
2845 { /* Momentum computed as:
2846 accumulated roation angle (deg) divided by time */
2848 if (((prev_angle < 90) && ((*angle) > 270)) ||
2849 ((prev_angle > 270) && ((*angle) < 90)))
2850 { /* We circle passing ZERO point */
2851 prev_angle = (*angle);
2853 else m = prev_angle - (*angle);
2855 st->accum_momentum += m;
2857 if ((tm_end - st->prev_momentum_tm) < 100)
2858 st->prev_momentum += m;
2861 if (fabs(st->prev_momentum) < 0.002)
2862 st->accum_momentum = 0.0; /* reset momentum */
2864 st->prev_momentum = 0.0; /* Start again */
2867 st->prev_momentum_tm = tm_end;
2868 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
2872 st->info.momentum = 0;
2878 * This function is used to test rotation gesture.
2879 * user may combine zoom, rotation together.
2880 * so its possible that both will be detected from input.
2881 * (both are two-finger movement-oriented gestures)
2883 * @param obj The gesture-layer object.
2884 * @param event_info Pointer to recent input event.
2885 * @param event_type Recent input event type.
2886 * @param g_type what Gesture we are testing.
2888 * @ingroup Elm_Gesture_Layer
2891 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2892 Evas_Callback_Type event_type, Elm_Gesture_Type g_type)
2897 Widget_Data *wd = elm_widget_data_get(obj);
2899 if (!wd->gesture[g_type]) return;
2901 Gesture_Info *gesture = wd->gesture[g_type];
2907 { /* Allocated once on first time */
2908 st = calloc(1, sizeof(Rotate_Type));
2910 _rotate_test_reset(gesture);
2914 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2917 case EVAS_CALLBACK_MOUSE_MOVE:
2918 case EVAS_CALLBACK_MULTI_MOVE:
2919 /* if non-continues mode and gesture NOT started, ignore MOVE */
2920 if ((!wd->glayer_continues_enable) &&
2921 (!st->rotate_st.timestamp))
2924 case EVAS_CALLBACK_MOUSE_DOWN:
2925 case EVAS_CALLBACK_MULTI_DOWN:
2926 { /* Here we take care of rotate-start and rotate move */
2930 if (eina_list_count(wd->touched) > 2)
2931 { /* Process rotate only when 2 fingers on surface */
2932 ev_flag = _set_state(gesture,
2933 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2934 consume_event(wd, event_info, event_type, ev_flag);
2939 if (!st->rotate_st.timestamp)
2940 { /* Now scan touched-devices list and find other finger */
2941 EINA_LIST_FOREACH(wd->touched, l, p)
2942 { /* Device of other finger <> pe device */
2943 if (p->device != pe->device)
2948 return; /* Single finger on touch */
2950 /* Record down fingers */
2951 consume_event(wd, event_info, event_type, ev_flag);
2952 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2953 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2955 /* Set mv field as well to be ready for MOVE events */
2956 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2957 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2959 /* Here we have rotate_st, rotate_st1 set, report START */
2960 /* Set rotate-base after BOTH down events recorded */
2961 /* Compute length of line between fingers rotate start */
2962 _get_rotate_properties(st,
2963 st->rotate_st.x, st->rotate_st.y,
2964 st->rotate_st1.x, st->rotate_st1.y,
2965 &st->info.base_angle);
2967 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2968 &st->info, EINA_FALSE);
2969 consume_event(wd, event_info, event_type, ev_flag);
2971 return; /* Rotate started */
2972 } /* End of ROTATE_START handling */
2975 /* if we got here, we have (exacally) two fingers on surfce */
2976 /* we also after START, report MOVE */
2977 /* First detect which finger moved */
2978 if (pe->device == st->rotate_mv.device)
2979 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2980 else if (pe->device == st->rotate_mv1.device)
2981 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2983 /* Compute change in rotate as fingers move */
2984 _get_rotate_properties(st,
2985 st->rotate_mv.x, st->rotate_mv.y,
2986 st->rotate_mv1.x, st->rotate_mv1.y,
2989 if (rotation_broke_tolerance(st))
2990 { /* Rotation broke tolerance, report move */
2991 double d = st->info.angle - st->next_step;
2995 if (d >= wd->rotate_step)
2996 { /* Report move in steps */
2997 st->next_step = st->info.angle;
2999 ev_flag = _set_state(gesture,
3000 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3001 consume_event(wd, event_info, event_type, ev_flag);
3003 } /* End of ROTATE_MOVE handling */
3008 case EVAS_CALLBACK_MOUSE_UP:
3009 case EVAS_CALLBACK_MULTI_UP:
3010 consume_event(wd, event_info, event_type, ev_flag);
3011 /* Reset timestamp of finger-up.This is used later
3012 by rotate_test_reset() to retain finger-down data */
3013 if (st->rotate_angular_tolerance < 0)
3015 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
3016 &st->info, EINA_FALSE);
3017 consume_event(wd, event_info, event_type, ev_flag);
3022 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3023 { /* Must be != undefined, if gesture started */
3024 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
3025 &st->info, EINA_FALSE);
3026 consume_event(wd, event_info, event_type, ev_flag);
3029 _rotate_test_reset(gesture);
3040 * This function is used to save input events in an abstract struct
3041 * to be used later by getsure-testing functions.
3043 * @param data The gesture-layer object.
3044 * @param event_info Pointer to recent input event.
3045 * @param event_type Recent input event type.
3046 * @param pe The abstract data-struct (output).
3048 * @ingroup Elm_Gesture_Layer
3051 _make_pointer_event(void *data, void *event_info,
3052 Evas_Callback_Type event_type, Pointer_Event *pe)
3054 Widget_Data *wd = elm_widget_data_get(data);
3055 if (!wd) return EINA_FALSE;
3057 memset(pe, '\0', sizeof(*pe));
3060 case EVAS_CALLBACK_MOUSE_DOWN:
3061 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
3062 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
3063 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
3064 pe->device = ELM_MOUSE_DEVICE;
3067 case EVAS_CALLBACK_MOUSE_UP:
3068 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
3069 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
3070 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
3071 pe->device = ELM_MOUSE_DEVICE;
3074 case EVAS_CALLBACK_MOUSE_MOVE:
3075 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
3076 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
3077 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
3078 pe->device = ELM_MOUSE_DEVICE;
3081 case EVAS_CALLBACK_MULTI_DOWN:
3082 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
3083 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
3084 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
3085 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
3088 case EVAS_CALLBACK_MULTI_UP:
3089 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
3090 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
3091 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
3092 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
3095 case EVAS_CALLBACK_MULTI_MOVE:
3096 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
3097 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
3098 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
3099 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
3106 pe->event_type = event_type;
3113 * This function restartes line, flick, zoom and rotate gestures
3114 * when gesture-layer continues-gestures enabled.
3115 * Example of continues-gesture:
3116 * When doing a line, user stops moving finger but keeps fingers on touch.
3117 * This will cause line-end, then as user continues moving his finger
3118 * it re-starts line gesture.
3119 * When continue mode is disabled, user has to lift finger from touch
3120 * to end a gesture. Them touch-again to start a new one.
3122 * @param data The gesture-layer object.
3123 * @param wd gesture layer widget data.
3124 * @param states_reset flag that marks gestures were reset in history clear.
3126 * @ingroup Elm_Gesture_Layer
3129 continues_gestures_restart(void *data, Eina_Bool states_reset)
3131 Widget_Data *wd = elm_widget_data_get(data);
3134 /* Run through events to restart gestures */
3136 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
3137 /* We turn-on flag for finished, aborted, not-started gestures */
3138 g = wd->gesture[ELM_GESTURE_MOMENTUM];
3139 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3140 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3143 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
3144 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3148 g = wd->gesture[ELM_GESTURE_N_LINES];
3149 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3150 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3153 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3154 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3158 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3159 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3160 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3163 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3164 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3168 g = wd->gesture[ELM_GESTURE_ZOOM];
3169 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3170 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3173 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3174 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3178 g = wd->gesture[ELM_GESTURE_ROTATE];
3179 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3180 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3183 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3184 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3192 * This function the core-function where input handling is done.
3193 * Here we get user input and stream it to gesture testing.
3194 * We notify user about any gestures with new state:
3196 * START - gesture started.
3197 * MOVE - gesture is ongoing.
3198 * END - gesture was completed.
3199 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3201 * We also check if a gesture was detected, then reset event history
3202 * If no gestures were found we reset gesture test flag
3203 * after streaming event-history to widget.
3204 * (stream to the widget all events not consumed as a gesture)
3206 * @param data The gesture-layer object.
3207 * @param event_info Pointer to recent input event.
3208 * @param event_type Recent input event type.
3210 * @ingroup Elm_Gesture_Layer
3213 _event_process(void *data, Evas_Object *obj __UNUSED__,
3214 void *event_info, Evas_Callback_Type event_type)
3217 Pointer_Event *pe = NULL;
3218 Widget_Data *wd = elm_widget_data_get(data);
3220 #if defined(DEBUG_GESTURE_LAYER)
3223 printf("Gesture | State | is tested\n");
3224 for (i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3228 printf(" %d %d %d\n", i, g->state, g->test);
3232 /* Start testing candidate gesture from here */
3233 if (_make_pointer_event(data, event_info, event_type, &_pe))
3236 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3237 _n_long_tap_test(data, pe, event_info, event_type,
3238 ELM_GESTURE_N_LONG_TAPS);
3240 /* This takes care of single, double and tripple tap */
3241 _tap_gestures_test(data, pe, event_info, event_type);
3243 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3244 _momentum_test(data, pe, event_info, event_type,
3245 ELM_GESTURE_MOMENTUM);
3247 if (IS_TESTED(ELM_GESTURE_N_LINES))
3248 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3250 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3251 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3253 if (_elm_config->glayer_zoom_finger_enable && IS_TESTED(ELM_GESTURE_ZOOM))
3254 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3256 if (IS_TESTED(ELM_GESTURE_ZOOM))
3257 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3259 if (_elm_config->glayer_rotate_finger_enable && IS_TESTED(ELM_GESTURE_ROTATE))
3260 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3262 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3263 _event_history_add(data, event_info, event_type);
3264 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3265 (event_type == EVAS_CALLBACK_MULTI_UP))
3267 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3270 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3271 _event_history_add(data, event_info, event_type);
3275 /* we maintain list of touched devices */
3276 /* We also use move to track current device x.y pos */
3277 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3278 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3279 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3280 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3282 wd->touched = _add_touched_device(wd->touched, pe);
3284 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3285 (event_type == EVAS_CALLBACK_MULTI_UP))
3287 wd->touched = _remove_touched_device(wd->touched, pe);
3290 /* Report current states and clear history if needed */
3291 Eina_Bool states_reset = _clear_if_finished(data);
3292 if (wd->glayer_continues_enable)
3293 continues_gestures_restart(data, states_reset);
3298 * For all _mouse_* / multi_* functions wethen send this event to
3299 * _event_process function.
3301 * @param data The gesture-layer object.
3302 * @param event_info Pointer to recent input event.
3304 * @ingroup Elm_Gesture_Layer
3307 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3310 Widget_Data *wd = elm_widget_data_get(data);
3312 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3313 return; /* We only process left-click at the moment */
3315 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3319 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3322 Widget_Data *wd = elm_widget_data_get(data);
3325 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3329 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3332 Widget_Data *wd = elm_widget_data_get(data);
3335 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3339 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3342 Widget_Data *wd = elm_widget_data_get(data);
3345 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3349 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3352 Widget_Data *wd = elm_widget_data_get(data);
3355 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3356 return; /* We only process left-click at the moment */
3358 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3362 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3365 Widget_Data *wd = elm_widget_data_get(data);
3368 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3372 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3375 Widget_Data *wd = elm_widget_data_get(data);
3378 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3382 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3385 Widget_Data *wd = elm_widget_data_get(data);
3388 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3392 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3395 Widget_Data *wd = elm_widget_data_get(data);
3398 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3402 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3404 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3406 Widget_Data *wd = elm_widget_data_get(obj);
3407 if (!wd) return EINA_FALSE;
3409 return !wd->repeat_events;
3413 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool hold_events)
3415 ELM_CHECK_WIDTYPE(obj, widtype);
3417 Widget_Data *wd = elm_widget_data_get(obj);
3420 wd->repeat_events = !(!!hold_events);
3424 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3426 ELM_CHECK_WIDTYPE(obj, widtype) 0;
3428 Widget_Data *wd = elm_widget_data_get(obj);
3431 return wd->zoom_step;
3435 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double step)
3437 ELM_CHECK_WIDTYPE(obj, widtype);
3439 Widget_Data *wd = elm_widget_data_get(obj);
3442 if (step < 0) return;
3444 wd->zoom_step = step;
3448 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3450 ELM_CHECK_WIDTYPE(obj, widtype) 0;
3452 Widget_Data *wd = elm_widget_data_get(obj);
3455 return wd->rotate_step;
3459 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double step)
3461 ELM_CHECK_WIDTYPE(obj, widtype);
3463 Widget_Data *wd = elm_widget_data_get(obj);
3466 if (step < 0) return;
3468 wd->rotate_step = step;
3472 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *target)
3474 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3476 Widget_Data *wd = elm_widget_data_get(obj);
3477 if (!wd) return EINA_FALSE;
3479 if (!target) return EINA_FALSE;
3481 /* if was attached before, unregister callbacks first */
3483 _unregister_callbacks(obj);
3485 wd->target = target;
3487 _register_callbacks(obj);
3492 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Type idx,
3493 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3495 ELM_CHECK_WIDTYPE(obj, widtype);
3497 Widget_Data *wd = elm_widget_data_get(obj);
3501 if (!wd->gesture[idx])
3502 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3503 if (!wd->gesture[idx]) return;
3505 p = wd->gesture[idx];
3508 p->fn[cb_type].cb = cb;
3509 p->fn[cb_type].user_data = data;
3510 p->state = ELM_GESTURE_STATE_UNDEFINED;
3515 _disable_hook(Evas_Object *obj)
3517 if (elm_widget_disabled_get(obj))
3518 _unregister_callbacks(obj);
3520 _register_callbacks(obj);
3524 elm_gesture_layer_add(Evas_Object *parent)
3530 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3532 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3533 elm_widget_type_set(obj, "gesture_layer");
3534 elm_widget_sub_object_add(parent, obj);
3535 elm_widget_data_set(obj, wd);
3536 elm_widget_del_hook_set(obj, _del_hook);
3537 elm_widget_disable_hook_set(obj, _disable_hook);
3540 wd->line_min_length =_elm_config->glayer_line_min_length * _elm_config->finger_size;
3541 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * _elm_config->finger_size;
3542 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * _elm_config->finger_size;
3543 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3544 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3545 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3546 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3547 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3548 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3549 wd->repeat_events = EINA_TRUE;
3550 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3552 #if defined(DEBUG_GESTURE_LAYER)
3553 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3554 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);
3556 memset(wd->gesture, 0, sizeof(wd->gesture));