2 # include "elementary_config.h"
5 #include <Elementary.h>
8 #define MY_CLASS ELM_GESTURE_LAYER_CLASS
10 #define MY_CLASS_NAME "Elm_Gesture_Layer"
11 #define MY_CLASS_NAME_LEGACY "elm_gesture_layer"
14 #define ELM_MOUSE_DEVICE 0
15 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
16 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
17 #define ELM_GESTURE_MOMENTUM_DELAY 25
18 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
19 #define ELM_GESTURE_MULTI_TIMEOUT 50
20 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
22 /* Some Trigo values */
23 #define RAD_90DEG M_PI_2
24 #define RAD_180DEG M_PI
25 #define RAD_270DEG (M_PI_2 * 3)
26 #define RAD_360DEG (M_PI * 2)
28 #define RAD2DEG(x) ((x) * 57.295779513)
29 #define DEG2RAD(x) ((x) / 57.295779513)
32 _glayer_buf_dup(void *buf, size_t size)
42 #define COPY_EVENT_INFO(EV) _glayer_buf_dup(EV, sizeof(*EV))
44 #define SET_TEST_BIT(P) \
46 P->test = P->cbs[ELM_GESTURE_STATE_START] || \
47 P->cbs[ELM_GESTURE_STATE_MOVE] || \
48 P->cbs[ELM_GESTURE_STATE_END] || \
49 P->cbs[ELM_GESTURE_STATE_ABORT]; \
52 #define IS_TESTED_GESTURE(gesture) \
53 ((gesture) ? (gesture)->test : EINA_FALSE)
55 #define IS_TESTED(T) \
56 ((sd->gesture[T]) ? sd->gesture[T]->test : EINA_FALSE)
58 #define ELM_GESTURE_LAYER_DATA_GET(o, sd) \
59 Elm_Gesture_Layer_Data * sd = eo_data_scope_get(o, MY_CLASS)
61 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN(o, ptr) \
62 ELM_GESTURE_LAYER_DATA_GET(o, ptr); \
65 CRI("No widget data for object %p (%s)", \
66 o, evas_object_type_get(o)); \
70 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
71 ELM_GESTURE_LAYER_DATA_GET(o, ptr); \
74 CRI("No widget data for object %p (%s)", \
75 o, evas_object_type_get(o)); \
79 #define ELM_GESTURE_LAYER_CHECK(obj) \
80 if (!obj || !eo_isa(obj, MY_CLASS)) \
86 * @struct _Pointer_Event
87 * Struct holds pointer-event info
88 * This is a generic pointer event structure
90 * @ingroup Elm_Gesture_Layer
95 unsigned int timestamp;
97 Evas_Callback_Type event_type;
103 * @typedef Pointer_Event
104 * Type for generic pointer event structure
106 * @ingroup Elm_Gesture_Layer
108 typedef struct _Pointer_Event Pointer_Event;
114 * Struct holds callback information.
116 * @ingroup Elm_Gesture_Layer
121 void *user_data; /**< Holds user data to CB (like sd) */
122 Elm_Gesture_Event_Cb cb;
129 * type for callback information
131 * @ingroup Elm_Gesture_Layer
133 typedef struct _Func_Data Func_Data;
138 * @struct _Gesture_Info
139 * Struct holds gesture info
141 * @ingroup Elm_Gesture_Layer
146 void *data; /**< Holds gesture intemidiate processing data */
147 Eina_Inlist *cbs[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info (Func_Data) for states */
148 Elm_Gesture_Type g_type; /**< gesture type */
149 Elm_Gesture_State state; /**< gesture state */
150 void *info; /**< Data for the state callback */
151 Eina_Bool test; /**< if true this gesture should be tested on input */
157 * @typedef Gesture_Info
158 * Type for _Gesture_Info
160 * @ingroup Elm_Gesture_Layer
162 typedef struct _Gesture_Info Gesture_Info;
166 void (*test)(Evas_Object *obj, Pointer_Event *pe,
167 void *event_info, Evas_Callback_Type event_type,
168 Elm_Gesture_Type g_type);
169 void (*reset)(Gesture_Info *gesture);
170 void (*cont_reset)(Gesture_Info *gesture); /* Can be NULL. */
173 /* functions referred by _glayer_tests_array */
174 static void _tap_gesture_test(Evas_Object *obj,
177 Evas_Callback_Type event_type,
178 Elm_Gesture_Type g_type);
179 static void _tap_gestures_test_reset(Gesture_Info *gesture);
180 static void _n_long_tap_test(Evas_Object *obj,
183 Evas_Callback_Type event_type,
184 Elm_Gesture_Type g_type);
185 static void _n_long_tap_test_reset(Gesture_Info *gesture);
186 static void _momentum_test(Evas_Object *obj,
189 Evas_Callback_Type event_type,
190 Elm_Gesture_Type g_type);
191 static void _momentum_test_reset(Gesture_Info *gesture);
192 static void _n_line_test(Evas_Object *obj,
195 Evas_Callback_Type event_type,
196 Elm_Gesture_Type g_type);
197 static void _line_test_reset(Gesture_Info *gesture);
198 static void _zoom_test(Evas_Object *obj,
201 Evas_Callback_Type event_type,
202 Elm_Gesture_Type g_type);
203 static void _zoom_test_reset(Gesture_Info *gesture);
204 static void _rotate_test(Evas_Object *obj,
207 Evas_Callback_Type event_type,
208 Elm_Gesture_Type g_type);
209 static void _rotate_test_reset(Gesture_Info *gesture);
211 static void _event_process(void *data,
214 Evas_Callback_Type event_type);
216 static void _callbacks_unregister(Evas_Object *obj);
218 /* Should be the same order as _Elm_Gesture_Type */
219 static Tests_Array_Funcs _glayer_tests_array[] = {
220 { NULL, NULL, NULL }, /** Because someone made an awful mistake. */
221 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
222 /* ELM_GESTURE_N_TAPS */
223 { _n_long_tap_test, _n_long_tap_test_reset, NULL },
224 /* ELM_GESTURE_N_LONG_TAPS */
225 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
226 /* ELM_GESTURE_N_DOUBLE_TAPS */
227 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
228 /* ELM_GESTURE_N_TRIPLE_TAPS */
229 { _momentum_test, _momentum_test_reset, _momentum_test_reset },
230 /* ELM_GESTURE_MOMENTUM */
231 { _n_line_test, _line_test_reset, _line_test_reset },
232 /* ELM_GESTURE_N_LINES */
233 { _n_line_test, _line_test_reset, _line_test_reset },
234 /* ELM_GESTURE_N_FLICKS */
235 { _zoom_test, _zoom_test_reset, _zoom_test_reset },
236 /* ELM_GESTURE_ZOOM */
237 { _rotate_test, _rotate_test_reset, _rotate_test_reset },
238 /* ELM_GESTURE_ROTATE */
245 * @struct _Event_History
246 * Struct holds event history.
247 * These events are repeated if no gesture found.
249 * @ingroup Elm_Gesture_Layer
251 struct _Event_History
255 Evas_Callback_Type event_type;
261 * @typedef Event_History
262 * Type for _Event_History
264 * @ingroup Elm_Gesture_Layer
266 typedef struct _Event_History Event_History;
268 /* All *Type structs hold result for the user in 'info' field
269 * The rest is gesture processing intermediate data.
270 * NOTE: info field must be FIRST in the struct.
271 * This is used when reporting ABORT in _event_history_clear() */
274 Elm_Gesture_Taps_Info info;
277 unsigned int n_taps_needed;
281 typedef struct _Taps_Type Taps_Type;
283 struct _Long_Tap_Type
285 Elm_Gesture_Taps_Info info;
288 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
291 typedef struct _Long_Tap_Type Long_Tap_Type;
293 struct _Momentum_Type /* Fields used by _line_test() */
295 Elm_Gesture_Momentum_Info info;
296 Evas_Coord_Point line_st;
297 Evas_Coord_Point line_end;
298 unsigned int t_st_x; /* Time start on X */
299 unsigned int t_st_y; /* Time start on Y */
300 unsigned int t_end; /* Time end */
301 unsigned int t_up; /* Recent up event time */
304 typedef struct _Momentum_Type Momentum_Type;
308 Evas_Coord_Point line_st;
309 Evas_Coord_Point line_end;
310 Evas_Coord line_length;
311 unsigned int t_st; /* Time start */
312 unsigned int t_end; /* Time end */
314 double line_angle; /* Current angle of line */
316 typedef struct _Line_Data Line_Data;
318 struct _Line_Type /* Fields used by _line_test() */
320 Elm_Gesture_Line_Info info;
321 Eina_List *list; /* List of Line_Data */
323 typedef struct _Line_Type Line_Type;
325 struct _Zoom_Type /* Fields used by _zoom_test() */
327 Elm_Gesture_Zoom_Info info;
328 Pointer_Event zoom_st;
329 Pointer_Event zoom_mv;
330 Pointer_Event zoom_st1;
331 Pointer_Event zoom_mv1;
332 Evas_Event_Mouse_Wheel *zoom_wheel;
333 Evas_Coord zoom_base; /* Holds gap between fingers on
335 Evas_Coord zoom_distance_tolerance;
336 unsigned int m_st_tm; /* momentum start time */
337 unsigned int m_prev_tm; /* momentum prev time */
338 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
339 double m_base; /* zoom value when momentum starts */
342 typedef struct _Zoom_Type Zoom_Type;
344 struct _Rotate_Type /* Fields used by _rotation_test() */
346 Elm_Gesture_Rotate_Info info;
347 Pointer_Event rotate_st;
348 Pointer_Event rotate_mv;
349 Pointer_Event rotate_st1;
350 Pointer_Event rotate_mv1;
351 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
352 double prev_momentum; /* Snapshot of momentum 0.01
354 double accum_momentum;
355 double rotate_angular_tolerance;
358 typedef struct _Rotate_Type Rotate_Type;
360 typedef struct _Elm_Gesture_Layer_Data Elm_Gesture_Layer_Data;
361 struct _Elm_Gesture_Layer_Data
363 Evas_Object *target; /* Target Widget */
364 Event_History *event_history_list;
367 Evas_Coord zoom_distance_tolerance;
368 Evas_Coord line_distance_tolerance;
369 double line_angular_tolerance;
370 double zoom_wheel_factor; /* mouse wheel zoom steps */
371 double zoom_finger_factor; /* used for zoom factor */
372 double rotate_angular_tolerance;
373 unsigned int flick_time_limit_ms;
374 double long_tap_start_timeout;
375 Eina_Bool glayer_continues_enable;
376 double double_tap_timeout;
381 Gesture_Info *gesture[ELM_GESTURE_LAST];
382 Eina_List *pending; /* List of devices need to refeed
384 Eina_List *touched; /* Information of touched devices */
387 Evas_Coord tap_finger_size; /* Default from Config */
388 Ecore_Timer *gest_taps_timeout; /* When this expires, dbl
389 * click/taps ABORTed */
391 Eina_Bool repeat_events : 1;
394 /* START - Functions to manage touched-device list */
397 * This function is used to find if device is touched
399 * @ingroup Elm_Gesture_Layer
402 _device_compare(const void *data1,
405 /* Compare the two device numbers */
406 return ((Pointer_Event *)data1)->device - ((Pointer_Event *)data2)->device;
412 * Remove Pointer Event from touched device list
413 * @param list Pointer to touched device list.
414 * @param Pointer_Event Pointer to PE.
416 * @ingroup Elm_Gesture_Layer
419 _touched_device_remove(Eina_List *list,
422 Eina_List *lst = NULL;
423 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
426 lst = eina_list_remove(list, p);
437 * Recoed Pointer Event in touched device list
438 * Note: This fuction allocates memory for PE event
439 * This memory is released in _touched_device_remove()
440 * @param list Pointer to touched device list.
441 * @param Pointer_Event Pointer to PE.
443 * @ingroup Elm_Gesture_Layer
446 _touched_device_add(Eina_List *list,
449 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
451 if (p) /* We like to track device touch-position, overwrite info */
453 memcpy(p, pe, sizeof(Pointer_Event));
457 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
458 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN)) /* Add touched
462 p = malloc(sizeof(Pointer_Event));
463 /* Freed in _touched_device_remove() */
464 memcpy(p, pe, sizeof(Pointer_Event));
465 return eina_list_append(list, p);
471 /* END - Functions to manage touched-device list */
477 * @param event_info pointer to event.
479 * @ingroup Elm_Gesture_Layer
481 static Evas_Event_Flags
482 _event_flag_get(void *event_info,
483 Evas_Callback_Type event_type)
487 case EVAS_CALLBACK_MOUSE_IN:
488 return ((Evas_Event_Mouse_In *)event_info)->event_flags;
490 case EVAS_CALLBACK_MOUSE_OUT:
491 return ((Evas_Event_Mouse_Out *)event_info)->event_flags;
493 case EVAS_CALLBACK_MOUSE_DOWN:
494 return ((Evas_Event_Mouse_Down *)event_info)->event_flags;
496 case EVAS_CALLBACK_MOUSE_MOVE:
497 return ((Evas_Event_Mouse_Move *)event_info)->event_flags;
499 case EVAS_CALLBACK_MOUSE_UP:
500 return ((Evas_Event_Mouse_Up *)event_info)->event_flags;
502 case EVAS_CALLBACK_MOUSE_WHEEL:
503 return ((Evas_Event_Mouse_Wheel *)event_info)->event_flags;
505 case EVAS_CALLBACK_MULTI_DOWN:
506 return ((Evas_Event_Multi_Down *)event_info)->event_flags;
508 case EVAS_CALLBACK_MULTI_MOVE:
509 return ((Evas_Event_Multi_Move *)event_info)->event_flags;
511 case EVAS_CALLBACK_MULTI_UP:
512 return ((Evas_Event_Multi_Up *)event_info)->event_flags;
514 case EVAS_CALLBACK_KEY_DOWN:
515 return ((Evas_Event_Key_Down *)event_info)->event_flags;
517 case EVAS_CALLBACK_KEY_UP:
518 return ((Evas_Event_Key_Up *)event_info)->event_flags;
521 return EVAS_EVENT_FLAG_NONE;
528 * Sets event flag to value returned from user callback
529 * @param sd Widget Data
530 * @param event_info pointer to event.
531 * @param event_type what type was ev (mouse down, etc...)
532 * @param ev_flags event flags
534 * @ingroup Elm_Gesture_Layer
537 _event_consume(Elm_Gesture_Layer_Data *sd,
539 Evas_Callback_Type event_type,
540 Evas_Event_Flags ev_flags)
542 /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
543 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
544 /* should not refeed this event. */
546 return; /* This happens when restarting gestures */
548 if (!sd->repeat_events) ev_flags |= EVAS_EVENT_FLAG_ON_HOLD;
554 case EVAS_CALLBACK_MOUSE_DOWN:
555 ((Evas_Event_Mouse_Down *)event_info)->event_flags |= ev_flags;
558 case EVAS_CALLBACK_MOUSE_MOVE:
559 ((Evas_Event_Mouse_Move *)event_info)->event_flags |= ev_flags;
562 case EVAS_CALLBACK_MOUSE_UP:
563 ((Evas_Event_Mouse_Up *)event_info)->event_flags |= ev_flags;
566 case EVAS_CALLBACK_MOUSE_WHEEL:
567 ((Evas_Event_Mouse_Wheel *)event_info)->event_flags |= ev_flags;
570 case EVAS_CALLBACK_MULTI_DOWN:
571 ((Evas_Event_Multi_Down *)event_info)->event_flags |= ev_flags;
574 case EVAS_CALLBACK_MULTI_MOVE:
575 ((Evas_Event_Multi_Move *)event_info)->event_flags |= ev_flags;
578 case EVAS_CALLBACK_MULTI_UP:
579 ((Evas_Event_Multi_Up *)event_info)->event_flags |= ev_flags;
582 case EVAS_CALLBACK_KEY_DOWN:
583 ((Evas_Event_Key_Down *)event_info)->event_flags |= ev_flags;
586 case EVAS_CALLBACK_KEY_UP:
587 ((Evas_Event_Key_Up *)event_info)->event_flags |= ev_flags;
599 * Report current state of a gesture by calling user callback.
600 * @param gesture what gesture state we report.
601 * @param info inforamtion for user callback
603 * @ingroup Elm_Gesture_Layer
605 static Evas_Event_Flags
606 _state_report(Gesture_Info *gesture,
609 Evas_Event_Flags flags = EVAS_EVENT_FLAG_NONE;
610 /* We report current state (START, MOVE, END, ABORT), once */
611 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
612 (gesture->cbs[gesture->state])) /* Fill state-info struct and
617 EINA_INLIST_FOREACH(gesture->cbs[gesture->state], cb_info)
618 flags |= cb_info->cb(cb_info->user_data, info);
621 return EVAS_EVENT_FLAG_NONE;
627 * Update state for a given gesture.
628 * We may update gesture state to:
629 * - @c UNDEFINED - current input did not start gesure yet.
630 * - @c START - gesture started according to input.
631 * - @c MOVE - gusture in progress.
632 * - @c END - gesture completed according to input.
633 * - @c ABORT - input does not matches gesure.
634 * note that we may move from UNDEFINED to ABORT
635 * because we may detect that gesture will not START
636 * with a given input.
638 * @param g given gesture to change state.
639 * @param s gesure new state.
640 * @param info buffer to be sent to user callback on report_state.
641 * @param force makes report_state to report the new-state even
642 * if its same as current state. Works for MOVE - gesture in progress.
644 * @ingroup Elm_Gesture_Layer
646 static Evas_Event_Flags
647 _state_set(Gesture_Info *g,
652 Elm_Gesture_State old_state;
654 if ((g->state == s) && (!force))
655 return EVAS_EVENT_FLAG_NONE;
657 old_state = g->state;
660 g->info = info; /* Information for user callback */
661 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
662 (g->state == ELM_GESTURE_STATE_END))
663 g->test = EINA_FALSE;
665 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
666 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
667 (s == ELM_GESTURE_STATE_ABORT))))
668 return _state_report(g, g->info);
670 return EVAS_EVENT_FLAG_NONE;
676 * This resets all gesture states and sets test-bit.
677 * this is used for restarting gestures to listen to input.
678 * happens after we complete a gesture or no gesture was detected.
679 * @param sd Widget data of the gesture-layer object.
681 * @ingroup Elm_Gesture_Layer
684 _states_reset(Elm_Gesture_Layer_Data *sd)
689 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
694 _state_set(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
703 * This function is used to save input events in an abstract struct
704 * to be used later by getsure-testing functions.
706 * @param data The gesture-layer object.
707 * @param event_info Pointer to recent input event.
708 * @param event_type Recent input event type.
709 * @param pe The abstract data-struct (output).
711 * @ingroup Elm_Gesture_Layer
714 _pointer_event_make(void *data EINA_UNUSED,
716 Evas_Callback_Type event_type,
719 memset(pe, '\0', sizeof(*pe));
722 case EVAS_CALLBACK_MOUSE_DOWN:
723 pe->x = ((Evas_Event_Mouse_Down *)event_info)->canvas.x;
724 pe->y = ((Evas_Event_Mouse_Down *)event_info)->canvas.y;
725 pe->timestamp = ((Evas_Event_Mouse_Down *)event_info)->timestamp;
726 pe->device = ELM_MOUSE_DEVICE;
729 case EVAS_CALLBACK_MOUSE_UP:
730 pe->x = ((Evas_Event_Mouse_Up *)event_info)->canvas.x;
731 pe->y = ((Evas_Event_Mouse_Up *)event_info)->canvas.y;
732 pe->timestamp = ((Evas_Event_Mouse_Up *)event_info)->timestamp;
733 pe->device = ELM_MOUSE_DEVICE;
736 case EVAS_CALLBACK_MOUSE_MOVE:
737 pe->x = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.x;
738 pe->y = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.y;
739 pe->timestamp = ((Evas_Event_Mouse_Move *)event_info)->timestamp;
740 pe->device = ELM_MOUSE_DEVICE;
743 case EVAS_CALLBACK_MULTI_DOWN:
744 pe->x = ((Evas_Event_Multi_Down *)event_info)->canvas.x;
745 pe->y = ((Evas_Event_Multi_Down *)event_info)->canvas.y;
746 pe->timestamp = ((Evas_Event_Multi_Down *)event_info)->timestamp;
747 pe->device = ((Evas_Event_Multi_Down *)event_info)->device;
750 case EVAS_CALLBACK_MULTI_UP:
751 pe->x = ((Evas_Event_Multi_Up *)event_info)->canvas.x;
752 pe->y = ((Evas_Event_Multi_Up *)event_info)->canvas.y;
753 pe->timestamp = ((Evas_Event_Multi_Up *)event_info)->timestamp;
754 pe->device = ((Evas_Event_Multi_Up *)event_info)->device;
757 case EVAS_CALLBACK_MULTI_MOVE:
758 pe->x = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.x;
759 pe->y = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.y;
760 pe->timestamp = ((Evas_Event_Multi_Move *)event_info)->timestamp;
761 pe->device = ((Evas_Event_Multi_Move *)event_info)->device;
768 pe->event_type = event_type;
775 * This function copies input events.
776 * We copy event info before adding it to history.
777 * The memory is freed when we clear history.
779 * @param event the event to copy
780 * @param event_type event type to copy
782 * @ingroup Elm_Gesture_Layer
785 _event_info_copy(void *event,
786 Evas_Callback_Type event_type)
790 case EVAS_CALLBACK_MOUSE_DOWN:
791 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *)event);
794 case EVAS_CALLBACK_MOUSE_MOVE:
795 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *)event);
798 case EVAS_CALLBACK_MOUSE_UP:
799 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *)event);
802 case EVAS_CALLBACK_MOUSE_WHEEL:
803 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *)event);
806 case EVAS_CALLBACK_MULTI_DOWN:
807 return COPY_EVENT_INFO((Evas_Event_Multi_Down *)event);
810 case EVAS_CALLBACK_MULTI_MOVE:
811 return COPY_EVENT_INFO((Evas_Event_Multi_Move *)event);
814 case EVAS_CALLBACK_MULTI_UP:
815 return COPY_EVENT_INFO((Evas_Event_Multi_Up *)event);
818 case EVAS_CALLBACK_KEY_DOWN:
819 return COPY_EVENT_INFO((Evas_Event_Key_Down *)event);
822 case EVAS_CALLBACK_KEY_UP:
823 return COPY_EVENT_INFO((Evas_Event_Key_Up *)event);
832 _event_history_add(Evas_Object *obj,
834 Evas_Callback_Type event_type)
838 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
840 ev = malloc(sizeof(Event_History));
841 ev->event = _event_info_copy(event, event_type); /* Freed on
842 * _event_history_clear */
843 ev->event_type = event_type;
844 sd->event_history_list = (Event_History *)eina_inlist_append(
845 EINA_INLIST_GET(sd->event_history_list), EINA_INLIST_GET(ev));
851 * For all _mouse_* / multi_* functions wethen send this event to
852 * _event_process function.
854 * @param data The gesture-layer object.
855 * @param event_info Pointer to recent input event.
857 * @ingroup Elm_Gesture_Layer
860 _mouse_down_cb(void *data,
862 Evas_Object *obj EINA_UNUSED,
865 if (((Evas_Event_Mouse_Down *)event_info)->button != 1)
866 return; /* We only process left-click at the moment */
868 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
872 _mouse_move_cb(void *data,
874 Evas_Object *obj EINA_UNUSED,
877 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
881 _key_down_cb(void *data,
883 Evas_Object *obj EINA_UNUSED,
886 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
890 _key_up_cb(void *data,
892 Evas_Object *obj EINA_UNUSED,
895 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
899 _mouse_up_cb(void *data,
901 Evas_Object *obj EINA_UNUSED,
904 if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
905 return; /* We only process left-click at the moment */
907 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
911 _mouse_wheel_cb(void *data,
913 Evas_Object *obj EINA_UNUSED,
916 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
920 _multi_down_cb(void *data,
922 Evas_Object *obj EINA_UNUSED,
925 /* Skip the mouse duplicates. */
926 if (((Evas_Event_Multi_Down *) event_info)->device == 0) return;
928 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
932 _multi_move_cb(void *data,
934 Evas_Object *obj EINA_UNUSED,
937 /* Skip the mouse duplicates. */
938 if (((Evas_Event_Multi_Move *) event_info)->device == 0) return;
940 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
944 _multi_up_cb(void *data,
946 Evas_Object *obj EINA_UNUSED,
949 /* Skip the mouse duplicates. */
950 if (((Evas_Event_Multi_Up *) event_info)->device == 0) return;
952 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
956 _target_del_cb(void *data,
958 Evas_Object *obj EINA_UNUSED,
959 void *event_info EINA_UNUSED)
961 _callbacks_unregister(data);
962 ELM_GESTURE_LAYER_DATA_GET(data, sd);
969 * We register callbacks when gesture layer is attached to an object
970 * or when its enabled after disable.
972 * @param obj The gesture-layer object.
974 * @ingroup Elm_Gesture_Layer
977 _callbacks_register(Evas_Object *obj)
979 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
981 if (!sd->target) return;
983 evas_object_event_callback_add
984 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
985 evas_object_event_callback_add
986 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
987 evas_object_event_callback_add
988 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
990 evas_object_event_callback_add
991 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
993 evas_object_event_callback_add
994 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
995 evas_object_event_callback_add
996 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
997 evas_object_event_callback_add
998 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1000 evas_object_event_callback_add
1001 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1002 evas_object_event_callback_add
1003 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1005 evas_object_event_callback_add
1006 (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1012 * We unregister callbacks when gesture layer is disabled.
1014 * @param obj The gesture-layer object.
1016 * @ingroup Elm_Gesture_Layer
1019 _callbacks_unregister(Evas_Object *obj)
1021 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1023 if (!sd->target) return;
1025 evas_object_event_callback_del_full
1026 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
1027 evas_object_event_callback_del_full
1028 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
1029 evas_object_event_callback_del_full
1030 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
1032 evas_object_event_callback_del_full
1033 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
1035 evas_object_event_callback_del_full
1036 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
1038 evas_object_event_callback_del_full
1039 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
1041 evas_object_event_callback_del_full
1042 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1044 evas_object_event_callback_del_full
1045 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1046 evas_object_event_callback_del_full
1047 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1049 evas_object_event_callback_del_full
1050 (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
1055 * This function is used to find if device number
1056 * is found in a list of devices.
1057 * The list contains devices for refeeding *UP event
1059 * @ingroup Elm_Gesture_Layer
1062 _device_in_pending_cmp(const void *data1,
1065 /* Compare the two device numbers */
1066 return ((intptr_t)data1) - ((intptr_t)data2);
1072 * This functions returns pending-device node
1073 * @ingroup Elm_Gesture_Layer
1076 _device_is_pending(Eina_List *list,
1078 Evas_Callback_Type event_type)
1080 int device = ELM_MOUSE_DEVICE;
1084 case EVAS_CALLBACK_MOUSE_UP:
1087 case EVAS_CALLBACK_MULTI_UP:
1088 device = ((Evas_Event_Multi_Up *)event)->device;
1095 return eina_list_search_unsorted_list
1096 (list, _device_in_pending_cmp, (void *)(intptr_t)device);
1102 * This functions adds device to refeed-pending device list
1103 * @ingroup Elm_Gesture_Layer
1106 _pending_device_add(Eina_List *list,
1108 Evas_Callback_Type event_type)
1110 int device = ELM_MOUSE_DEVICE;
1114 case EVAS_CALLBACK_MOUSE_DOWN:
1117 case EVAS_CALLBACK_MULTI_DOWN:
1118 device = ((Evas_Event_Multi_Down *)event)->device;
1125 if (!eina_list_search_unsorted_list
1126 (list, _device_in_pending_cmp, (void *)(intptr_t)device))
1128 return eina_list_append(list, (void *)(intptr_t)device);
1137 * This function reports ABORT to all none-detected gestures
1138 * Then resets test bits for all desired gesures
1139 * and clears input-events history.
1140 * note: if no gesture was detected, events from history list
1141 * are streamed to the widget because it's unused by layer.
1142 * user may cancel refeed of events by setting repeat events.
1144 * @param obj The gesture-layer object.
1146 * @ingroup Elm_Gesture_Layer
1149 _event_history_clear(Evas_Object *obj)
1153 Evas *e = evas_object_evas_get(obj);
1154 Eina_Bool gesture_found = EINA_FALSE;
1156 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1158 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1163 if (p->state == ELM_GESTURE_STATE_END)
1165 gesture_found = EINA_TRUE;
1168 { /* Report ABORT to all gestures that still not finished */
1170 _state_set(p, ELM_GESTURE_STATE_ABORT,
1171 sd->gesture[i]->info, EINA_FALSE);
1176 _states_reset(sd); /* we are ready to start testing for gestures again */
1178 /* Clear all gestures intermediate data */
1180 /* FIXME: +1 because of the mistake in the enum. */
1181 Gesture_Info **gitr = sd->gesture + 1;
1182 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1183 for (; fitr->reset; fitr++, gitr++)
1185 if (IS_TESTED_GESTURE(*gitr))
1190 /* Disable gesture layer so refeeded events won't be consumed by it */
1191 _callbacks_unregister(obj);
1192 while (sd->event_history_list)
1195 t = sd->event_history_list;
1196 Eina_List *pending = _device_is_pending
1197 (sd->pending, sd->event_history_list->event,
1198 sd->event_history_list->event_type);
1200 /* Refeed events if no gesture matched input */
1201 if (pending || ((!gesture_found) && (!sd->repeat_events)))
1203 evas_event_refeed_event(e, sd->event_history_list->event,
1204 sd->event_history_list->event_type);
1208 sd->pending = eina_list_remove_list(sd->pending, pending);
1212 sd->pending = _pending_device_add
1213 (sd->pending, sd->event_history_list->event,
1214 sd->event_history_list->event_type);
1218 free(sd->event_history_list->event);
1219 sd->event_history_list = (Event_History *)eina_inlist_remove(
1220 EINA_INLIST_GET(sd->event_history_list),
1221 EINA_INLIST_GET(sd->event_history_list));
1224 _callbacks_register(obj);
1231 * if gesture was NOT detected AND we only have gestures in ABORT state
1232 * we clear history immediately to be ready for input.
1234 * @param obj The gesture-layer object.
1235 * @return TRUE on event history_clear
1237 * @ingroup Elm_Gesture_Layer
1240 _clear_if_finished(Evas_Object *obj)
1243 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
1245 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1247 /* Clear history if all we have aborted gestures */
1248 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1249 { /* If no gesture started and all we have aborted gestures, reset all */
1250 Gesture_Info *p = sd->gesture[i];
1252 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
1254 if ((p->state == ELM_GESTURE_STATE_START) ||
1255 (p->state == ELM_GESTURE_STATE_MOVE))
1256 reset_s = EINA_FALSE;
1258 all_undefined = EINA_FALSE;
1262 if (reset_s && (!all_undefined))
1263 return _event_history_clear(obj);
1271 * This function restartes line, flick, zoom and rotate gestures
1272 * when gesture-layer continues-gestures enabled.
1273 * Example of continues-gesture:
1274 * When doing a line, user stops moving finger but keeps fingers on touch.
1275 * This will cause line-end, then as user continues moving his finger
1276 * it re-starts line gesture.
1277 * When continue mode is disabled, user has to lift finger from touch
1278 * to end a gesture. Them touch-again to start a new one.
1280 * @param data The gesture-layer object.
1281 * @param sd gesture layer widget data.
1282 * @param states_reset flag that marks gestures were reset in history clear.
1284 * @ingroup Elm_Gesture_Layer
1287 _continues_gestures_restart(void *data,
1288 Eina_Bool states_reset)
1290 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1292 /* Test all the gestures */
1294 /* FIXME: +1 because of the mistake in the enum. */
1295 Gesture_Info **gitr = sd->gesture + 1;
1296 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1297 for (; fitr->test; fitr++, gitr++)
1299 Gesture_Info *g = *gitr;
1300 Eina_Bool tmp = (g) ?
1301 ((states_reset) || ((g->state != ELM_GESTURE_STATE_START)
1302 && (g->state != ELM_GESTURE_STATE_MOVE)))
1304 if (tmp && fitr->cont_reset)
1306 fitr->cont_reset(g);
1307 _state_set(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
1317 * This function the core-function where input handling is done.
1318 * Here we get user input and stream it to gesture testing.
1319 * We notify user about any gestures with new state:
1321 * START - gesture started.
1322 * MOVE - gesture is ongoing.
1323 * END - gesture was completed.
1324 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
1326 * We also check if a gesture was detected, then reset event history
1327 * If no gestures were found we reset gesture test flag
1328 * after streaming event-history to widget.
1329 * (stream to the widget all events not consumed as a gesture)
1331 * @param data The gesture-layer object.
1332 * @param event_info Pointer to recent input event.
1333 * @param event_type Recent input event type.
1335 * @ingroup Elm_Gesture_Layer
1338 _event_process(void *data,
1339 Evas_Object *obj EINA_UNUSED,
1341 Evas_Callback_Type event_type)
1344 Pointer_Event *pe = NULL;
1346 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1348 /* Start testing candidate gesture from here */
1349 if (_pointer_event_make(data, event_info, event_type, &_pe))
1352 /* Test all the gestures */
1354 /* FIXME: +1 because of the mistake in the enum. */
1355 Gesture_Info **gitr = sd->gesture + 1;
1356 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1357 for (; fitr->test; fitr++, gitr++)
1359 if (IS_TESTED_GESTURE(*gitr))
1360 fitr->test(data, pe, event_info, event_type, (*gitr)->g_type);
1364 if (_event_flag_get(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
1365 _event_history_add(data, event_info, event_type);
1367 /* we maintain list of touched devices */
1368 /* We also use move to track current device x.y pos */
1369 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1370 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1371 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1372 (event_type == EVAS_CALLBACK_MULTI_MOVE))
1374 sd->touched = _touched_device_add(sd->touched, pe);
1376 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
1377 (event_type == EVAS_CALLBACK_MULTI_UP))
1379 sd->touched = _touched_device_remove(sd->touched, pe);
1382 /* Report current states and clear history if needed */
1383 Eina_Bool states_reset = _clear_if_finished(data);
1384 if (sd->glayer_continues_enable)
1385 _continues_gestures_restart(data, states_reset);
1389 _inside(Evas_Coord xx1,
1395 w >>= 1; /* Use half the distance, from center to all directions */
1396 if (!w) /* use system default instead */
1397 w = elm_config_finger_size_get() >> 1; /* Finger size devided by 2 */
1399 if (xx1 < (xx2 - w))
1402 if (xx1 > (xx2 + w))
1405 if (yy1 < (yy2 - w))
1408 if (yy1 > (yy2 + w))
1414 /* All *test_reset() funcs are called to clear
1415 * gesture intermediate data.
1416 * This happens when we need to reset our tests.
1417 * for example when gesture is detected or all ABORTed. */
1419 _tap_gestures_test_reset(Gesture_Info *gesture)
1424 EINA_SAFETY_ON_NULL_RETURN(gesture);
1425 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1427 ELM_SAFE_FREE(sd->gest_taps_timeout, ecore_timer_del);
1432 EINA_LIST_FREE(((Taps_Type *)gesture->data)->l, data)
1433 EINA_LIST_FREE(data, pe)
1436 memset(gesture->data, 0, sizeof(Taps_Type));
1439 /* All *test_reset() funcs are called to clear
1440 * gesture intermediate data.
1441 * This happens when we need to reset our tests.
1442 * for example when gesture is detected or all ABORTed. */
1444 _n_long_tap_test_reset(Gesture_Info *gesture)
1449 EINA_SAFETY_ON_NULL_RETURN(gesture);
1450 if (!gesture->data) return;
1454 EINA_LIST_FREE(st->touched, p)
1458 ELM_SAFE_FREE(st->timeout, ecore_timer_del);
1459 memset(gesture->data, 0, sizeof(Long_Tap_Type));
1463 _momentum_test_reset(Gesture_Info *gesture)
1465 EINA_SAFETY_ON_NULL_RETURN(gesture);
1466 if (!gesture->data) return;
1468 memset(gesture->data, 0, sizeof(Momentum_Type));
1472 _line_data_reset(Line_Data *st)
1477 memset(st, 0, sizeof(Line_Data));
1478 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1482 _line_test_reset(Gesture_Info *gesture)
1487 EINA_SAFETY_ON_NULL_RETURN(gesture);
1488 if (!gesture->data) return;
1492 EINA_LIST_FREE(st->list, t_line)
1498 _zoom_test_reset(Gesture_Info *gesture)
1501 Evas_Modifier_Mask mask;
1503 EINA_SAFETY_ON_NULL_RETURN(gesture);
1504 if (!gesture->data) return;
1505 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1508 mask = evas_key_modifier_mask_get(
1509 evas_object_evas_get(sd->target), "Control");
1510 evas_object_key_ungrab(sd->target, "Control_L", mask, 0);
1511 evas_object_key_ungrab(sd->target, "Control_R", mask, 0);
1513 memset(st, 0, sizeof(Zoom_Type));
1514 st->zoom_distance_tolerance = sd->zoom_distance_tolerance;
1515 st->info.zoom = 1.0;
1519 _rotate_test_reset(Gesture_Info *gesture)
1523 EINA_SAFETY_ON_NULL_RETURN(gesture);
1524 if (!gesture->data) return;
1526 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1529 memset(st, 0, sizeof(Rotate_Type));
1530 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1531 st->rotate_angular_tolerance = sd->rotate_angular_tolerance;
1535 _match_fingers_compare(Eina_List *list,
1539 /* Compare coords of first item in list to cur coords */
1543 EINA_LIST_FOREACH(list, l, pe_list)
1545 Pointer_Event *pe2 = eina_list_data_get(pe_list);
1547 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y, w))
1555 _pe_device_compare(const void *data1,
1558 /* Compare device of first item in list to our pe device */
1559 const Pointer_Event *pe1 = eina_list_data_get(data1);
1560 const Pointer_Event *pe2 = data2;
1562 if (pe1->device == pe2->device)
1564 else if (pe1->device < pe2->device)
1571 _pointer_event_record(Taps_Type *st,
1574 Elm_Gesture_Layer_Data *sd,
1576 Evas_Callback_Type event_type)
1578 /* Keep copy of pe and record it in list */
1579 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1581 memcpy(p, pe, sizeof(Pointer_Event));
1582 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1588 /* This will also update middle-point to report to user later */
1589 st->info.x = st->sum_x / st->n_taps;
1590 st->info.y = st->sum_y / st->n_taps;
1591 st->info.timestamp = pe->timestamp;
1595 pe_list = eina_list_append(pe_list, p);
1596 st->l = eina_list_append(st->l, pe_list);
1599 pe_list = eina_list_append(pe_list, p);
1607 * This function computes minimum rect to bound taps at idx index
1609 * @param taps [in] List of lists containing taps info.
1610 * @param idx [in] index of events taken from lists.
1611 * @param r [out] rect object to save info
1612 * @return EINA_TRUE if managed to compute rect.
1614 * @ingroup Elm_Gesture_Layer
1617 _taps_rect_get(Eina_List *taps, int idx, Evas_Coord_Rectangle *r)
1618 { /* Build a rect bounding all taps at index idx */
1620 Evas_Coord bx = 0, by = 0;
1622 Eina_Bool was_init = EINA_FALSE;
1624 EINA_LIST_FOREACH(taps, l, pe_list)
1626 Pointer_Event *pe = eina_list_nth(pe_list, idx);
1627 if (!pe) continue; /* Not suppose to happen */
1631 if (pe->x < r->x) r->x = pe->x;
1632 if (pe->y < r->y) r->y = pe->y;
1633 if (pe->x > bx) bx = pe->x;
1634 if (pe->y > by) by = pe->y;
1640 was_init = EINA_TRUE;
1652 * This function checks if the tap gesture is done.
1654 * @param data gesture info pointer
1655 * @return EINA_TRUE if it is done.
1657 * @ingroup Elm_Gesture_Layer
1660 _tap_gesture_check_finish(Gesture_Info *gesture, Evas_Coord tap_finger_size)
1662 /* Here we check if taps-gesture was completed successfuly */
1663 /* Count how many taps were recieved on each device then */
1664 /* determine if it matches n_taps_needed defined on START */
1666 Taps_Type *st = gesture->data;
1669 Evas_Coord_Rectangle base;
1670 Evas_Coord_Rectangle tmp;
1671 if (!tap_finger_size) /* Use system default if not set by user */
1672 tap_finger_size = elm_config_finger_size_get();
1674 if (!st->l) return EINA_FALSE;
1675 EINA_LIST_FOREACH(st->l, l, pe_list)
1677 /* No match taps number on device, ABORT */
1678 if (eina_list_count(pe_list) != st->n_taps_needed)
1684 /* Now bound each tap touches in a rect, compare diff within tolerance */
1685 /* Get rect based on first DOWN events for all devices */
1686 if (!_taps_rect_get(st->l, 0, &base))
1687 return EINA_FALSE; /* Should not happen */
1689 for (i = 1; i < st->n_taps_needed; i++)
1690 { /* Compare all other rects to base, tolerance is finger size */
1691 if (_taps_rect_get(st->l, i, &tmp))
1693 if (abs(tmp.x - base.x) > tap_finger_size)
1696 if (abs(tmp.y - base.y) > tap_finger_size)
1699 if (abs((tmp.x + tmp.w) - (base.x + base.w)) > tap_finger_size)
1702 if (abs((tmp.y + tmp.h) - (base.y + base.h)) > tap_finger_size)
1713 * This function sets state a tap-gesture to END or ABORT
1715 * @param data gesture info pointer
1717 * @ingroup Elm_Gesture_Layer
1720 _tap_gesture_finish(void *data, Evas_Coord tap_finger_size)
1722 /* This function will test each tap gesture when timer expires */
1723 Elm_Gesture_State s = ELM_GESTURE_STATE_ABORT;
1724 Gesture_Info *gesture = data;
1725 Taps_Type *st = gesture->data;
1727 if (_tap_gesture_check_finish(gesture, tap_finger_size))
1729 s = ELM_GESTURE_STATE_END;
1732 st->info.n = eina_list_count(st->l);
1733 _state_set(gesture, s, gesture->info, EINA_FALSE);
1734 _tap_gestures_test_reset(gesture);
1740 * when this timer expires we finish tap gestures.
1742 * @param data The gesture-layer object.
1743 * @return cancles callback for this timer.
1745 * @ingroup Elm_Gesture_Layer
1748 _multi_tap_timeout(void *data)
1750 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1752 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1753 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TAPS],
1754 sd->tap_finger_size);
1756 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1757 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_DOUBLE_TAPS],
1758 sd->tap_finger_size);
1760 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1761 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TRIPLE_TAPS],
1762 sd->tap_finger_size);
1764 _clear_if_finished(data);
1765 sd->gest_taps_timeout = NULL;
1767 return ECORE_CALLBACK_CANCEL;
1773 * when this timer expires we START long tap gesture
1775 * @param data The gesture-layer object.
1776 * @return cancles callback for this timer.
1778 * @ingroup Elm_Gesture_Layer
1781 _long_tap_timeout(void *data)
1783 Gesture_Info *gesture = data;
1785 _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1786 gesture->data, EINA_TRUE);
1788 return ECORE_CALLBACK_RENEW;
1794 * This function checks the state of a tap gesture.
1796 * @param sd Gesture Layer Widget Data.
1797 * @param pe The recent input event as stored in pe struct.
1798 * @param event_info Original input event pointer.
1799 * @param event_type Type of original input event.
1800 * @param gesture what gesture is tested
1801 * @param how many taps for this gesture (1, 2 or 3)
1803 * @ingroup Elm_Gesture_Layer
1806 _tap_gesture_test(Evas_Object *obj,
1809 Evas_Callback_Type event_type,
1810 Elm_Gesture_Type g_type)
1814 Gesture_Info *gesture;
1815 Eina_List *pe_list = NULL;
1816 Pointer_Event *pe_last = NULL;
1817 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1819 /* Here we fill Tap struct */
1820 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1825 gesture = sd->gesture[g_type];
1826 if (!gesture) return;
1830 case ELM_GESTURE_N_TAPS:
1834 case ELM_GESTURE_N_DOUBLE_TAPS:
1838 case ELM_GESTURE_N_TRIPLE_TAPS:
1848 if (!st) /* Allocated once on first time */
1850 st = calloc(1, sizeof(Taps_Type));
1852 _tap_gestures_test_reset(gesture);
1855 switch (pe->event_type)
1857 case EVAS_CALLBACK_MULTI_DOWN:
1858 case EVAS_CALLBACK_MOUSE_DOWN:
1859 /* Each device taps (DOWN, UP event) registered in same list */
1860 /* Find list for this device or start a new list if not found */
1861 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1863 { /* This device touched before, verify that this tap is on */
1864 /* top of a previous tap (including a tap of other device) */
1865 if (!_match_fingers_compare(st->l, pe, sd->tap_finger_size))
1866 { /* New DOWN event is not on top of any prev touch */
1867 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1868 &st->info, EINA_FALSE);
1869 _event_consume(sd, event_info, event_type, ev_flag);
1875 /* All tests are good, register this tap in device list */
1876 pe_list = _pointer_event_record
1877 (st, pe_list, pe, sd, event_info, event_type);
1879 if (!sd->gest_taps_timeout)
1881 if (sd->double_tap_timeout > 0.0)
1883 sd->gest_taps_timeout =
1884 ecore_timer_add(sd->double_tap_timeout,
1885 _multi_tap_timeout, gesture->obj);
1888 else /* We re-allocate gest_taps_timeout between taps */
1889 ecore_timer_reset(sd->gest_taps_timeout);
1891 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1892 { /* This is the first mouse down we got */
1893 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
1894 &st->info, EINA_FALSE);
1895 _event_consume(sd, event_info, event_type, ev_flag);
1897 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1901 else if (eina_list_count(pe_list) > st->n_taps_needed)
1902 { /* If we arleady got too many touches for this gesture. */
1903 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1904 &st->info, EINA_FALSE);
1907 if (gesture->state == ELM_GESTURE_STATE_MOVE)
1908 { /* Report MOVE if all devices have same DOWN/UP count */
1909 /* Should be in MOVE state from last UP event */
1911 Eina_Bool move = EINA_TRUE;
1914 EINA_LIST_FOREACH(st->l, l, pe_list)
1918 n = eina_list_count(pe_list);
1920 else if (n != eina_list_count(pe_list))
1926 if (move && (n > 0))
1928 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1929 &st->info, EINA_TRUE);
1935 case EVAS_CALLBACK_MULTI_UP:
1936 case EVAS_CALLBACK_MOUSE_UP:
1937 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1938 if (!pe_list) return;
1940 _pointer_event_record(st, pe_list, pe, sd, event_info, event_type);
1942 if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1943 !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1944 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1945 ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1946 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1947 { /* Test for finish immidiatly, not waiting for timeout */
1948 if (_tap_gesture_check_finish(gesture, sd->tap_finger_size))
1950 _tap_gesture_finish(gesture, sd->tap_finger_size);
1955 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1956 (gesture->state == ELM_GESTURE_STATE_MOVE))
1957 { /* Tap gesture started, no finger on surface. Report MOVE */
1959 Eina_Bool move = EINA_TRUE;
1962 /* Report move only if all devices have same DOWN/UP count */
1963 EINA_LIST_FOREACH(st->l, l, pe_list)
1967 n = eina_list_count(pe_list);
1969 else if (n != eina_list_count(pe_list))
1975 if ((move && (n > 0)) && (n < st->n_taps_needed))
1976 { /* Set number of fingers and report MOVE */
1977 /* We don't report MOVE when (n >= st->n_taps_needed)
1978 because will be END or ABORT at this stage */
1979 st->info.n = eina_list_count(st->l);
1980 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1981 &st->info, EINA_TRUE);
1987 case EVAS_CALLBACK_MULTI_MOVE:
1988 case EVAS_CALLBACK_MOUSE_MOVE:
1989 /* Verify that user didn't move out of tap area before next tap */
1990 /* BUT: we need to skip some MOVE events coming before DOWN */
1991 /* when user taps next tap. So fetch LAST recorded event for */
1992 /* device (DOWN or UP event), ignore all MOVEs if last was UP */
1993 pe_last = eina_list_data_get(eina_list_last(
1994 eina_list_search_unsorted(st->l, _pe_device_compare, pe)));
1997 { /* pe_last is the last event recorded for this device */
1998 if ((pe_last->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1999 (pe_last->event_type == EVAS_CALLBACK_MULTI_DOWN))
2000 { /* Test only MOVE events that come after DOWN event */
2001 if (!_inside(pe_last->x, pe_last->y, pe->x, pe->y,
2002 sd->tap_finger_size))
2004 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2005 &st->info, EINA_FALSE);
2006 _event_consume(sd, event_info, event_type, ev_flag);
2020 * This function computes center-point for long-tap gesture
2022 * @param st Long Tap gesture info pointer
2023 * @param pe The recent input event as stored in pe struct.
2025 * @ingroup Elm_Gesture_Layer
2028 _compute_taps_center(Long_Tap_Type *st,
2035 Evas_Coord x = 0, y = 0;
2037 if (!eina_list_count(st->touched))
2040 EINA_LIST_FOREACH(st->touched, l, p)
2041 { /* Accumulate all then take avarage */
2042 if (p->device == pe->device) /* This will take care of values
2043 * coming from MOVE event */
2055 *x_out = x / eina_list_count(st->touched);
2056 *y_out = y / eina_list_count(st->touched);
2062 * This function checks N long-tap gesture.
2064 * @param obj The gesture-layer object.
2065 * @param pe The recent input event as stored in pe struct.
2066 * @param event_info Original input event pointer.
2067 * @param event_type Type of original input event.
2068 * @param g_type what Gesture we are testing.
2069 * @param taps How many click/taps we test for.
2071 * @ingroup Elm_Gesture_Layer
2074 _n_long_tap_test(Evas_Object *obj,
2077 Evas_Callback_Type event_type,
2078 Elm_Gesture_Type g_type)
2080 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2081 Gesture_Info *gesture;
2084 /* Here we fill Recent_Taps struct and fire-up click/tap timers */
2085 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2087 if (!pe) /* this happens when unhandled event arrived */
2088 return; /* see _make_pointer_event function */
2090 gesture = sd->gesture[g_type];
2091 if (!gesture) return;
2094 if (!st) /* Allocated once on first time */
2096 st = calloc(1, sizeof(Long_Tap_Type));
2098 _n_long_tap_test_reset(gesture);
2101 switch (pe->event_type)
2103 case EVAS_CALLBACK_MULTI_DOWN:
2104 case EVAS_CALLBACK_MOUSE_DOWN:
2105 st->touched = _touched_device_add(st->touched, pe);
2106 st->info.n = eina_list_count(st->touched);
2108 _event_consume(sd, event_info, event_type, ev_flag);
2109 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
2110 st->center_x = st->info.x; /* Update coords for */
2111 st->center_y = st->info.y; /* reporting START */
2113 /* This is the first mouse down we got */
2114 if (eina_list_count(st->touched) == 1)
2116 _state_set(gesture, ELM_GESTURE_STATE_START,
2117 gesture->data, EINA_FALSE);
2118 st->info.timestamp = pe->timestamp;
2120 /* To test long tap */
2121 /* When this timer expires, gesture STARTED */
2122 if ((!st->timeout) && (sd->long_tap_start_timeout > 0.0))
2123 st->timeout = ecore_timer_add(sd->long_tap_start_timeout,
2124 _long_tap_timeout, gesture);
2129 ecore_timer_reset(st->timeout);
2134 case EVAS_CALLBACK_MULTI_UP:
2135 case EVAS_CALLBACK_MOUSE_UP:
2136 st->touched = _touched_device_remove(st->touched, pe);
2137 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
2140 if (gesture->state == ELM_GESTURE_STATE_MOVE)
2141 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2142 &st->info, EINA_FALSE);
2144 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2145 &st->info, EINA_FALSE);
2147 ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2148 _event_consume(sd, event_info, event_type, ev_flag);
2153 case EVAS_CALLBACK_MULTI_MOVE:
2154 case EVAS_CALLBACK_MOUSE_MOVE:
2156 ((gesture->state == ELM_GESTURE_STATE_START) ||
2157 /* Report MOVE only if STARTED */
2158 (gesture->state == ELM_GESTURE_STATE_MOVE)))
2163 _compute_taps_center(st, &x, &y, pe);
2164 /* ABORT if user moved fingers out of tap area */
2165 if (!_inside(x, y, st->center_x, st->center_y,
2166 sd->tap_finger_size))
2168 ELM_SAFE_FREE(st->timeout, ecore_timer_del);
2170 /* Report MOVE if gesture started */
2171 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2172 &st->info, EINA_FALSE);
2175 _event_consume(sd, event_info, event_type, ev_flag);
2187 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
2188 * This momentum value will be sent to widget when gesture is completed.
2190 * @param momentum pointer to buffer where we record momentum value.
2191 * @param xx1 x coord where user started gesture.
2192 * @param yy1 y coord where user started gesture.
2193 * @param xx2 x coord where user completed gesture.
2194 * @param yy2 y coord where user completed gesture.
2195 * @param t1x timestamp for X, when user started gesture.
2196 * @param t1y timestamp for Y, when user started gesture.
2197 * @param t2 timestamp when user completed gesture.
2199 * @ingroup Elm_Gesture_Layer
2202 _momentum_set(Elm_Gesture_Momentum_Info *momentum,
2211 Evas_Coord velx = 0, vely = 0, vel;
2212 Evas_Coord dx = xx2 - xx1;
2213 Evas_Coord dy = yy2 - yy1;
2218 velx = (dx * 1000) / dtx;
2221 vely = (dy * 1000) / dty;
2223 vel = sqrt((velx * velx) + (vely * vely));
2225 if ((_elm_config->thumbscroll_friction > 0.0) &&
2226 (vel > _elm_config->thumbscroll_momentum_threshold)) /* report
2229 momentum->mx = velx;
2230 momentum->my = vely;
2242 * This function is used for computing rotation angle (DEG).
2244 * @param xx1 first finger x location.
2245 * @param yy1 first finger y location.
2246 * @param xx2 second finger x location.
2247 * @param yy2 second finger y location.
2249 * @return angle of the line between (xx1,yy1), (xx2,yy2) in Deg.
2250 * Angles now are given in DEG, not RAD.
2251 * ZERO angle at 12-oclock, growing clockwise.
2253 * @ingroup Elm_Gesture_Layer
2256 _angle_get(Evas_Coord xx1,
2261 double a, xx, yy, rt = (-1);
2263 xx = fabs(xx2 - xx1);
2264 yy = fabs(yy2 - yy1);
2266 if (((int)xx) && ((int)yy))
2268 rt = a = RAD2DEG(atan(yy / xx));
2271 if (yy1 < yy2) rt = 360 - a;
2276 if (yy1 < yy2) rt = 180 + a;
2281 if (rt < 0) /* Do this only if rt is not set */
2283 if (((int)xx)) /* Horizontal line */
2285 if (xx2 < xx1) rt = 180;
2289 { /* Vertical line */
2290 if (yy2 < yy1) rt = 90;
2295 /* Now we want to change from:
2297 * original circle 180 0 We want: 270 90
2301 if (rt >= 360) rt -= 360;
2309 * This function is used for computing the magnitude and direction
2310 * of vector between two points.
2312 * @param xx1 first finger x location.
2313 * @param yy1 first finger y location.
2314 * @param xx2 second finger x location.
2315 * @param yy2 second finger y location.
2316 * @param l length computed (output)
2317 * @param a angle computed (output)
2319 * @ingroup Elm_Gesture_Layer
2322 _vector_get(Evas_Coord xx1,
2333 *l = (Evas_Coord)sqrt((xx * xx) + (yy * yy));
2334 *a = _angle_get(xx1, yy1, xx2, yy2);
2338 _direction_get(Evas_Coord xx1,
2341 if (xx2 < xx1) return -1;
2342 if (xx2 > xx1) return 1;
2350 * This function tests momentum gesture.
2351 * @param obj The gesture-layer object.
2352 * @param pe The recent input event as stored in pe struct.
2353 * @param event_info recent input event.
2354 * @param event_type recent event type.
2355 * @param g_type what Gesture we are testing.
2357 * @ingroup Elm_Gesture_Layer
2360 _momentum_test(Evas_Object *obj,
2363 Evas_Callback_Type event_type,
2364 Elm_Gesture_Type g_type)
2369 Gesture_Info *gesture;
2370 Pointer_Event pe_local;
2371 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2372 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
2373 unsigned int cnt = 1; /* We start counter counting current pe event */
2375 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2377 gesture = sd->gesture[g_type];
2378 if (!gesture) return;
2380 /* When continues enable = TRUE a gesture may START on MOVE event */
2381 /* We don't allow this to happen with the if-statement below. */
2382 /* When continues enable = FALSE a gesture may START on DOWN only */
2383 /* Therefor it would NOT start on MOVE event. */
2384 /* NOTE that touched list is updated AFTER this function returns */
2385 /* so (count == 0) when we get here on first touch on surface. */
2386 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2387 return; /* Got move on mouse-over move */
2390 if (!st) /* Allocated once on first time */
2392 st = calloc(1, sizeof(Momentum_Type));
2394 _momentum_test_reset(gesture);
2400 /* First make avarage of all touched devices to determine center point */
2401 pe_local = *pe; /* Copy pe event info to local */
2402 EINA_LIST_FOREACH(sd->touched, l, p)
2403 if (p->device != pe_local.device)
2410 /* Compute avarage to get center point */
2414 /* If user added finger - reset gesture */
2415 if ((st->info.n) && (st->info.n < cnt))
2416 state_to_report = ELM_GESTURE_STATE_ABORT;
2418 if (st->info.n < cnt)
2423 case EVAS_CALLBACK_MOUSE_DOWN:
2424 case EVAS_CALLBACK_MULTI_DOWN:
2425 case EVAS_CALLBACK_MOUSE_MOVE:
2426 case EVAS_CALLBACK_MULTI_MOVE:
2429 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2430 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2431 (sd->glayer_continues_enable)) /* start also on MOVE */
2432 { /* We start on MOVE when cont-enabled only */
2433 st->line_st.x = st->line_end.x = pe_local.x;
2434 st->line_st.y = st->line_end.y = pe_local.y;
2435 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
2436 st->xdir = st->ydir = 0;
2437 st->info.x2 = st->info.x1 = pe_local.x;
2438 st->info.y2 = st->info.y1 = pe_local.y;
2439 st->info.tx = st->info.ty = pe_local.timestamp;
2440 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
2441 &st->info, EINA_FALSE);
2442 _event_consume(sd, event_info, event_type, ev_flag);
2450 Eina_Bool force = EINA_TRUE; /* for move state */
2452 /* ABORT if got DOWN or MOVE event after UP+timeout */
2453 if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
2455 state_to_report = ELM_GESTURE_STATE_ABORT;
2459 /* We report state but don't compute momentum now */
2460 ev_flag = _state_set(gesture, state_to_report, &st->info,
2462 _event_consume(sd, event_info, event_type, ev_flag);
2463 return; /* Stop computing when user remove finger */
2466 /* Too long of a wait, reset all values */
2467 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2469 st->line_st.x = pe_local.x;
2470 st->line_st.y = pe_local.y;
2471 st->t_st_y = st->t_st_x = pe_local.timestamp;
2472 st->info.tx = st->t_st_x;
2473 st->info.ty = st->t_st_y;
2474 st->xdir = st->ydir = 0;
2480 xdir = _direction_get(st->line_end.x, pe_local.x);
2481 ydir = _direction_get(st->line_end.y, pe_local.y);
2482 if (xdir && (xdir != st->xdir))
2484 st->line_st.x = st->line_end.x;
2485 st->info.tx = st->t_st_x = st->t_end;
2489 if (ydir && (ydir != st->ydir))
2491 st->line_st.y = st->line_end.y;
2492 st->info.ty = st->t_st_y = st->t_end;
2497 st->info.x2 = st->line_end.x = pe_local.x;
2498 st->info.y2 = st->line_end.y = pe_local.y;
2499 st->t_end = pe_local.timestamp;
2500 _momentum_set(&st->info, st->line_st.x, st->line_st.y,
2501 pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2502 pe_local.timestamp);
2504 ev_flag = _state_set(gesture, state_to_report, &st->info,
2506 _event_consume(sd, event_info, event_type, ev_flag);
2509 case EVAS_CALLBACK_MOUSE_UP:
2510 case EVAS_CALLBACK_MULTI_UP:
2511 st->t_up = pe_local.timestamp; /* Record recent up event time */
2512 if ((cnt > 1) || /* Ignore if more fingers touch surface */
2513 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2516 /* Too long of a wait, reset all values */
2517 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2519 st->line_st.x = pe_local.x;
2520 st->line_st.y = pe_local.y;
2521 st->t_st_y = st->t_st_x = pe_local.timestamp;
2522 st->xdir = st->ydir = 0;
2525 st->info.x2 = pe_local.x;
2526 st->info.y2 = pe_local.y;
2527 st->line_end.x = pe_local.x;
2528 st->line_end.y = pe_local.y;
2529 st->t_end = pe_local.timestamp;
2531 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2532 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2533 state_to_report = ELM_GESTURE_STATE_END;
2535 state_to_report = ELM_GESTURE_STATE_ABORT;
2537 ev_flag = _state_set(gesture, state_to_report, &st->info,
2539 _event_consume(sd, event_info, event_type, ev_flag);
2548 _line_device_compare(const void *data1,
2551 /* Compare device component of line struct */
2552 const Line_Data *ln1 = data1;
2553 const int *device = data2;
2555 if (ln1->t_st) /* Compare only with lines that started */
2556 return ln1->device - (*device);
2564 * This function construct line struct from input.
2565 * @param info pointer to store line momentum.
2566 * @param st line info to store input data.
2567 * @param pe The recent input event as stored in pe struct.
2569 * @ingroup Elm_Gesture_Layer
2572 _single_line_process(Elm_Gesture_Line_Info *info,
2575 Evas_Callback_Type event_type)
2577 /* Record events and set momentum for line pointed by st */
2583 case EVAS_CALLBACK_MOUSE_DOWN:
2584 case EVAS_CALLBACK_MOUSE_MOVE:
2585 case EVAS_CALLBACK_MULTI_DOWN:
2586 case EVAS_CALLBACK_MULTI_MOVE:
2587 if (!st->t_st) /* This happens only when line starts */
2589 st->line_st.x = pe->x;
2590 st->line_st.y = pe->y;
2591 st->t_st = pe->timestamp;
2592 st->device = pe->device;
2593 info->momentum.x1 = pe->x;
2594 info->momentum.y1 = pe->y;
2595 info->momentum.tx = pe->timestamp;
2596 info->momentum.ty = pe->timestamp;
2603 case EVAS_CALLBACK_MOUSE_UP:
2604 case EVAS_CALLBACK_MULTI_UP:
2605 /* IGNORE if line info was cleared, like long press, move */
2609 st->line_end.x = pe->x;
2610 st->line_end.y = pe->y;
2611 st->t_end = pe->timestamp;
2620 _line_data_reset(st);
2624 info->momentum.x2 = pe->x;
2625 info->momentum.y2 = pe->y;
2626 _momentum_set(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2627 st->t_st, st->t_st, pe->timestamp);
2635 * This function test for (n) line gesture.
2636 * @param obj The gesture-layer object.
2637 * @param pe The recent input event as stored in pe struct.
2638 * @param event_info Original input event pointer.
2639 * @param event_type Type of original input event.
2640 * @param g_type what Gesture we are testing.
2642 * @ingroup Elm_Gesture_Layer
2645 _n_line_test(Evas_Object *obj,
2648 Evas_Callback_Type event_type,
2649 Elm_Gesture_Type g_type)
2654 Gesture_Info *gesture;
2655 Line_Data *line = NULL;
2660 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2662 gesture = sd->gesture[g_type];
2663 if (!gesture ) return;
2665 /* When continues enable = TRUE a gesture may START on MOVE event */
2666 /* We don't allow this to happen with the if-statement below. */
2667 /* When continues enable = FALSE a gesture may START on DOWN only */
2668 /* Therefor it would NOT start on MOVE event. */
2669 /* NOTE that touched list is updated AFTER this function returns */
2670 /* so (count == 0) when we get here on first touch on surface. */
2671 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2672 return; /* Got move on mouse-over move */
2677 st = calloc(1, sizeof(Line_Type));
2682 cnt = eina_list_count(list);
2684 if (cnt) /* list is not empty, locate this device on list */
2686 line = (Line_Data *)eina_list_search_unsorted
2687 (st->list, _line_device_compare, &pe->device);
2690 if (!line) /* List is empty or device not found, new line-struct on
2693 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2694 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2695 ((sd->glayer_continues_enable) && /* START on MOVE also */
2696 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2697 /* Allocate new item on START only */
2698 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2700 line = calloc(1, sizeof(Line_Data));
2701 _line_data_reset(line);
2702 list = eina_list_append(list, line);
2707 if (!line) /* This may happen on MOVE that comes before DOWN */
2708 return; /* No line-struct to work with, can't continue testing */
2710 /* update st with input */
2711 if (_single_line_process(&st->info, line, pe, event_type))
2712 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2714 /* Get direction and magnitude of the line */
2716 _vector_get(line->line_st.x, line->line_st.y, pe->x, pe->y,
2717 &line->line_length, &angle);
2719 /* These are used later to compare lines length */
2720 Evas_Coord shortest_line_len = line->line_length;
2721 Evas_Coord longest_line_len = line->line_length;
2722 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2724 /* Now update line-state */
2725 if (line->t_st) /* Analyze line only if line started */
2727 if (line->line_angle >= 0.0) /* if line direction was set, we
2728 * test if broke tolerance */
2730 double a = fabs(angle - line->line_angle);
2731 /* Distance from line */
2732 double d = (tan(DEG2RAD(a))) * line->line_length;
2733 /* Broke tolerance: abort line and start a new one */
2734 if ((d > sd->line_distance_tolerance) ||
2735 (a > sd->line_angular_tolerance))
2737 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2738 &st->info, EINA_FALSE);
2739 _event_consume(sd, event_info, event_type, ev_flag);
2743 /* We may finish line if momentum is zero */
2744 if (sd->glayer_continues_enable)
2746 /* This is for continues-gesture */
2747 /* Finish line on zero momentum for continues gesture */
2748 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2750 line->line_end.x = pe->x;
2751 line->line_end.y = pe->y;
2752 line->t_end = pe->timestamp;
2757 { /* Record the line angle as it broke minimum length for line */
2758 if (line->line_length >= sd->line_min_length)
2759 st->info.angle = line->line_angle = angle;
2764 if (line->line_angle < 0.0) /* it's not a line, too short
2765 * more close to a tap */
2767 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2768 &st->info, EINA_FALSE);
2769 _event_consume(sd, event_info, event_type, ev_flag);
2775 /* Count how many lines already started / ended */
2778 unsigned int tm_start = pe->timestamp;
2779 unsigned int tm_end = pe->timestamp;
2782 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2783 Eina_Bool lines_parallel = EINA_TRUE;
2784 EINA_LIST_FOREACH(list, l, t_line)
2787 base_angle = t_line->line_angle;
2790 if (t_line->line_angle >= 0) /* Compare angle only with
2791 * lines with direction
2794 if (fabs(base_angle - t_line->line_angle) >
2795 sd->line_angular_tolerance)
2796 lines_parallel = EINA_FALSE;
2800 if (t_line->line_length) /* update only if this line is used */
2802 if (shortest_line_len > t_line->line_length)
2803 shortest_line_len = t_line->line_length;
2805 if (longest_line_len < t_line->line_length)
2806 longest_line_len = t_line->line_length;
2812 if (t_line->t_st < tm_start)
2813 tm_start = t_line->t_st;
2819 if (t_line->t_end < tm_end)
2820 tm_end = t_line->t_end;
2824 st->info.momentum.n = started;
2827 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2828 /* user lift one finger then starts again without line-end - ABORT */
2829 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2831 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2833 _event_consume(sd, event_info, event_type, ev_flag);
2837 if (!lines_parallel) /* Lines are NOT at same direction, abort this
2840 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2842 _event_consume(sd, event_info, event_type, ev_flag);
2846 /* We report ABORT if lines length are NOT matching when fingers are up */
2847 if ((longest_line_len - shortest_line_len) >
2848 (elm_config_finger_size_get() * 2))
2850 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2852 _event_consume(sd, event_info, event_type, ev_flag);
2856 /* We consider FLICK as a fast line.ABORT if take too long to finish */
2857 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) >
2858 sd->flick_time_limit_ms))
2860 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2862 _event_consume(sd, event_info, event_type, ev_flag);
2868 case EVAS_CALLBACK_MOUSE_UP:
2869 case EVAS_CALLBACK_MULTI_UP:
2870 if ((started) && (started == ended))
2872 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2873 &st->info, EINA_FALSE);
2874 _event_consume(sd, event_info, event_type, ev_flag);
2879 case EVAS_CALLBACK_MOUSE_DOWN:
2880 case EVAS_CALLBACK_MULTI_DOWN:
2881 case EVAS_CALLBACK_MOUSE_MOVE:
2882 case EVAS_CALLBACK_MULTI_MOVE:
2885 /* For continues gesture */
2886 if (sd->glayer_continues_enable && (started == ended))
2888 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2889 &st->info, EINA_FALSE);
2890 _event_consume(sd, event_info, event_type, ev_flag);
2893 { /* When continues, may START on MOVE event too */
2894 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2896 /* This happens when: on n > 1 lines then one finger up */
2897 /* caused abort, then put finger down. */
2898 /* This will stop line from starting again. */
2899 /* Number of lines, MUST match touched-device in list */
2900 if ((!sd->glayer_continues_enable) &&
2901 (eina_list_count(st->list) <
2902 eina_list_count(sd->touched)))
2903 s = ELM_GESTURE_STATE_ABORT;
2905 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2906 s = ELM_GESTURE_STATE_START;
2908 ev_flag = _state_set(gesture, s, &st->info, EINA_TRUE);
2909 _event_consume(sd, event_info, event_type, ev_flag);
2915 return; /* Unhandeld event type */
2922 * This function is used to check if rotation gesture started.
2923 * @param st Contains current rotation values from user input.
2924 * @return TRUE/FALSE if we need to set rotation START.
2926 * @ingroup Elm_Gesture_Layer
2929 _on_rotation_broke_tolerance(Rotate_Type *st)
2931 if (st->info.base_angle < 0)
2932 return EINA_FALSE; /* Angle has to be computed first */
2934 if (st->rotate_angular_tolerance < 0)
2937 double low = st->info.base_angle - st->rotate_angular_tolerance;
2938 double high = st->info.base_angle + st->rotate_angular_tolerance;
2939 double t = st->info.angle;
2963 if ((t < low) || (t > high)) /* This marks that roation action has
2966 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2967 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2977 * This function is used for computing the gap between fingers.
2978 * It returns the length and center point between fingers.
2980 * @param xx1 first finger x location.
2981 * @param yy1 first finger y location.
2982 * @param xx2 second finger x location.
2983 * @param yy2 second finger y location.
2984 * @param x Get center point x cord (output)
2985 * @param y Get center point y cord (output)
2987 * @return length of the line between (xx1,yy1), (xx2,yy2) in pixels.
2989 * @ingroup Elm_Gesture_Layer
2992 _finger_gap_length_get(Evas_Coord xx1,
2999 double a, b, xx, yy, gap;
3000 xx = fabs(xx2 - xx1);
3001 yy = fabs(yy2 - yy1);
3002 gap = sqrt((xx * xx) + (yy * yy));
3004 /* START - Compute zoom center point */
3005 /* The triangle defined as follows:
3013 * http://en.wikipedia.org/wiki/Trigonometric_functions
3014 *************************************/
3015 if (((int)xx) && ((int)yy))
3017 double A = atan((yy / xx));
3018 a = (Evas_Coord)((gap / 2) * sin(A));
3019 b = (Evas_Coord)((gap / 2) * cos(A));
3020 *x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
3021 *y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
3025 if ((int)xx) /* horiz line, take half width */
3027 *x = (Evas_Coord)((xx1 + xx2) / 2);
3028 *y = (Evas_Coord)(yy1);
3031 if ((int)yy) /* vert line, take half width */
3033 *x = (Evas_Coord)(xx1);
3034 *y = (Evas_Coord)((yy1 + yy2) / 2);
3037 /* END - Compute zoom center point */
3039 return (Evas_Coord)gap;
3045 * This function is used for computing zoom value.
3047 * @param st Pointer to zoom data based on user input.
3048 * @param tm_end Recent input event timestamp.
3049 * @param zoom_val Current computed zoom value.
3051 * @return zoom momentum
3053 * @ingroup Elm_Gesture_Layer
3056 _zoom_momentum_get(Zoom_Type *st,
3057 unsigned int tm_end,
3060 unsigned int tm_total;
3061 if (!st->m_st_tm) /* Init, and we don't start computing momentum yet */
3063 st->m_st_tm = st->m_prev_tm = tm_end;
3064 st->m_base = zoom_val;
3068 if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
3069 return 0.0; /* we don't start to compute momentum yet */
3071 if (st->dir) /* if direction was already defined, check if changed */
3073 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
3074 /* Direction changed, reset momentum */
3075 ((st->dir > 0) && (zoom_val < st->info.zoom)))
3078 st->dir = (-st->dir);
3083 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
3085 if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
3087 st->m_st_tm = 0; /* Rest momentum when waiting too long */
3091 st->m_prev_tm = tm_end;
3092 tm_total = tm_end - st->m_st_tm;
3095 return ((zoom_val - st->m_base) * 1000) / tm_total;
3103 * This function is used for computing zoom value.
3105 * @param st Pointer to zoom data based on user input.
3106 * @param xx1 first finger x location.
3107 * @param yy1 first finger y location.
3108 * @param xx2 second finger x location.
3109 * @param yy2 second finger y location.
3110 * @param factor zoom-factor, used to determine how fast zoom works.
3112 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
3114 * @ingroup Elm_Gesture_Layer
3117 _zoom_compute(Zoom_Type *st,
3122 double zoom_finger_factor)
3125 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
3126 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
3128 Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3129 &st->info.x, &st->info.y);
3131 st->info.radius = diam / 2;
3135 st->zoom_base = diam;
3136 return st->info.zoom;
3139 if (st->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
3140 * zoom action NOT started yet */
3142 /* avoid jump with zoom value when break tolerance */
3143 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
3145 st->zoom_base -= st->zoom_distance_tolerance;
3146 st->zoom_distance_tolerance = 0;
3149 /* avoid jump with zoom value when break tolerance */
3150 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
3152 st->zoom_base += st->zoom_distance_tolerance;
3153 st->zoom_distance_tolerance = 0;
3159 /* We use factor only on the difference between gap-base */
3160 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
3161 rt = ((1.0) + ((((float)diam - (float)st->zoom_base) /
3162 (float)st->zoom_base) * zoom_finger_factor));
3164 /* Momentum: zoom per second: */
3165 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
3173 * This function handles zoom with mouse wheel.
3174 * thats a combination of wheel + CTRL key.
3175 * @param obj The gesture-layer object.
3176 * @param event_info Original input event pointer.
3177 * @param event_type Type of original input event.
3178 * @param g_type what Gesture we are testing.
3180 * @ingroup Elm_Gesture_Layer
3183 _zoom_with_wheel_test(Evas_Object *obj,
3185 Evas_Callback_Type event_type,
3186 Elm_Gesture_Type g_type)
3188 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3190 if (!sd->gesture[g_type]) return;
3192 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3193 Zoom_Type *st = gesture_zoom->data;
3194 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3195 if (!st) /* Allocated once on first time, used for zoom intermediate data */
3197 st = calloc(1, sizeof(Zoom_Type));
3198 gesture_zoom->data = st;
3199 _zoom_test_reset(gesture_zoom);
3204 case EVAS_CALLBACK_KEY_UP:
3206 Evas_Event_Key_Up *p = event_info;
3207 if ((!strcmp(p->key, "Control_L")) ||
3208 /* Test if we ended a zoom gesture when releasing CTRL */
3209 (!strcmp(p->key, "Control_R")))
3211 if ((st->zoom_wheel) &&
3212 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3213 /* User released CTRL after zooming */
3214 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3216 st->info.momentum = _zoom_momentum_get
3217 (st, p->timestamp, st->info.zoom);
3219 ev_flag = _state_set
3220 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3222 _event_consume(sd, event_info, event_type, ev_flag);
3230 case EVAS_CALLBACK_MOUSE_WHEEL:
3233 Elm_Gesture_State s;
3234 if (!evas_key_modifier_is_set(
3235 ((Evas_Event_Mouse_Wheel *)event_info)->modifiers,
3236 "Control")) /* if using wheel witout CTRL after starting zoom */
3238 if ((st->zoom_wheel) &&
3239 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3240 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3242 ev_flag = _state_set
3243 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3245 _event_consume(sd, event_info, event_type, ev_flag);
3250 return; /* Ignore mouse-wheel without control */
3253 /* Using mouse wheel with CTRL for zoom */
3254 /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0) we
3255 * continue a zoom gesture */
3256 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
3259 s = ELM_GESTURE_STATE_MOVE;
3262 { /* On first wheel event, report START */
3263 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
3264 evas_object_evas_get(sd->target), "Control");
3266 s = ELM_GESTURE_STATE_START;
3267 if (!evas_object_key_grab
3268 (sd->target, "Control_L", mask, 0, EINA_FALSE))
3269 ERR("Failed to Grabbed CTRL_L");
3270 if (!evas_object_key_grab
3271 (sd->target, "Control_R", mask, 0, EINA_FALSE))
3272 ERR("Failed to Grabbed CTRL_R");
3275 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
3276 st->zoom_wheel = (Evas_Event_Mouse_Wheel *)event_info;
3277 st->info.x = st->zoom_wheel->canvas.x;
3278 st->info.y = st->zoom_wheel->canvas.y;
3280 if (st->zoom_wheel->z < 0) /* zoom in */
3281 st->info.zoom += (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3283 if (st->zoom_wheel->z > 0) /* zoom out */
3284 st->info.zoom -= (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3286 if (st->info.zoom < 0.0)
3287 st->info.zoom = 0.0;
3289 st->info.momentum = _zoom_momentum_get
3290 (st, st->zoom_wheel->timestamp, st->info.zoom);
3292 ev_flag = _state_set(gesture_zoom, s, &st->info, force);
3293 _event_consume(sd, event_info, event_type, ev_flag);
3305 * This function is used to test zoom gesture.
3306 * user may combine zoom, rotation together.
3307 * so its possible that both will be detected from input.
3308 * (both are two-finger movement-oriented gestures)
3310 * @param obj The gesture-layer object.
3311 * @param event_info Pointer to recent input event.
3312 * @param event_type Recent input event type.
3313 * @param g_type what Gesture we are testing.
3315 * @ingroup Elm_Gesture_Layer
3318 _zoom_test(Evas_Object *obj,
3321 Evas_Callback_Type event_type,
3322 Elm_Gesture_Type g_type)
3324 /* Test for wheel zoom. */
3325 _zoom_with_wheel_test(obj, event_info, event_type, ELM_GESTURE_ZOOM);
3327 if (!_elm_config->glayer_zoom_finger_enable)
3332 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3334 if (!sd->gesture[g_type]) return;
3336 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3337 Zoom_Type *st = gesture_zoom->data;
3339 if (!st) /* Allocated once on first time, used for zoom data */
3341 st = calloc(1, sizeof(Zoom_Type));
3342 gesture_zoom->data = st;
3343 _zoom_test_reset(gesture_zoom);
3346 /* Start - new zoom testing, letting all fingers start */
3347 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3350 case EVAS_CALLBACK_MOUSE_MOVE:
3351 case EVAS_CALLBACK_MULTI_MOVE:
3352 /* if non-continues mode and gesture NOT started, ignore MOVE */
3353 if ((!sd->glayer_continues_enable) &&
3354 (!st->zoom_st.timestamp))
3356 // fallthrough is intentional
3357 case EVAS_CALLBACK_MOUSE_DOWN:
3358 case EVAS_CALLBACK_MULTI_DOWN:
3359 { /* Here we take care of zoom-start and zoom move */
3363 if (eina_list_count(sd->touched) > 2) /* Process zoom only
3367 ev_flag = _state_set
3368 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3370 _event_consume(sd, event_info, event_type, ev_flag);
3375 if (!st->zoom_st.timestamp) /* Now scan touched-devices list
3376 * and find other finger */
3378 EINA_LIST_FOREACH(sd->touched, l, p)
3379 { /* Device of other finger <> pe device */
3380 if (p->device != pe->device)
3384 if (!p) /* Single finger on touch */
3387 /* Record down fingers */
3388 _event_consume(sd, event_info, event_type, ev_flag);
3389 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
3390 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
3392 /* Set mv field as well to be ready for MOVE events */
3393 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3394 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
3396 /* Here we have zoom_st, zoom_st1 set, report START */
3397 /* Set zoom-base after BOTH down events recorded */
3398 /* Compute length of line between fingers zoom start */
3399 st->info.zoom = 1.0;
3400 st->zoom_base = _finger_gap_length_get
3401 (st->zoom_st1.x, st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
3402 &st->info.x, &st->info.y);
3404 st->info.radius = st->zoom_base / 2;
3406 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
3407 /* zoom started with mouse-wheel, don't report twice */
3408 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
3410 ev_flag = _state_set
3411 (gesture_zoom, ELM_GESTURE_STATE_START, &st->info,
3413 _event_consume(sd, event_info, event_type, ev_flag);
3416 return; /* Zoom started */
3417 } /* End of ZOOM_START handling */
3419 /* if we got here, we have (exacally) two fingers on surfce */
3420 /* we also after START, report MOVE */
3421 /* First detect which finger moved */
3422 if (pe->device == st->zoom_mv.device)
3423 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3424 else if (pe->device == st->zoom_mv1.device)
3425 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
3427 /* Compute change in zoom as fingers move */
3428 st->info.zoom = _zoom_compute(st,
3429 st->zoom_mv.x, st->zoom_mv.y,
3430 st->zoom_mv1.x, st->zoom_mv1.y,
3431 sd->zoom_finger_factor);
3433 if (!st->zoom_distance_tolerance) /* Zoom broke tolerance,
3436 double d = st->info.zoom - st->next_step;
3440 if (d >= sd->zoom_step) /* Report move in steps */
3442 st->next_step = st->info.zoom;
3444 ev_flag = _state_set(gesture_zoom,
3445 ELM_GESTURE_STATE_MOVE,
3446 &st->info, EINA_TRUE);
3447 _event_consume(sd, event_info, event_type, ev_flag);
3449 } /* End of ZOOM_MOVE handling */
3454 case EVAS_CALLBACK_MOUSE_UP:
3455 case EVAS_CALLBACK_MULTI_UP:
3456 /* Reset timestamp of finger-up.This is used later
3457 by _zoom_test_reset() to retain finger-down data */
3458 _event_consume(sd, event_info, event_type, ev_flag);
3459 if (((st->zoom_wheel) || (st->zoom_base)) &&
3460 (st->zoom_distance_tolerance == 0))
3462 ev_flag = _state_set(gesture_zoom, ELM_GESTURE_STATE_END,
3463 &st->info, EINA_FALSE);
3464 _event_consume(sd, event_info, event_type, ev_flag);
3469 /* if we got here not a ZOOM */
3470 /* Must be != undefined, if gesture started */
3471 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
3473 ev_flag = _state_set
3474 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3476 _event_consume(sd, event_info, event_type, ev_flag);
3479 _zoom_test_reset(gesture_zoom);
3489 _rotate_properties_get(Rotate_Type *st,
3496 /* FIXME: Fix momentum computation, it's wrong */
3497 double prev_angle = *angle;
3499 st->info.radius = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3500 &st->info.x, &st->info.y) / 2;
3502 *angle = _angle_get(xx1, yy1, xx2, yy2);
3504 if (angle == &st->info.angle) /* Fingers are moving, compute momentum */
3506 unsigned int tm_start =
3507 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3508 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
3509 unsigned int tm_end =
3510 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3511 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3513 unsigned int tm_total = tm_end - tm_start;
3514 if (tm_total) /* Momentum computed as:
3515 accumulated roation angle (deg) divided by time */
3518 if (((prev_angle < 90) && ((*angle) > 270)) ||
3519 /* We circle passing ZERO point */
3520 ((prev_angle > 270) && ((*angle) < 90)))
3522 prev_angle = (*angle);
3524 else m = prev_angle - (*angle);
3526 st->accum_momentum += m;
3528 if ((tm_end - st->prev_momentum_tm) < 100)
3529 st->prev_momentum += m;
3532 if (fabs(st->prev_momentum) < 0.002)
3533 st->accum_momentum = 0.0; /* reset momentum */
3535 st->prev_momentum = 0.0; /* Start again */
3538 st->prev_momentum_tm = tm_end;
3539 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3543 st->info.momentum = 0;
3549 * This function is used to test rotation gesture.
3550 * user may combine zoom, rotation together.
3551 * so its possible that both will be detected from input.
3552 * (both are two-finger movement-oriented gestures)
3554 * @param obj The gesture-layer object.
3555 * @param event_info Pointer to recent input event.
3556 * @param event_type Recent input event type.
3557 * @param g_type what Gesture we are testing.
3559 * @ingroup Elm_Gesture_Layer
3562 _rotate_test(Evas_Object *obj,
3565 Evas_Callback_Type event_type,
3566 Elm_Gesture_Type g_type)
3568 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3569 Gesture_Info *gesture;
3570 Rotate_Type *st = NULL;
3572 if (!_elm_config->glayer_rotate_finger_enable)
3578 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3580 if (!sd->gesture[g_type]) return;
3582 gesture = sd->gesture[g_type];
3583 if (!gesture) return ;
3586 if (!st) /* Allocated once on first time */
3588 st = calloc(1, sizeof(Rotate_Type));
3590 _rotate_test_reset(gesture);
3595 case EVAS_CALLBACK_MOUSE_MOVE:
3596 case EVAS_CALLBACK_MULTI_MOVE:
3597 /* if non-continues mode and gesture NOT started, ignore MOVE */
3598 if ((!sd->glayer_continues_enable) &&
3599 (!st->rotate_st.timestamp))
3601 // fallthrough is intentional
3602 case EVAS_CALLBACK_MOUSE_DOWN:
3603 case EVAS_CALLBACK_MULTI_DOWN:
3604 { /* Here we take care of rotate-start and rotate move */
3608 if (eina_list_count(sd->touched) > 2) /* Process rotate only
3612 ev_flag = _state_set
3613 (gesture, ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3614 _event_consume(sd, event_info, event_type, ev_flag);
3619 if (!st->rotate_st.timestamp) /* Now scan touched-devices list
3620 * and find other finger */
3622 EINA_LIST_FOREACH(sd->touched, l, p)
3623 { /* Device of other finger <> pe device */
3624 if (p->device != pe->device)
3629 return; /* Single finger on touch */
3631 /* Record down fingers */
3632 _event_consume(sd, event_info, event_type, ev_flag);
3633 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3634 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3636 /* Set mv field as well to be ready for MOVE events */
3637 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3638 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3640 /* Here we have rotate_st, rotate_st1 set, report START */
3641 /* Set rotate-base after BOTH down events recorded */
3642 /* Compute length of line between fingers rotate start */
3643 _rotate_properties_get(st,
3644 st->rotate_st.x, st->rotate_st.y,
3645 st->rotate_st1.x, st->rotate_st1.y,
3646 &st->info.base_angle);
3648 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
3649 &st->info, EINA_FALSE);
3650 _event_consume(sd, event_info, event_type, ev_flag);
3652 return; /* Rotate started */
3653 } /* End of ROTATE_START handling */
3655 /* if we got here, we have (exacally) two fingers on surfce */
3656 /* we also after START, report MOVE */
3657 /* First detect which finger moved */
3658 if (pe->device == st->rotate_mv.device)
3659 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3660 else if (pe->device == st->rotate_mv1.device)
3661 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3663 /* Compute change in rotate as fingers move */
3664 _rotate_properties_get(st,
3665 st->rotate_mv.x, st->rotate_mv.y,
3666 st->rotate_mv1.x, st->rotate_mv1.y,
3669 if (_on_rotation_broke_tolerance(st)) /* Rotation broke
3673 double d = st->info.angle - st->next_step;
3677 if (d >= sd->rotate_step) /* Report move in steps */
3679 st->next_step = st->info.angle;
3681 ev_flag = _state_set
3682 (gesture, ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3683 _event_consume(sd, event_info, event_type, ev_flag);
3685 } /* End of ROTATE_MOVE handling */
3690 case EVAS_CALLBACK_MOUSE_UP:
3691 case EVAS_CALLBACK_MULTI_UP:
3692 _event_consume(sd, event_info, event_type, ev_flag);
3693 /* Reset timestamp of finger-up.This is used later
3694 by rotate_test_reset() to retain finger-down data */
3695 if (st->rotate_angular_tolerance < 0)
3697 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
3698 &st->info, EINA_FALSE);
3699 _event_consume(sd, event_info, event_type, ev_flag);
3704 /* Must be != undefined, if gesture started */
3705 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3707 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
3708 &st->info, EINA_FALSE);
3709 _event_consume(sd, event_info, event_type, ev_flag);
3712 _rotate_test_reset(gesture);
3720 EOLIAN static Eina_Bool
3721 _elm_gesture_layer_elm_widget_disable(Eo *obj, Elm_Gesture_Layer_Data *_pd EINA_UNUSED)
3723 if (elm_widget_disabled_get(obj))
3724 _callbacks_unregister(obj);
3726 _callbacks_register(obj);
3732 _elm_gesture_layer_evas_object_smart_add(Eo *obj, Elm_Gesture_Layer_Data *priv)
3734 eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
3735 elm_widget_sub_object_parent_add(obj);
3737 priv->line_min_length =
3738 _elm_config->glayer_line_min_length * elm_config_finger_size_get();
3739 priv->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance
3740 * elm_config_finger_size_get();
3741 priv->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance
3742 * elm_config_finger_size_get();
3743 priv->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3744 /* mouse wheel zoom steps */
3745 priv->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor;
3746 priv->rotate_angular_tolerance =
3747 _elm_config->glayer_rotate_angular_tolerance;
3748 priv->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3749 priv->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3750 priv->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3751 priv->repeat_events = EINA_TRUE;
3752 priv->glayer_continues_enable = _elm_config->glayer_continues_enable;
3754 /* FIXME: Hack to get around old configs - if too small, enlarge. */
3755 if (_elm_config->glayer_double_tap_timeout < 0.00001)
3756 _elm_config->glayer_double_tap_timeout = 0.25;
3757 priv->double_tap_timeout = _elm_config->glayer_double_tap_timeout;
3759 memset(priv->gesture, 0, sizeof(priv->gesture));
3762 static void _cbs_clean(Elm_Gesture_Layer_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type);
3765 _elm_gesture_layer_evas_object_smart_del(Eo *obj, Elm_Gesture_Layer_Data *sd)
3767 Pointer_Event *data;
3770 /* Clear all gestures intermediate data, stop any timers */
3772 /* FIXME: +1 because of the mistake in the enum. */
3773 Gesture_Info **gitr = sd->gesture + 1;
3774 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
3775 for (; fitr->reset; fitr++, gitr++)
3777 if (IS_TESTED_GESTURE(*gitr))
3782 /* First Free all gestures internal data structures */
3783 for (i = 0; i < ELM_GESTURE_LAST; i++)
3786 if (sd->gesture[i]->data)
3787 free(sd->gesture[i]->data);
3789 _cbs_clean(sd, i, ELM_GESTURE_STATE_START);
3790 _cbs_clean(sd, i, ELM_GESTURE_STATE_MOVE);
3791 _cbs_clean(sd, i, ELM_GESTURE_STATE_END);
3792 _cbs_clean(sd, i, ELM_GESTURE_STATE_ABORT);
3793 free(sd->gesture[i]);
3794 sd->gesture[i] = NULL; /* Referenced by _event_history_clear */
3796 ecore_timer_del(sd->gest_taps_timeout);
3798 /* Then take care of clearing events */
3799 _event_history_clear(obj);
3800 sd->pending = eina_list_free(sd->pending);
3802 EINA_LIST_FREE(sd->touched, data)
3805 if (!elm_widget_disabled_get(obj))
3806 _callbacks_unregister(obj);
3808 eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
3812 elm_gesture_layer_add(Evas_Object *parent)
3814 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3815 Evas_Object *obj = eo_add(MY_CLASS, parent);
3821 _elm_gesture_layer_eo_base_constructor(Eo *obj, Elm_Gesture_Layer_Data *_pd EINA_UNUSED)
3823 eo_do_super(obj, MY_CLASS, eo_constructor());
3824 eo_do(obj, evas_obj_type_set(MY_CLASS_NAME_LEGACY));
3827 EOLIAN static Eina_Bool
3828 _elm_gesture_layer_hold_events_get(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd)
3830 return !sd->repeat_events;
3834 _elm_gesture_layer_hold_events_set(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd, Eina_Bool hold_events)
3836 sd->repeat_events = !(!!hold_events);
3839 EOLIAN static double
3840 _elm_gesture_layer_zoom_step_get(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd)
3842 return sd->zoom_step;
3846 _elm_gesture_layer_zoom_step_set(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd, double step)
3848 if (step < 0) return;
3850 sd->zoom_step = step;
3853 EOLIAN static double
3854 _elm_gesture_layer_rotate_step_get(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd)
3856 return sd->rotate_step;
3860 _elm_gesture_layer_rotate_step_set(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd, double step)
3862 if (step < 0) return;
3864 sd->rotate_step = step;
3867 EOLIAN static Eina_Bool
3868 _elm_gesture_layer_attach(Eo *obj, Elm_Gesture_Layer_Data *sd, Evas_Object *target)
3870 if (!target) return EINA_FALSE;
3872 /* if was attached before, unregister callbacks first */
3874 _callbacks_unregister(obj);
3876 sd->target = target;
3878 _callbacks_register(obj);
3883 _cbs_clean(Elm_Gesture_Layer_Data *sd,
3884 Elm_Gesture_Type idx,
3885 Elm_Gesture_State cb_type)
3887 if (!sd->gesture[idx]) return;
3890 EINA_INLIST_FREE(sd->gesture[idx]->cbs[cb_type], cb_info)
3892 sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
3893 sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
3896 SET_TEST_BIT(sd->gesture[idx]);
3900 _elm_gesture_layer_cb_set(Eo *obj, Elm_Gesture_Layer_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3902 /* Clear gesture intermediate data, stop any timers */
3903 if (IS_TESTED_GESTURE(sd->gesture[idx]))
3904 _glayer_tests_array[idx].reset(sd->gesture[idx]);
3906 _cbs_clean(sd, idx, cb_type); // for ABI compat.
3907 eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
3911 _elm_gesture_layer_cb_add(Eo *obj, Elm_Gesture_Layer_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3917 if (!sd->gesture[idx])
3918 sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3919 if (!sd->gesture[idx]) return;
3921 Func_Data *cb_info = calloc(1, sizeof(*cb_info));
3922 if (!cb_info) return;
3924 cb_info->user_data = data;
3926 p = sd->gesture[idx];
3929 p->cbs[cb_type] = eina_inlist_append(p->cbs[cb_type],
3930 EINA_INLIST_GET(cb_info));
3931 p->state = ELM_GESTURE_STATE_UNDEFINED;
3936 _elm_gesture_layer_cb_del(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3938 if (!sd->gesture[idx]) return;
3942 EINA_INLIST_FOREACH_SAFE(sd->gesture[idx]->cbs[cb_type], itr, cb_info)
3944 if (cb_info->cb == cb && cb_info->user_data == data)
3946 /* Clear gesture intermediate data, stop any timers */
3947 if (IS_TESTED_GESTURE(sd->gesture[idx]))
3948 _glayer_tests_array[idx].reset(sd->gesture[idx]);
3950 sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
3951 sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
3953 SET_TEST_BIT(sd->gesture[idx]);
3960 elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length)
3962 ELM_GESTURE_LAYER_CHECK(obj);
3963 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3964 sd->line_min_length = line_min_length;
3968 elm_gesture_layer_line_min_length_get(const Evas_Object *obj)
3970 ELM_GESTURE_LAYER_CHECK(obj) 0;
3971 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3972 return sd->line_min_length;
3976 elm_gesture_layer_zoom_distance_tolerance_set(Evas_Object *obj, Evas_Coord zoom_distance_tolerance)
3978 ELM_GESTURE_LAYER_CHECK(obj);
3979 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3980 sd->zoom_distance_tolerance = zoom_distance_tolerance;
3984 elm_gesture_layer_zoom_distance_tolerance_get(const Evas_Object *obj)
3986 ELM_GESTURE_LAYER_CHECK(obj) 0;
3987 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3988 return sd->zoom_distance_tolerance;
3992 elm_gesture_layer_line_distance_tolerance_set(Evas_Object *obj, Evas_Coord line_distance_tolerance)
3994 ELM_GESTURE_LAYER_CHECK(obj);
3995 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3996 sd->line_distance_tolerance = line_distance_tolerance;
4000 elm_gesture_layer_line_distance_tolerance_get(const Evas_Object *obj)
4002 ELM_GESTURE_LAYER_CHECK(obj) 0;
4003 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4004 return sd->line_distance_tolerance;
4008 elm_gesture_layer_line_angular_tolerance_set(Evas_Object *obj, double line_angular_tolerance)
4010 ELM_GESTURE_LAYER_CHECK(obj);
4011 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4012 sd->line_angular_tolerance = line_angular_tolerance;
4016 elm_gesture_layer_line_angular_tolerance_get(const Evas_Object *obj)
4018 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4019 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4020 return sd->line_angular_tolerance;
4024 elm_gesture_layer_zoom_wheel_factor_set(Evas_Object *obj, double zoom_wheel_factor)
4026 ELM_GESTURE_LAYER_CHECK(obj);
4027 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4028 sd->zoom_wheel_factor = zoom_wheel_factor;
4032 elm_gesture_layer_zoom_wheel_factor_get(const Evas_Object *obj)
4034 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4035 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4036 return sd->zoom_wheel_factor;
4040 elm_gesture_layer_zoom_finger_factor_set(Evas_Object *obj, double zoom_finger_factor)
4042 ELM_GESTURE_LAYER_CHECK(obj);
4043 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4044 sd->zoom_finger_factor = zoom_finger_factor;
4048 elm_gesture_layer_zoom_finger_factor_get(const Evas_Object *obj)
4050 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4051 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4052 return sd->zoom_finger_factor;
4056 elm_gesture_layer_rotate_angular_tolerance_set(Evas_Object *obj, double rotate_angular_tolerance)
4058 ELM_GESTURE_LAYER_CHECK(obj);
4059 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4060 sd->rotate_angular_tolerance = rotate_angular_tolerance;
4064 elm_gesture_layer_rotate_angular_tolerance_get(const Evas_Object *obj)
4066 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4067 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4068 return sd->rotate_angular_tolerance;
4072 elm_gesture_layer_flick_time_limit_ms_set(Evas_Object *obj, unsigned int flick_time_limit_ms)
4074 ELM_GESTURE_LAYER_CHECK(obj);
4075 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4076 sd->flick_time_limit_ms = flick_time_limit_ms;
4080 elm_gesture_layer_flick_time_limit_ms_get(const Evas_Object *obj)
4082 ELM_GESTURE_LAYER_CHECK(obj) 0;
4083 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4084 return sd->flick_time_limit_ms;
4088 elm_gesture_layer_long_tap_start_timeout_set(Evas_Object *obj, double long_tap_start_timeout)
4090 ELM_GESTURE_LAYER_CHECK(obj);
4091 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4092 sd->long_tap_start_timeout = long_tap_start_timeout;
4096 elm_gesture_layer_long_tap_start_timeout_get(const Evas_Object *obj)
4098 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4099 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4100 return sd->long_tap_start_timeout;
4104 elm_gesture_layer_continues_enable_set(Evas_Object *obj, Eina_Bool continues_enable)
4106 ELM_GESTURE_LAYER_CHECK(obj);
4107 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4108 sd->glayer_continues_enable = continues_enable;
4112 elm_gesture_layer_continues_enable_get(const Evas_Object *obj)
4114 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4115 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4116 return sd->glayer_continues_enable;
4120 elm_gesture_layer_double_tap_timeout_set(Evas_Object *obj, double double_tap_timeout)
4122 ELM_GESTURE_LAYER_CHECK(obj);
4123 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4124 sd->double_tap_timeout = double_tap_timeout;
4128 elm_gesture_layer_double_tap_timeout_get(const Evas_Object *obj)
4130 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
4131 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
4132 return sd->double_tap_timeout;
4136 _elm_gesture_layer_tap_finger_size_set(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd, Evas_Coord sz)
4139 sz = 0; /* Should not be negative, will reset to system value */
4141 sd->tap_finger_size = sz;
4144 EOLIAN static Evas_Coord
4145 _elm_gesture_layer_tap_finger_size_get(Eo *obj EINA_UNUSED, Elm_Gesture_Layer_Data *sd)
4147 return sd->tap_finger_size;
4151 _elm_gesture_layer_class_constructor(Eo_Class *klass)
4153 evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
4156 #include "elm_gesture_layer.eo.c"