1 #include <Elementary.h>
4 static const char GESTURE_LAYER_SMART_NAME[] = "elm_gesture_layer";
7 #define ELM_MOUSE_DEVICE 0
8 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
9 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
10 #define ELM_GESTURE_MOMENTUM_DELAY 25
11 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
12 #define ELM_GESTURE_MULTI_TIMEOUT 50
13 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
15 /* Some Trigo values */
16 #define RAD_90DEG M_PI_2
17 #define RAD_180DEG M_PI
18 #define RAD_270DEG (M_PI_2 * 3)
19 #define RAD_360DEG (M_PI * 2)
21 #define RAD2DEG(x) ((x) * 57.295779513)
22 #define DEG2RAD(x) ((x) / 57.295779513)
25 _glayer_buf_dup(void *buf, size_t size)
35 #define COPY_EVENT_INFO(EV) _glayer_buf_dup(EV, sizeof(*EV))
37 #define SET_TEST_BIT(P) \
39 P->test = P->fn[ELM_GESTURE_STATE_START].cb || \
40 P->fn[ELM_GESTURE_STATE_MOVE].cb || \
41 P->fn[ELM_GESTURE_STATE_END].cb || \
42 P->fn[ELM_GESTURE_STATE_ABORT].cb; \
45 #define IS_TESTED_GESTURE(gesture) \
46 ((gesture) ? (gesture)->test : EINA_FALSE)
48 #define IS_TESTED(T) \
49 ((sd->gesture[T]) ? sd->gesture[T]->test : EINA_FALSE)
51 #define ELM_GESTURE_LAYER_DATA_GET(o, sd) \
52 Elm_Gesture_Layer_Smart_Data * sd = evas_object_smart_data_get(o)
54 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN(o, ptr) \
55 ELM_GESTURE_LAYER_DATA_GET(o, ptr); \
58 CRITICAL("No widget data for object %p (%s)", \
59 o, evas_object_type_get(o)); \
63 #define ELM_GESTURE_LAYER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
64 ELM_GESTURE_LAYER_DATA_GET(o, ptr); \
67 CRITICAL("No widget data for object %p (%s)", \
68 o, evas_object_type_get(o)); \
72 #define ELM_GESTURE_LAYER_CHECK(obj) \
73 if (!obj || !elm_widget_type_check((obj), \
74 GESTURE_LAYER_SMART_NAME, __func__)) \
77 EVAS_SMART_SUBCLASS_NEW
78 (GESTURE_LAYER_SMART_NAME, _elm_gesture_layer, Elm_Widget_Smart_Class,
79 Elm_Widget_Smart_Class, elm_widget_smart_class_get, NULL);
84 * @struct _Pointer_Event
85 * Struct holds pointer-event info
86 * This is a generic pointer event structure
88 * @ingroup Elm_Gesture_Layer
93 unsigned int timestamp;
95 Evas_Callback_Type event_type;
101 * @typedef Pointer_Event
102 * Type for generic pointer event structure
104 * @ingroup Elm_Gesture_Layer
106 typedef struct _Pointer_Event Pointer_Event;
112 * Struct holds callback information.
114 * @ingroup Elm_Gesture_Layer
118 void *user_data; /**< Holds user data to CB (like sd) */
119 Elm_Gesture_Event_Cb cb;
126 * type for callback information
128 * @ingroup Elm_Gesture_Layer
130 typedef struct _Func_Data Func_Data;
135 * @struct _Gesture_Info
136 * Struct holds gesture info
138 * @ingroup Elm_Gesture_Layer
143 void *data; /**< Holds gesture intemidiate processing data */
144 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
145 Elm_Gesture_Type g_type; /**< gesture type */
146 Elm_Gesture_State state; /**< gesture state */
147 void *info; /**< Data for the state callback */
148 Eina_Bool test; /**< if true this gesture should be tested on input */
154 * @typedef Gesture_Info
155 * Type for _Gesture_Info
157 * @ingroup Elm_Gesture_Layer
159 typedef struct _Gesture_Info Gesture_Info;
163 void (*test)(Evas_Object *obj, Pointer_Event *pe,
164 void *event_info, Evas_Callback_Type event_type,
165 Elm_Gesture_Type g_type);
166 void (*reset)(Gesture_Info *gesture);
167 void (*cont_reset)(Gesture_Info *gesture); /* Can be NULL. */
170 /* functions referred by _glayer_tests_array */
171 static void _tap_gesture_test(Evas_Object *obj,
174 Evas_Callback_Type event_type,
175 Elm_Gesture_Type g_type);
176 static void _tap_gestures_test_reset(Gesture_Info *gesture);
177 static void _n_long_tap_test(Evas_Object *obj,
180 Evas_Callback_Type event_type,
181 Elm_Gesture_Type g_type);
182 static void _n_long_tap_test_reset(Gesture_Info *gesture);
183 static void _momentum_test(Evas_Object *obj,
186 Evas_Callback_Type event_type,
187 Elm_Gesture_Type g_type);
188 static void _momentum_test_reset(Gesture_Info *gesture);
189 static void _n_line_test(Evas_Object *obj,
192 Evas_Callback_Type event_type,
193 Elm_Gesture_Type g_type);
194 static void _line_test_reset(Gesture_Info *gesture);
195 static void _zoom_test(Evas_Object *obj,
198 Evas_Callback_Type event_type,
199 Elm_Gesture_Type g_type);
200 static void _zoom_test_reset(Gesture_Info *gesture);
201 static void _rotate_test(Evas_Object *obj,
204 Evas_Callback_Type event_type,
205 Elm_Gesture_Type g_type);
206 static void _rotate_test_reset(Gesture_Info *gesture);
208 static void _event_process(void *data,
211 Evas_Callback_Type event_type);
213 /* Should be the same order as _Elm_Gesture_Type */
214 static Tests_Array_Funcs _glayer_tests_array[] = {
215 { NULL, NULL, NULL }, /** Because someone made an awful mistake. */
216 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
217 /* ELM_GESTURE_N_TAPS */
218 { _n_long_tap_test, _n_long_tap_test_reset, NULL },
219 /* ELM_GESTURE_N_LONG_TAPS */
220 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
221 /* ELM_GESTURE_N_DOUBLE_TAPS */
222 { _tap_gesture_test, _tap_gestures_test_reset, NULL },
223 /* ELM_GESTURE_N_TRIPLE_TAPS */
224 { _momentum_test, _momentum_test_reset, _momentum_test_reset },
225 /* ELM_GESTURE_MOMENTUM */
226 { _n_line_test, _line_test_reset, _line_test_reset },
227 /* ELM_GESTURE_N_LINES */
228 { _n_line_test, _line_test_reset, _line_test_reset },
229 /* ELM_GESTURE_N_FLICKS */
230 { _zoom_test, _zoom_test_reset, _zoom_test_reset },
231 /* ELM_GESTURE_ZOOM */
232 { _rotate_test, _rotate_test_reset, _rotate_test_reset },
233 /* ELM_GESTURE_ROTATE */
240 * @struct _Event_History
241 * Struct holds event history.
242 * These events are repeated if no gesture found.
244 * @ingroup Elm_Gesture_Layer
246 struct _Event_History
250 Evas_Callback_Type event_type;
256 * @typedef Event_History
257 * Type for _Event_History
259 * @ingroup Elm_Gesture_Layer
261 typedef struct _Event_History Event_History;
263 /* All *Type structs hold result for the user in 'info' field
264 * The rest is gesture processing intermediate data.
265 * NOTE: info field must be FIRST in the struct.
266 * This is used when reporting ABORT in _event_history_clear() */
269 Elm_Gesture_Taps_Info info;
272 unsigned int n_taps_needed;
276 typedef struct _Taps_Type Taps_Type;
278 struct _Long_Tap_Type
280 Elm_Gesture_Taps_Info info;
283 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
286 typedef struct _Long_Tap_Type Long_Tap_Type;
288 struct _Momentum_Type /* Fields used by _line_test() */
290 Elm_Gesture_Momentum_Info info;
291 Evas_Coord_Point line_st;
292 Evas_Coord_Point line_end;
293 unsigned int t_st_x; /* Time start on X */
294 unsigned int t_st_y; /* Time start on Y */
295 unsigned int t_end; /* Time end */
296 unsigned int t_up; /* Recent up event time */
299 typedef struct _Momentum_Type Momentum_Type;
303 Evas_Coord_Point line_st;
304 Evas_Coord_Point line_end;
305 Evas_Coord line_length;
306 unsigned int t_st; /* Time start */
307 unsigned int t_end; /* Time end */
309 double line_angle; /* Current angle of line */
311 typedef struct _Line_Data Line_Data;
313 struct _Line_Type /* Fields used by _line_test() */
315 Elm_Gesture_Line_Info info;
316 Eina_List *list; /* List of Line_Data */
318 typedef struct _Line_Type Line_Type;
320 struct _Zoom_Type /* Fields used by _zoom_test() */
322 Elm_Gesture_Zoom_Info info;
323 Pointer_Event zoom_st;
324 Pointer_Event zoom_mv;
325 Pointer_Event zoom_st1;
326 Pointer_Event zoom_mv1;
327 Evas_Event_Mouse_Wheel *zoom_wheel;
328 Evas_Coord zoom_base; /* Holds gap between fingers on
330 Evas_Coord zoom_distance_tolerance;
331 unsigned int m_st_tm; /* momentum start time */
332 unsigned int m_prev_tm; /* momentum prev time */
333 int dir; /* Direction: 1=zoom-in, (-1)=zoom-out */
334 double m_base; /* zoom value when momentum starts */
337 typedef struct _Zoom_Type Zoom_Type;
339 struct _Rotate_Type /* Fields used by _rotation_test() */
341 Elm_Gesture_Rotate_Info info;
342 Pointer_Event rotate_st;
343 Pointer_Event rotate_mv;
344 Pointer_Event rotate_st1;
345 Pointer_Event rotate_mv1;
346 unsigned int prev_momentum_tm; /* timestamp of prev_momentum */
347 double prev_momentum; /* Snapshot of momentum 0.01
349 double accum_momentum;
350 double rotate_angular_tolerance;
353 typedef struct _Rotate_Type Rotate_Type;
355 typedef struct _Elm_Gesture_Layer_Smart_Data Elm_Gesture_Layer_Smart_Data;
356 struct _Elm_Gesture_Layer_Smart_Data
358 Elm_Widget_Smart_Data base; /* base widget smart data as
359 * first member obligatory, as
360 * we're inheriting from it */
362 Evas_Object *target; /* Target Widget */
363 Event_History *event_history_list;
366 Evas_Coord zoom_distance_tolerance;
367 Evas_Coord line_distance_tolerance;
368 double line_angular_tolerance;
369 double zoom_wheel_factor; /* mouse wheel zoom steps */
370 double zoom_finger_factor; /* used for zoom factor */
371 double rotate_angular_tolerance;
372 unsigned int flick_time_limit_ms;
373 double long_tap_start_timeout;
374 Eina_Bool glayer_continues_enable;
375 double double_tap_timeout;
380 Gesture_Info *gesture[ELM_GESTURE_LAST];
381 Eina_List *pending; /* List of devices need to refeed
383 Eina_List *touched; /* Information of touched devices */
386 Ecore_Timer *gest_taps_timeout; /* When this expires, dbl
387 * click/taps ABORTed */
389 Eina_Bool repeat_events : 1;
392 /* START - Functions to manage touched-device list */
395 * This function is used to find if device is touched
397 * @ingroup Elm_Gesture_Layer
400 _device_compare(const void *data1,
403 /* Compare the two device numbers */
404 return ((Pointer_Event *)data1)->device - ((Pointer_Event *)data2)->device;
410 * Remove Pointer Event from touched device list
411 * @param list Pointer to touched device list.
412 * @param Pointer_Event Pointer to PE.
414 * @ingroup Elm_Gesture_Layer
417 _touched_device_remove(Eina_List *list,
420 Eina_List *lst = NULL;
421 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
424 lst = eina_list_remove(list, p);
435 * Recoed Pointer Event in touched device list
436 * Note: This fuction allocates memory for PE event
437 * This memory is released in _touched_device_remove()
438 * @param list Pointer to touched device list.
439 * @param Pointer_Event Pointer to PE.
441 * @ingroup Elm_Gesture_Layer
444 _touched_device_add(Eina_List *list,
447 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
449 if (p) /* We like to track device touch-position, overwrite info */
451 memcpy(p, pe, sizeof(Pointer_Event));
455 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
456 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN)) /* Add touched
460 p = malloc(sizeof(Pointer_Event));
461 /* Freed in _touched_device_remove() */
462 memcpy(p, pe, sizeof(Pointer_Event));
463 return eina_list_append(list, p);
469 /* END - Functions to manage touched-device list */
475 * @param event_info pointer to event.
477 * @ingroup Elm_Gesture_Layer
479 static Evas_Event_Flags
480 _event_flag_get(void *event_info,
481 Evas_Callback_Type event_type)
485 case EVAS_CALLBACK_MOUSE_IN:
486 return ((Evas_Event_Mouse_In *)event_info)->event_flags;
488 case EVAS_CALLBACK_MOUSE_OUT:
489 return ((Evas_Event_Mouse_Out *)event_info)->event_flags;
491 case EVAS_CALLBACK_MOUSE_DOWN:
492 return ((Evas_Event_Mouse_Down *)event_info)->event_flags;
494 case EVAS_CALLBACK_MOUSE_MOVE:
495 return ((Evas_Event_Mouse_Move *)event_info)->event_flags;
497 case EVAS_CALLBACK_MOUSE_UP:
498 return ((Evas_Event_Mouse_Up *)event_info)->event_flags;
500 case EVAS_CALLBACK_MOUSE_WHEEL:
501 return ((Evas_Event_Mouse_Wheel *)event_info)->event_flags;
503 case EVAS_CALLBACK_MULTI_DOWN:
504 return ((Evas_Event_Multi_Down *)event_info)->event_flags;
506 case EVAS_CALLBACK_MULTI_MOVE:
507 return ((Evas_Event_Multi_Move *)event_info)->event_flags;
509 case EVAS_CALLBACK_MULTI_UP:
510 return ((Evas_Event_Multi_Up *)event_info)->event_flags;
512 case EVAS_CALLBACK_KEY_DOWN:
513 return ((Evas_Event_Key_Down *)event_info)->event_flags;
515 case EVAS_CALLBACK_KEY_UP:
516 return ((Evas_Event_Key_Up *)event_info)->event_flags;
519 return EVAS_EVENT_FLAG_NONE;
526 * Sets event flag to value returned from user callback
527 * @param sd Widget Data
528 * @param event_info pointer to event.
529 * @param event_type what type was ev (mouse down, etc...)
530 * @param ev_flags event flags
532 * @ingroup Elm_Gesture_Layer
535 _event_consume(Elm_Gesture_Layer_Smart_Data *sd,
537 Evas_Callback_Type event_type,
538 Evas_Event_Flags ev_flags)
540 /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
541 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
542 /* should not refeed this event. */
544 return; /* This happens when restarting gestures */
546 if (!sd->repeat_events) ev_flags |= EVAS_EVENT_FLAG_ON_HOLD;
552 case EVAS_CALLBACK_MOUSE_DOWN:
553 ((Evas_Event_Mouse_Down *)event_info)->event_flags |= ev_flags;
556 case EVAS_CALLBACK_MOUSE_MOVE:
557 ((Evas_Event_Mouse_Move *)event_info)->event_flags |= ev_flags;
560 case EVAS_CALLBACK_MOUSE_UP:
561 ((Evas_Event_Mouse_Up *)event_info)->event_flags |= ev_flags;
564 case EVAS_CALLBACK_MOUSE_WHEEL:
565 ((Evas_Event_Mouse_Wheel *)event_info)->event_flags |= ev_flags;
568 case EVAS_CALLBACK_MULTI_DOWN:
569 ((Evas_Event_Multi_Down *)event_info)->event_flags |= ev_flags;
572 case EVAS_CALLBACK_MULTI_MOVE:
573 ((Evas_Event_Multi_Move *)event_info)->event_flags |= ev_flags;
576 case EVAS_CALLBACK_MULTI_UP:
577 ((Evas_Event_Multi_Up *)event_info)->event_flags |= ev_flags;
580 case EVAS_CALLBACK_KEY_DOWN:
581 ((Evas_Event_Key_Down *)event_info)->event_flags |= ev_flags;
584 case EVAS_CALLBACK_KEY_UP:
585 ((Evas_Event_Key_Up *)event_info)->event_flags |= ev_flags;
597 * Report current state of a gesture by calling user callback.
598 * @param gesture what gesture state we report.
599 * @param info inforamtion for user callback
601 * @ingroup Elm_Gesture_Layer
603 static Evas_Event_Flags
604 _state_report(Gesture_Info *gesture,
607 /* We report current state (START, MOVE, END, ABORT), once */
608 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
609 (gesture->fn[gesture->state].cb)) /* Fill state-info struct and
613 return gesture->fn[gesture->state].cb(
614 gesture->fn[gesture->state].user_data, info);
617 return EVAS_EVENT_FLAG_NONE;
623 * Update state for a given gesture.
624 * We may update gesture state to:
625 * - @c UNDEFINED - current input did not start gesure yet.
626 * - @c START - gesture started according to input.
627 * - @c MOVE - gusture in progress.
628 * - @c END - gesture completed according to input.
629 * - @c ABORT - input does not matches gesure.
630 * note that we may move from UNDEFINED to ABORT
631 * because we may detect that gesture will not START
632 * with a given input.
634 * @param g given gesture to change state.
635 * @param s gesure new state.
636 * @param info buffer to be sent to user callback on report_state.
637 * @param force makes report_state to report the new-state even
638 * if its same as current state. Works for MOVE - gesture in progress.
640 * @ingroup Elm_Gesture_Layer
642 static Evas_Event_Flags
643 _state_set(Gesture_Info *g,
648 Elm_Gesture_State old_state;
650 if ((g->state == s) && (!force))
651 return EVAS_EVENT_FLAG_NONE;
653 old_state = g->state;
656 g->info = info; /* Information for user callback */
657 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
658 (g->state == ELM_GESTURE_STATE_END))
659 g->test = EINA_FALSE;
661 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
662 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
663 (s == ELM_GESTURE_STATE_ABORT))))
664 return _state_report(g, g->info);
666 return EVAS_EVENT_FLAG_NONE;
672 * This resets all gesture states and sets test-bit.
673 * this is used for restarting gestures to listen to input.
674 * happens after we complete a gesture or no gesture was detected.
675 * @param sd Widget data of the gesture-layer object.
677 * @ingroup Elm_Gesture_Layer
680 _states_reset(Elm_Gesture_Layer_Smart_Data *sd)
685 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
690 _state_set(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
699 * This function is used to save input events in an abstract struct
700 * to be used later by getsure-testing functions.
702 * @param data The gesture-layer object.
703 * @param event_info Pointer to recent input event.
704 * @param event_type Recent input event type.
705 * @param pe The abstract data-struct (output).
707 * @ingroup Elm_Gesture_Layer
710 _pointer_event_make(void *data __UNUSED__,
712 Evas_Callback_Type event_type,
715 memset(pe, '\0', sizeof(*pe));
718 case EVAS_CALLBACK_MOUSE_DOWN:
719 pe->x = ((Evas_Event_Mouse_Down *)event_info)->canvas.x;
720 pe->y = ((Evas_Event_Mouse_Down *)event_info)->canvas.y;
721 pe->timestamp = ((Evas_Event_Mouse_Down *)event_info)->timestamp;
722 pe->device = ELM_MOUSE_DEVICE;
725 case EVAS_CALLBACK_MOUSE_UP:
726 pe->x = ((Evas_Event_Mouse_Up *)event_info)->canvas.x;
727 pe->y = ((Evas_Event_Mouse_Up *)event_info)->canvas.y;
728 pe->timestamp = ((Evas_Event_Mouse_Up *)event_info)->timestamp;
729 pe->device = ELM_MOUSE_DEVICE;
732 case EVAS_CALLBACK_MOUSE_MOVE:
733 pe->x = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.x;
734 pe->y = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.y;
735 pe->timestamp = ((Evas_Event_Mouse_Move *)event_info)->timestamp;
736 pe->device = ELM_MOUSE_DEVICE;
739 case EVAS_CALLBACK_MULTI_DOWN:
740 pe->x = ((Evas_Event_Multi_Down *)event_info)->canvas.x;
741 pe->y = ((Evas_Event_Multi_Down *)event_info)->canvas.y;
742 pe->timestamp = ((Evas_Event_Multi_Down *)event_info)->timestamp;
743 pe->device = ((Evas_Event_Multi_Down *)event_info)->device;
746 case EVAS_CALLBACK_MULTI_UP:
747 pe->x = ((Evas_Event_Multi_Up *)event_info)->canvas.x;
748 pe->y = ((Evas_Event_Multi_Up *)event_info)->canvas.y;
749 pe->timestamp = ((Evas_Event_Multi_Up *)event_info)->timestamp;
750 pe->device = ((Evas_Event_Multi_Up *)event_info)->device;
753 case EVAS_CALLBACK_MULTI_MOVE:
754 pe->x = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.x;
755 pe->y = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.y;
756 pe->timestamp = ((Evas_Event_Multi_Move *)event_info)->timestamp;
757 pe->device = ((Evas_Event_Multi_Move *)event_info)->device;
764 pe->event_type = event_type;
771 * This function copies input events.
772 * We copy event info before adding it to history.
773 * The memory is freed when we clear history.
775 * @param event the event to copy
776 * @param event_type event type to copy
778 * @ingroup Elm_Gesture_Layer
781 _event_info_copy(void *event,
782 Evas_Callback_Type event_type)
786 case EVAS_CALLBACK_MOUSE_DOWN:
787 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *)event);
790 case EVAS_CALLBACK_MOUSE_MOVE:
791 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *)event);
794 case EVAS_CALLBACK_MOUSE_UP:
795 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *)event);
798 case EVAS_CALLBACK_MOUSE_WHEEL:
799 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *)event);
802 case EVAS_CALLBACK_MULTI_DOWN:
803 return COPY_EVENT_INFO((Evas_Event_Multi_Down *)event);
806 case EVAS_CALLBACK_MULTI_MOVE:
807 return COPY_EVENT_INFO((Evas_Event_Multi_Move *)event);
810 case EVAS_CALLBACK_MULTI_UP:
811 return COPY_EVENT_INFO((Evas_Event_Multi_Up *)event);
814 case EVAS_CALLBACK_KEY_DOWN:
815 return COPY_EVENT_INFO((Evas_Event_Key_Down *)event);
818 case EVAS_CALLBACK_KEY_UP:
819 return COPY_EVENT_INFO((Evas_Event_Key_Up *)event);
828 _event_history_add(Evas_Object *obj,
830 Evas_Callback_Type event_type)
834 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
836 ev = malloc(sizeof(Event_History));
837 ev->event = _event_info_copy(event, event_type); /* Freed on
838 * _event_history_clear */
839 ev->event_type = event_type;
840 sd->event_history_list = (Event_History *)eina_inlist_append(
841 EINA_INLIST_GET(sd->event_history_list), EINA_INLIST_GET(ev));
847 * For all _mouse_* / multi_* functions wethen send this event to
848 * _event_process function.
850 * @param data The gesture-layer object.
851 * @param event_info Pointer to recent input event.
853 * @ingroup Elm_Gesture_Layer
856 _mouse_down_cb(void *data,
858 Evas_Object *obj __UNUSED__,
861 if (((Evas_Event_Mouse_Down *)event_info)->button != 1)
862 return; /* We only process left-click at the moment */
864 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
868 _mouse_move_cb(void *data,
870 Evas_Object *obj __UNUSED__,
873 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
877 _key_down_cb(void *data,
879 Evas_Object *obj __UNUSED__,
882 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
886 _key_up_cb(void *data,
888 Evas_Object *obj __UNUSED__,
891 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
895 _mouse_up_cb(void *data,
897 Evas_Object *obj __UNUSED__,
900 if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
901 return; /* We only process left-click at the moment */
903 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
907 _mouse_wheel_cb(void *data,
909 Evas_Object *obj __UNUSED__,
912 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
916 _multi_down_cb(void *data,
918 Evas_Object *obj __UNUSED__,
921 /* Skip the mouse duplicates. */
922 if (((Evas_Event_Multi_Down *) event_info)->device == 0) return;
924 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
928 _multi_move_cb(void *data,
930 Evas_Object *obj __UNUSED__,
933 /* Skip the mouse duplicates. */
934 if (((Evas_Event_Multi_Move *) event_info)->device == 0) return;
936 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
940 _multi_up_cb(void *data,
942 Evas_Object *obj __UNUSED__,
945 /* Skip the mouse duplicates. */
946 if (((Evas_Event_Multi_Up *) event_info)->device == 0) return;
948 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
954 * We register callbacks when gesture layer is attached to an object
955 * or when its enabled after disable.
957 * @param obj The gesture-layer object.
959 * @ingroup Elm_Gesture_Layer
962 _callbacks_register(Evas_Object *obj)
964 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
966 if (!sd->target) return;
968 evas_object_event_callback_add
969 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
970 evas_object_event_callback_add
971 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
972 evas_object_event_callback_add
973 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
975 evas_object_event_callback_add
976 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
978 evas_object_event_callback_add
979 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
980 evas_object_event_callback_add
981 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
982 evas_object_event_callback_add
983 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
985 evas_object_event_callback_add
986 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
987 evas_object_event_callback_add
988 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
994 * We unregister callbacks when gesture layer is disabled.
996 * @param obj The gesture-layer object.
998 * @ingroup Elm_Gesture_Layer
1001 _callbacks_unregister(Evas_Object *obj)
1003 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1005 if (!sd->target) return;
1007 evas_object_event_callback_del_full
1008 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
1009 evas_object_event_callback_del_full
1010 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
1011 evas_object_event_callback_del_full
1012 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
1014 evas_object_event_callback_del_full
1015 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
1017 evas_object_event_callback_del_full
1018 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
1020 evas_object_event_callback_del_full
1021 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
1023 evas_object_event_callback_del_full
1024 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
1026 evas_object_event_callback_del_full
1027 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
1028 evas_object_event_callback_del_full
1029 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
1034 * This function is used to find if device number
1035 * is found in a list of devices.
1036 * The list contains devices for refeeding *UP event
1038 * @ingroup Elm_Gesture_Layer
1041 _device_in_pending_cmp(const void *data1,
1044 /* Compare the two device numbers */
1045 return ((intptr_t)data1) - ((intptr_t)data2);
1051 * This functions returns pending-device node
1052 * @ingroup Elm_Gesture_Layer
1055 _device_is_pending(Eina_List *list,
1057 Evas_Callback_Type event_type)
1059 int device = ELM_MOUSE_DEVICE;
1063 case EVAS_CALLBACK_MOUSE_UP:
1066 case EVAS_CALLBACK_MULTI_UP:
1067 device = ((Evas_Event_Multi_Up *)event)->device;
1074 return eina_list_search_unsorted_list
1075 (list, _device_in_pending_cmp, (void *)(intptr_t)device);
1081 * This functions adds device to refeed-pending device list
1082 * @ingroup Elm_Gesture_Layer
1085 _pending_device_add(Eina_List *list,
1087 Evas_Callback_Type event_type)
1089 int device = ELM_MOUSE_DEVICE;
1093 case EVAS_CALLBACK_MOUSE_DOWN:
1096 case EVAS_CALLBACK_MULTI_DOWN:
1097 device = ((Evas_Event_Multi_Down *)event)->device;
1104 if (!eina_list_search_unsorted_list
1105 (list, _device_in_pending_cmp, (void *)(intptr_t)device))
1107 return eina_list_append(list, (void *)(intptr_t)device);
1116 * This function reports ABORT to all none-detected gestures
1117 * Then resets test bits for all desired gesures
1118 * and clears input-events history.
1119 * note: if no gesture was detected, events from history list
1120 * are streamed to the widget because it's unused by layer.
1121 * user may cancel refeed of events by setting repeat events.
1123 * @param obj The gesture-layer object.
1125 * @ingroup Elm_Gesture_Layer
1128 _event_history_clear(Evas_Object *obj)
1132 Evas *e = evas_object_evas_get(obj);
1133 Eina_Bool gesture_found = EINA_FALSE;
1135 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1137 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1142 if (p->state == ELM_GESTURE_STATE_END)
1144 gesture_found = EINA_TRUE;
1147 { /* Report ABORT to all gestures that still not finished */
1148 _state_set(p, ELM_GESTURE_STATE_ABORT, sd->gesture[i]->info,
1154 _states_reset(sd); /* we are ready to start testing for gestures again */
1156 /* Clear all gestures intermediate data */
1158 /* FIXME: +1 because of the mistake in the enum. */
1159 Gesture_Info **gitr = sd->gesture + 1;
1160 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1161 for (; fitr->reset; fitr++, gitr++)
1163 if (IS_TESTED_GESTURE(*gitr))
1168 /* Disable gesture layer so refeeded events won't be consumed by it */
1169 _callbacks_unregister(obj);
1170 while (sd->event_history_list)
1173 t = sd->event_history_list;
1174 Eina_List *pending = _device_is_pending
1175 (sd->pending, sd->event_history_list->event,
1176 sd->event_history_list->event_type);
1178 /* Refeed events if no gesture matched input */
1179 if (pending || ((!gesture_found) && (!sd->repeat_events)))
1181 evas_event_refeed_event(e, sd->event_history_list->event,
1182 sd->event_history_list->event_type);
1186 sd->pending = eina_list_remove_list(sd->pending, pending);
1190 sd->pending = _pending_device_add
1191 (sd->pending, sd->event_history_list->event,
1192 sd->event_history_list->event_type);
1196 free(sd->event_history_list->event);
1197 sd->event_history_list = (Event_History *)eina_inlist_remove(
1198 EINA_INLIST_GET(sd->event_history_list),
1199 EINA_INLIST_GET(sd->event_history_list));
1202 _callbacks_register(obj);
1209 * if gesture was NOT detected AND we only have gestures in ABORT state
1210 * we clear history immediately to be ready for input.
1212 * @param obj The gesture-layer object.
1213 * @return TRUE on event history_clear
1215 * @ingroup Elm_Gesture_Layer
1218 _clear_if_finished(Evas_Object *obj)
1221 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
1223 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1225 /* Clear history if all we have aborted gestures */
1226 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1227 { /* If no gesture started and all we have aborted gestures, reset all */
1228 Gesture_Info *p = sd->gesture[i];
1230 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
1232 if ((p->state == ELM_GESTURE_STATE_START) ||
1233 (p->state == ELM_GESTURE_STATE_MOVE))
1234 reset_s = EINA_FALSE;
1236 all_undefined = EINA_FALSE;
1240 if (reset_s && (!all_undefined))
1241 return _event_history_clear(obj);
1249 * This function restartes line, flick, zoom and rotate gestures
1250 * when gesture-layer continues-gestures enabled.
1251 * Example of continues-gesture:
1252 * When doing a line, user stops moving finger but keeps fingers on touch.
1253 * This will cause line-end, then as user continues moving his finger
1254 * it re-starts line gesture.
1255 * When continue mode is disabled, user has to lift finger from touch
1256 * to end a gesture. Them touch-again to start a new one.
1258 * @param data The gesture-layer object.
1259 * @param sd gesture layer widget data.
1260 * @param states_reset flag that marks gestures were reset in history clear.
1262 * @ingroup Elm_Gesture_Layer
1265 _continues_gestures_restart(void *data,
1266 Eina_Bool states_reset)
1268 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1270 /* Test all the gestures */
1272 /* FIXME: +1 because of the mistake in the enum. */
1273 Gesture_Info **gitr = sd->gesture + 1;
1274 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1275 for (; fitr->test; fitr++, gitr++)
1277 Gesture_Info *g = *gitr;
1278 Eina_Bool tmp = (g) ?
1279 ((states_reset) || ((g->state != ELM_GESTURE_STATE_START)
1280 && (g->state != ELM_GESTURE_STATE_MOVE)))
1282 if (tmp && fitr->cont_reset)
1284 fitr->cont_reset(g);
1285 _state_set(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
1295 * This function the core-function where input handling is done.
1296 * Here we get user input and stream it to gesture testing.
1297 * We notify user about any gestures with new state:
1299 * START - gesture started.
1300 * MOVE - gesture is ongoing.
1301 * END - gesture was completed.
1302 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
1304 * We also check if a gesture was detected, then reset event history
1305 * If no gestures were found we reset gesture test flag
1306 * after streaming event-history to widget.
1307 * (stream to the widget all events not consumed as a gesture)
1309 * @param data The gesture-layer object.
1310 * @param event_info Pointer to recent input event.
1311 * @param event_type Recent input event type.
1313 * @ingroup Elm_Gesture_Layer
1316 _event_process(void *data,
1317 Evas_Object *obj __UNUSED__,
1319 Evas_Callback_Type event_type)
1322 Pointer_Event *pe = NULL;
1324 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1326 /* Start testing candidate gesture from here */
1327 if (_pointer_event_make(data, event_info, event_type, &_pe))
1330 /* Test all the gestures */
1332 /* FIXME: +1 because of the mistake in the enum. */
1333 Gesture_Info **gitr = sd->gesture + 1;
1334 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1335 for (; fitr->test; fitr++, gitr++)
1337 if (IS_TESTED_GESTURE(*gitr))
1338 fitr->test(data, pe, event_info, event_type, (*gitr)->g_type);
1342 if (_event_flag_get(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
1343 _event_history_add(data, event_info, event_type);
1345 /* we maintain list of touched devices */
1346 /* We also use move to track current device x.y pos */
1347 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1348 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1349 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1350 (event_type == EVAS_CALLBACK_MULTI_MOVE))
1352 sd->touched = _touched_device_add(sd->touched, pe);
1354 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
1355 (event_type == EVAS_CALLBACK_MULTI_UP))
1357 sd->touched = _touched_device_remove(sd->touched, pe);
1360 /* Report current states and clear history if needed */
1361 Eina_Bool states_reset = _clear_if_finished(data);
1362 if (sd->glayer_continues_enable)
1363 _continues_gestures_restart(data, states_reset);
1367 _inside(Evas_Coord xx1,
1372 int w = elm_config_finger_size_get() >> 1; /* Finger size devided by 2 */
1374 if (xx1 < (xx2 - w))
1377 if (xx1 > (xx2 + w))
1380 if (yy1 < (yy2 - w))
1383 if (yy1 > (yy2 + w))
1389 /* All *test_reset() funcs are called to clear
1390 * gesture intermediate data.
1391 * This happens when we need to reset our tests.
1392 * for example when gesture is detected or all ABORTed. */
1394 _tap_gestures_test_reset(Gesture_Info *gesture)
1399 EINA_SAFETY_ON_NULL_RETURN(gesture);
1400 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1402 if (sd->gest_taps_timeout)
1404 ecore_timer_del(sd->gest_taps_timeout);
1405 sd->gest_taps_timeout = NULL;
1411 EINA_LIST_FREE (((Taps_Type *)gesture->data)->l, data)
1412 EINA_LIST_FREE (data, pe)
1415 memset(gesture->data, 0, sizeof(Taps_Type));
1418 /* All *test_reset() funcs are called to clear
1419 * gesture intermediate data.
1420 * This happens when we need to reset our tests.
1421 * for example when gesture is detected or all ABORTed. */
1423 _n_long_tap_test_reset(Gesture_Info *gesture)
1429 EINA_SAFETY_ON_NULL_RETURN(gesture);
1430 if (!gesture->data) return;
1434 EINA_LIST_FOREACH(st->touched, l, p)
1437 eina_list_free(st->touched);
1440 ecore_timer_del(st->timeout);
1443 memset(gesture->data, 0, sizeof(Long_Tap_Type));
1447 _momentum_test_reset(Gesture_Info *gesture)
1449 EINA_SAFETY_ON_NULL_RETURN(gesture);
1450 if (!gesture->data) return;
1452 memset(gesture->data, 0, sizeof(Momentum_Type));
1456 _line_data_reset(Line_Data *st)
1461 memset(st, 0, sizeof(Line_Data));
1462 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1466 _line_test_reset(Gesture_Info *gesture)
1473 EINA_SAFETY_ON_NULL_RETURN(gesture);
1474 if (!gesture->data) return;
1479 EINA_LIST_FOREACH(list, l, t_line)
1482 eina_list_free(list);
1487 _zoom_test_reset(Gesture_Info *gesture)
1490 Evas_Modifier_Mask mask;
1492 EINA_SAFETY_ON_NULL_RETURN(gesture);
1493 if (!gesture->data) return;
1494 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1497 mask = evas_key_modifier_mask_get(
1498 evas_object_evas_get(sd->target), "Control");
1499 evas_object_key_ungrab(sd->target, "Control_L", mask, 0);
1500 evas_object_key_ungrab(sd->target, "Control_R", mask, 0);
1502 memset(st, 0, sizeof(Zoom_Type));
1503 st->zoom_distance_tolerance = sd->zoom_distance_tolerance;
1504 st->info.zoom = 1.0;
1508 _rotate_test_reset(Gesture_Info *gesture)
1512 EINA_SAFETY_ON_NULL_RETURN(gesture);
1513 if (!gesture->data) return;
1515 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1518 memset(st, 0, sizeof(Rotate_Type));
1519 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1520 st->rotate_angular_tolerance = sd->rotate_angular_tolerance;
1524 _match_fingers_compare(const void *data1,
1527 /* Compare coords of first item in list to cur coords */
1528 const Pointer_Event *pe1 = eina_list_data_get(data1);
1529 const Pointer_Event *pe2 = data2;
1531 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1533 else if (pe1->x < pe2->x)
1537 if (pe1->x == pe2->x)
1538 return pe1->y - pe2->y;
1545 _pe_device_compare(const void *data1,
1548 /* Compare device of first item in list to our pe device */
1549 const Pointer_Event *pe1 = eina_list_data_get(data1);
1550 const Pointer_Event *pe2 = data2;
1552 /* Only match if last was a down event */
1553 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1554 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1557 if (pe1->device == pe2->device)
1559 else if (pe1->device < pe2->device)
1566 _pointer_event_record(Taps_Type *st,
1569 Elm_Gesture_Layer_Smart_Data *sd,
1571 Evas_Callback_Type event_type)
1573 /* Keep copy of pe and record it in list */
1574 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1576 memcpy(p, pe, sizeof(Pointer_Event));
1577 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1583 /* This will also update middle-point to report to user later */
1584 st->info.x = st->sum_x / st->n_taps;
1585 st->info.y = st->sum_y / st->n_taps;
1586 st->info.timestamp = pe->timestamp;
1590 pe_list = eina_list_append(pe_list, p);
1591 st->l = eina_list_append(st->l, pe_list);
1594 pe_list = eina_list_append(pe_list, p);
1602 * This function checks if the tap gesture is done.
1604 * @param data gesture info pointer
1605 * @return EINA_TRUE if it is done.
1607 * @ingroup Elm_Gesture_Layer
1610 _tap_gesture_check_finish(Gesture_Info *gesture)
1612 /* Here we check if taps-gesture was completed successfuly */
1613 /* Count how many taps were recieved on each device then */
1614 /* determine if it matches n_taps_needed defined on START */
1615 Taps_Type *st = gesture->data;
1619 if (!st->l) return EINA_FALSE;
1620 EINA_LIST_FOREACH(st->l, l, pe_list)
1622 /* No match taps number on device, ABORT */
1623 if (eina_list_count(pe_list) != st->n_taps_needed)
1635 * This function sets state a tap-gesture to END or ABORT
1637 * @param data gesture info pointer
1639 * @ingroup Elm_Gesture_Layer
1642 _tap_gesture_finish(void *data)
1644 /* This function will test each tap gesture when timer expires */
1645 Elm_Gesture_State s = ELM_GESTURE_STATE_ABORT;
1646 Gesture_Info *gesture = data;
1647 Taps_Type *st = gesture->data;
1649 if (_tap_gesture_check_finish(gesture))
1651 s = ELM_GESTURE_STATE_END;
1654 st->info.n = eina_list_count(st->l);
1655 _state_set(gesture, s, gesture->info, EINA_FALSE);
1656 _tap_gestures_test_reset(gesture);
1662 * when this timer expires we finish tap gestures.
1664 * @param data The gesture-layer object.
1665 * @return cancles callback for this timer.
1667 * @ingroup Elm_Gesture_Layer
1670 _multi_tap_timeout(void *data)
1672 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1674 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1675 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TAPS]);
1677 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1678 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1680 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1681 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1683 _clear_if_finished(data);
1684 sd->gest_taps_timeout = NULL;
1686 return ECORE_CALLBACK_CANCEL;
1692 * when this timer expires we START long tap gesture
1694 * @param data The gesture-layer object.
1695 * @return cancles callback for this timer.
1697 * @ingroup Elm_Gesture_Layer
1700 _long_tap_timeout(void *data)
1702 Gesture_Info *gesture = data;
1704 _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1705 gesture->data, EINA_TRUE);
1707 return ECORE_CALLBACK_RENEW;
1713 * This function checks the state of a tap gesture.
1715 * @param sd Gesture Layer Widget Data.
1716 * @param pe The recent input event as stored in pe struct.
1717 * @param event_info Original input event pointer.
1718 * @param event_type Type of original input event.
1719 * @param gesture what gesture is tested
1720 * @param how many taps for this gesture (1, 2 or 3)
1722 * @ingroup Elm_Gesture_Layer
1725 _tap_gesture_test(Evas_Object *obj,
1728 Evas_Callback_Type event_type,
1729 Elm_Gesture_Type g_type)
1733 Gesture_Info *gesture;
1734 Eina_List *pe_list = NULL;
1735 Pointer_Event *pe_down = NULL;
1736 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1738 /* Here we fill Tap struct */
1739 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1744 gesture = sd->gesture[g_type];
1745 if (!gesture) return;
1749 case ELM_GESTURE_N_TAPS:
1753 case ELM_GESTURE_N_DOUBLE_TAPS:
1757 case ELM_GESTURE_N_TRIPLE_TAPS:
1767 if (!st) /* Allocated once on first time */
1769 st = calloc(1, sizeof(Taps_Type));
1771 _tap_gestures_test_reset(gesture);
1774 switch (pe->event_type)
1776 case EVAS_CALLBACK_MULTI_DOWN:
1777 case EVAS_CALLBACK_MOUSE_DOWN:
1778 /* Check if got tap on same cord was tapped before */
1779 pe_list = eina_list_search_unsorted(st->l, _match_fingers_compare, pe);
1782 /* This device was touched in other cord before completion */
1783 eina_list_search_unsorted(st->l, _pe_device_compare, pe))
1785 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1786 &st->info, EINA_FALSE);
1787 _event_consume(sd, event_info, event_type, ev_flag);
1792 pe_list = _pointer_event_record
1793 (st, pe_list, pe, sd, event_info, event_type);
1794 if (!sd->gest_taps_timeout)
1796 if (sd->double_tap_timeout > 0.0)
1798 sd->gest_taps_timeout =
1799 ecore_timer_add(sd->double_tap_timeout,
1800 _multi_tap_timeout, gesture->obj);
1804 ecore_timer_reset(sd->gest_taps_timeout);
1806 /* This is the first mouse down we got */
1807 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1809 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
1810 &st->info, EINA_FALSE);
1811 _event_consume(sd, event_info, event_type, ev_flag);
1813 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1817 else if (eina_list_count(pe_list) > st->n_taps_needed)
1818 /* If we arleady got too many touches for this gesture. */
1819 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1820 &st->info, EINA_FALSE);
1824 case EVAS_CALLBACK_MULTI_UP:
1825 case EVAS_CALLBACK_MOUSE_UP:
1826 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1827 if (!pe_list) return;
1829 pe_list = _pointer_event_record
1830 (st, pe_list, pe, sd, event_info, event_type);
1832 if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1833 !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1834 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1835 ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1836 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1838 if (_tap_gesture_check_finish(gesture))
1840 _tap_gesture_finish(gesture);
1847 case EVAS_CALLBACK_MULTI_MOVE:
1848 case EVAS_CALLBACK_MOUSE_MOVE:
1849 /* Get first event in first list, this has to be a Mouse Down event */
1850 /* and verify that user didn't move out of this area before next tap */
1851 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1854 pe_down = eina_list_data_get(pe_list);
1855 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1857 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1858 &st->info, EINA_FALSE);
1859 _event_consume(sd, event_info, event_type, ev_flag);
1872 * This function computes center-point for long-tap gesture
1874 * @param st Long Tap gesture info pointer
1875 * @param pe The recent input event as stored in pe struct.
1877 * @ingroup Elm_Gesture_Layer
1880 _compute_taps_center(Long_Tap_Type *st,
1887 Evas_Coord x = 0, y = 0;
1889 if (!eina_list_count(st->touched))
1892 EINA_LIST_FOREACH(st->touched, l, p)
1893 { /* Accumulate all then take avarage */
1894 if (p->device == pe->device) /* This will take care of values
1895 * coming from MOVE event */
1907 *x_out = x / eina_list_count(st->touched);
1908 *y_out = y / eina_list_count(st->touched);
1914 * This function checks N long-tap gesture.
1916 * @param obj The gesture-layer object.
1917 * @param pe The recent input event as stored in pe struct.
1918 * @param event_info Original input event pointer.
1919 * @param event_type Type of original input event.
1920 * @param g_type what Gesture we are testing.
1921 * @param taps How many click/taps we test for.
1923 * @ingroup Elm_Gesture_Layer
1926 _n_long_tap_test(Evas_Object *obj,
1929 Evas_Callback_Type event_type,
1930 Elm_Gesture_Type g_type)
1932 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1933 Gesture_Info *gesture;
1936 /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1937 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1939 if (!pe) /* this happens when unhandled event arrived */
1940 return; /* see _make_pointer_event function */
1942 gesture = sd->gesture[g_type];
1943 if (!gesture) return;
1946 if (!st) /* Allocated once on first time */
1948 st = calloc(1, sizeof(Long_Tap_Type));
1950 _n_long_tap_test_reset(gesture);
1953 switch (pe->event_type)
1955 case EVAS_CALLBACK_MULTI_DOWN:
1956 case EVAS_CALLBACK_MOUSE_DOWN:
1957 st->touched = _touched_device_add(st->touched, pe);
1958 st->info.n = eina_list_count(st->touched);
1960 /* This is the first mouse down we got */
1961 if (eina_list_count(st->touched) == 1)
1963 _state_set(gesture, ELM_GESTURE_STATE_START,
1964 gesture->data, EINA_FALSE);
1965 st->info.timestamp = pe->timestamp;
1967 /* To test long tap */
1968 /* When this timer expires, gesture STARTED */
1969 if ((!st->timeout) && (sd->long_tap_start_timeout > 0.0))
1970 st->timeout = ecore_timer_add(sd->long_tap_start_timeout,
1971 _long_tap_timeout, gesture);
1976 ecore_timer_reset(st->timeout);
1980 _event_consume(sd, event_info, event_type, ev_flag);
1981 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1982 st->center_x = st->info.x;
1983 st->center_y = st->info.y;
1986 case EVAS_CALLBACK_MULTI_UP:
1987 case EVAS_CALLBACK_MOUSE_UP:
1988 st->touched = _touched_device_remove(st->touched, pe);
1989 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1992 if (gesture->state == ELM_GESTURE_STATE_MOVE)
1993 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
1994 &st->info, EINA_FALSE);
1996 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1997 &st->info, EINA_FALSE);
2001 ecore_timer_del(st->timeout);
2004 _event_consume(sd, event_info, event_type, ev_flag);
2009 case EVAS_CALLBACK_MULTI_MOVE:
2010 case EVAS_CALLBACK_MOUSE_MOVE:
2012 ((gesture->state == ELM_GESTURE_STATE_START) ||
2013 /* Report MOVE only if STARTED */
2014 (gesture->state == ELM_GESTURE_STATE_MOVE)))
2019 _compute_taps_center(st, &x, &y, pe);
2020 /* ABORT if user moved fingers out of tap area */
2021 if (!_inside(x, y, st->center_x, st->center_y))
2025 ecore_timer_del(st->timeout);
2029 /* Report MOVE if gesture started */
2030 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2031 &st->info, EINA_FALSE);
2034 _event_consume(sd, event_info, event_type, ev_flag);
2046 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
2047 * This momentum value will be sent to widget when gesture is completed.
2049 * @param momentum pointer to buffer where we record momentum value.
2050 * @param x1 x coord where user started gesture.
2051 * @param y1 y coord where user started gesture.
2052 * @param x2 x coord where user completed gesture.
2053 * @param y2 y coord where user completed gesture.
2054 * @param t1x timestamp for X, when user started gesture.
2055 * @param t1y timestamp for Y, when user started gesture.
2056 * @param t2 timestamp when user completed gesture.
2058 * @ingroup Elm_Gesture_Layer
2061 _momentum_set(Elm_Gesture_Momentum_Info *momentum,
2070 Evas_Coord velx = 0, vely = 0, vel;
2071 Evas_Coord dx = xx2 - xx1;
2072 Evas_Coord dy = yy2 - yy1;
2077 velx = (dx * 1000) / dtx;
2080 vely = (dy * 1000) / dty;
2082 vel = sqrt((velx * velx) + (vely * vely));
2084 if ((_elm_config->thumbscroll_friction > 0.0) &&
2085 (vel > _elm_config->thumbscroll_momentum_threshold)) /* report
2088 momentum->mx = velx;
2089 momentum->my = vely;
2101 * This function is used for computing rotation angle (DEG).
2103 * @param x1 first finger x location.
2104 * @param y1 first finger y location.
2105 * @param x2 second finger x location.
2106 * @param y2 second finger y location.
2108 * @return angle of the line between (x1,y1), (x2,y2) in Deg.
2109 * Angles now are given in DEG, not RAD.
2110 * ZERO angle at 12-oclock, growing clockwise.
2112 * @ingroup Elm_Gesture_Layer
2115 _angle_get(Evas_Coord xx1,
2120 double a, xx, yy, rt = (-1);
2122 xx = fabs(xx2 - xx1);
2123 yy = fabs(yy2 - yy1);
2125 if (((int)xx) && ((int)yy))
2127 rt = a = RAD2DEG(atan(yy / xx));
2130 if (yy1 < yy2) rt = 360 - a;
2135 if (yy1 < yy2) rt = 180 + a;
2140 if (rt < 0) /* Do this only if rt is not set */
2142 if (((int)xx)) /* Horizontal line */
2144 if (xx2 < xx1) rt = 180;
2148 { /* Vertical line */
2149 if (yy2 < yy1) rt = 90;
2154 /* Now we want to change from:
2156 * original circle 180 0 We want: 270 90
2160 if (rt >= 360) rt -= 360;
2168 * This function is used for computing the magnitude and direction
2169 * of vector between two points.
2171 * @param x1 first finger x location.
2172 * @param y1 first finger y location.
2173 * @param x2 second finger x location.
2174 * @param y2 second finger y location.
2175 * @param l length computed (output)
2176 * @param a angle computed (output)
2178 * @ingroup Elm_Gesture_Layer
2181 _vector_get(Evas_Coord xx1,
2192 *l = (Evas_Coord)sqrt((xx * xx) + (yy * yy));
2193 *a = _angle_get(xx1, yy1, xx2, yy2);
2197 _direction_get(Evas_Coord xx1,
2200 if (xx2 < xx1) return -1;
2201 if (xx2 > xx1) return 1;
2209 * This function tests momentum gesture.
2210 * @param obj The gesture-layer object.
2211 * @param pe The recent input event as stored in pe struct.
2212 * @param event_info recent input event.
2213 * @param event_type recent event type.
2214 * @param g_type what Gesture we are testing.
2216 * @ingroup Elm_Gesture_Layer
2219 _momentum_test(Evas_Object *obj,
2222 Evas_Callback_Type event_type,
2223 Elm_Gesture_Type g_type)
2228 Gesture_Info *gesture;
2229 Pointer_Event pe_local;
2230 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2231 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
2232 unsigned int cnt = 1; /* We start counter counting current pe event */
2234 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2236 gesture = sd->gesture[g_type];
2237 if (!gesture) return;
2239 /* When continues enable = TRUE a gesture may START on MOVE event */
2240 /* We don't allow this to happen with the if-statement below. */
2241 /* When continues enable = FALSE a gesture may START on DOWN only */
2242 /* Therefor it would NOT start on MOVE event. */
2243 /* NOTE that touched list is updated AFTER this function returns */
2244 /* so (count == 0) when we get here on first touch on surface. */
2245 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2246 return; /* Got move on mouse-over move */
2249 if (!st) /* Allocated once on first time */
2251 st = calloc(1, sizeof(Momentum_Type));
2253 _momentum_test_reset(gesture);
2259 /* First make avarage of all touched devices to determine center point */
2260 pe_local = *pe; /* Copy pe event info to local */
2261 EINA_LIST_FOREACH(sd->touched, l, p)
2262 if (p->device != pe_local.device)
2269 /* Compute avarage to get center point */
2273 /* If user added finger - reset gesture */
2274 if ((st->info.n) && (st->info.n < cnt))
2275 state_to_report = ELM_GESTURE_STATE_ABORT;
2277 if (st->info.n < cnt)
2282 case EVAS_CALLBACK_MOUSE_DOWN:
2283 case EVAS_CALLBACK_MULTI_DOWN:
2284 case EVAS_CALLBACK_MOUSE_MOVE:
2285 case EVAS_CALLBACK_MULTI_MOVE:
2288 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2289 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2290 (sd->glayer_continues_enable)) /* start also on MOVE */
2291 { /* We start on MOVE when cont-enabled only */
2292 st->line_st.x = st->line_end.x = pe_local.x;
2293 st->line_st.y = st->line_end.y = pe_local.y;
2294 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
2295 st->xdir = st->ydir = 0;
2296 st->info.x2 = st->info.x1 = pe_local.x;
2297 st->info.y2 = st->info.y1 = pe_local.y;
2298 st->info.tx = st->info.ty = pe_local.timestamp;
2299 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
2300 &st->info, EINA_FALSE);
2301 _event_consume(sd, event_info, event_type, ev_flag);
2309 Eina_Bool force = EINA_TRUE; /* for move state */
2311 /* ABORT if got DOWN or MOVE event after UP+timeout */
2312 if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
2314 state_to_report = ELM_GESTURE_STATE_ABORT;
2318 /* We report state but don't compute momentum now */
2319 ev_flag = _state_set(gesture, state_to_report, &st->info,
2321 _event_consume(sd, event_info, event_type, ev_flag);
2322 return; /* Stop computing when user remove finger */
2325 /* Too long of a wait, reset all values */
2326 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2328 st->line_st.x = pe_local.x;
2329 st->line_st.y = pe_local.y;
2330 st->t_st_y = st->t_st_x = pe_local.timestamp;
2331 st->info.tx = st->t_st_x;
2332 st->info.ty = st->t_st_y;
2333 st->xdir = st->ydir = 0;
2339 xdir = _direction_get(st->line_end.x, pe_local.x);
2340 ydir = _direction_get(st->line_end.y, pe_local.y);
2341 if (xdir && (xdir != st->xdir))
2343 st->line_st.x = st->line_end.x;
2344 st->info.tx = st->t_st_x = st->t_end;
2348 if (ydir && (ydir != st->ydir))
2350 st->line_st.y = st->line_end.y;
2351 st->info.ty = st->t_st_y = st->t_end;
2356 st->info.x2 = st->line_end.x = pe_local.x;
2357 st->info.y2 = st->line_end.y = pe_local.y;
2358 st->t_end = pe_local.timestamp;
2359 _momentum_set(&st->info, st->line_st.x, st->line_st.y,
2360 pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2361 pe_local.timestamp);
2363 ev_flag = _state_set(gesture, state_to_report, &st->info,
2365 _event_consume(sd, event_info, event_type, ev_flag);
2368 case EVAS_CALLBACK_MOUSE_UP:
2369 case EVAS_CALLBACK_MULTI_UP:
2370 st->t_up = pe_local.timestamp; /* Record recent up event time */
2371 if ((cnt > 1) || /* Ignore if more fingers touch surface */
2372 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2375 /* Too long of a wait, reset all values */
2376 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2378 st->line_st.x = pe_local.x;
2379 st->line_st.y = pe_local.y;
2380 st->t_st_y = st->t_st_x = pe_local.timestamp;
2381 st->xdir = st->ydir = 0;
2384 st->info.x2 = pe_local.x;
2385 st->info.y2 = pe_local.y;
2386 st->line_end.x = pe_local.x;
2387 st->line_end.y = pe_local.y;
2388 st->t_end = pe_local.timestamp;
2390 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2391 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2392 state_to_report = ELM_GESTURE_STATE_END;
2394 state_to_report = ELM_GESTURE_STATE_ABORT;
2396 ev_flag = _state_set(gesture, state_to_report, &st->info,
2398 _event_consume(sd, event_info, event_type, ev_flag);
2407 _line_device_compare(const void *data1,
2410 /* Compare device component of line struct */
2411 const Line_Data *ln1 = data1;
2412 const int *device = data2;
2414 if (ln1->t_st) /* Compare only with lines that started */
2415 return ln1->device - (*device);
2423 * This function construct line struct from input.
2424 * @param info pointer to store line momentum.
2425 * @param st line info to store input data.
2426 * @param pe The recent input event as stored in pe struct.
2428 * @ingroup Elm_Gesture_Layer
2431 _single_line_process(Elm_Gesture_Line_Info *info,
2434 Evas_Callback_Type event_type)
2436 /* Record events and set momentum for line pointed by st */
2442 case EVAS_CALLBACK_MOUSE_DOWN:
2443 case EVAS_CALLBACK_MOUSE_MOVE:
2444 case EVAS_CALLBACK_MULTI_DOWN:
2445 case EVAS_CALLBACK_MULTI_MOVE:
2446 if (!st->t_st) /* This happens only when line starts */
2448 st->line_st.x = pe->x;
2449 st->line_st.y = pe->y;
2450 st->t_st = pe->timestamp;
2451 st->device = pe->device;
2452 info->momentum.x1 = pe->x;
2453 info->momentum.y1 = pe->y;
2454 info->momentum.tx = pe->timestamp;
2455 info->momentum.ty = pe->timestamp;
2462 case EVAS_CALLBACK_MOUSE_UP:
2463 case EVAS_CALLBACK_MULTI_UP:
2464 /* IGNORE if line info was cleared, like long press, move */
2468 st->line_end.x = pe->x;
2469 st->line_end.y = pe->y;
2470 st->t_end = pe->timestamp;
2479 _line_data_reset(st);
2483 info->momentum.x2 = pe->x;
2484 info->momentum.y2 = pe->y;
2485 _momentum_set(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2486 st->t_st, st->t_st, pe->timestamp);
2494 * This function test for (n) line gesture.
2495 * @param obj The gesture-layer object.
2496 * @param pe The recent input event as stored in pe struct.
2497 * @param event_info Original input event pointer.
2498 * @param event_type Type of original input event.
2499 * @param g_type what Gesture we are testing.
2501 * @ingroup Elm_Gesture_Layer
2504 _n_line_test(Evas_Object *obj,
2507 Evas_Callback_Type event_type,
2508 Elm_Gesture_Type g_type)
2513 Gesture_Info *gesture;
2514 Line_Data *line = NULL;
2519 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2521 gesture = sd->gesture[g_type];
2522 if (!gesture ) return;
2524 /* When continues enable = TRUE a gesture may START on MOVE event */
2525 /* We don't allow this to happen with the if-statement below. */
2526 /* When continues enable = FALSE a gesture may START on DOWN only */
2527 /* Therefor it would NOT start on MOVE event. */
2528 /* NOTE that touched list is updated AFTER this function returns */
2529 /* so (count == 0) when we get here on first touch on surface. */
2530 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2531 return; /* Got move on mouse-over move */
2536 st = calloc(1, sizeof(Line_Type));
2541 cnt = eina_list_count(list);
2543 if (cnt) /* list is not empty, locate this device on list */
2545 line = (Line_Data *)eina_list_search_unsorted
2546 (st->list, _line_device_compare, &pe->device);
2549 if (!line) /* List is empty or device not found, new line-struct on
2552 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2553 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2554 ((sd->glayer_continues_enable) && /* START on MOVE also */
2555 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2556 /* Allocate new item on START only */
2557 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2559 line = calloc(1, sizeof(Line_Data));
2560 _line_data_reset(line);
2561 list = eina_list_append(list, line);
2566 if (!line) /* This may happen on MOVE that comes before DOWN */
2567 return; /* No line-struct to work with, can't continue testing */
2569 /* update st with input */
2570 if (_single_line_process(&st->info, line, pe, event_type))
2571 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2573 /* Get direction and magnitude of the line */
2575 _vector_get(line->line_st.x, line->line_st.y, pe->x, pe->y,
2576 &line->line_length, &angle);
2578 /* These are used later to compare lines length */
2579 Evas_Coord shortest_line_len = line->line_length;
2580 Evas_Coord longest_line_len = line->line_length;
2581 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2583 /* Now update line-state */
2584 if (line->t_st) /* Analyze line only if line started */
2586 if (line->line_angle >= 0.0) /* if line direction was set, we
2587 * test if broke tolerance */
2589 double a = fabs(angle - line->line_angle);
2590 /* Distance from line */
2591 double d = (tan(DEG2RAD(a))) * line->line_length;
2592 /* Broke tolerance: abort line and start a new one */
2593 if ((d > sd->line_distance_tolerance) ||
2594 (a > sd->line_angular_tolerance))
2596 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2597 &st->info, EINA_FALSE);
2598 _event_consume(sd, event_info, event_type, ev_flag);
2602 /* We may finish line if momentum is zero */
2603 if (sd->glayer_continues_enable)
2605 /* This is for continues-gesture */
2606 /* Finish line on zero momentum for continues gesture */
2607 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2609 line->line_end.x = pe->x;
2610 line->line_end.y = pe->y;
2611 line->t_end = pe->timestamp;
2616 { /* Record the line angle as it broke minimum length for line */
2617 if (line->line_length >= sd->line_min_length)
2618 st->info.angle = line->line_angle = angle;
2623 if (line->line_angle < 0.0) /* it's not a line, too short
2624 * more close to a tap */
2626 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2627 &st->info, EINA_FALSE);
2628 _event_consume(sd, event_info, event_type, ev_flag);
2634 /* Count how many lines already started / ended */
2637 unsigned int tm_start = pe->timestamp;
2638 unsigned int tm_end = pe->timestamp;
2641 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2642 Eina_Bool lines_parallel = EINA_TRUE;
2643 EINA_LIST_FOREACH(list, l, t_line)
2646 base_angle = t_line->line_angle;
2649 if (t_line->line_angle >= 0) /* Compare angle only with
2650 * lines with direction
2653 if (fabs(base_angle - t_line->line_angle) >
2654 sd->line_angular_tolerance)
2655 lines_parallel = EINA_FALSE;
2659 if (t_line->line_length) /* update only if this line is used */
2661 if (shortest_line_len > t_line->line_length)
2662 shortest_line_len = t_line->line_length;
2664 if (longest_line_len < t_line->line_length)
2665 longest_line_len = t_line->line_length;
2671 if (t_line->t_st < tm_start)
2672 tm_start = t_line->t_st;
2678 if (t_line->t_end < tm_end)
2679 tm_end = t_line->t_end;
2683 st->info.momentum.n = started;
2686 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2687 /* user lift one finger then starts again without line-end - ABORT */
2688 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2690 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2692 _event_consume(sd, event_info, event_type, ev_flag);
2696 if (!lines_parallel) /* Lines are NOT at same direction, abort this
2699 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2701 _event_consume(sd, event_info, event_type, ev_flag);
2705 /* We report ABORT if lines length are NOT matching when fingers are up */
2706 if ((longest_line_len - shortest_line_len) >
2707 (elm_config_finger_size_get() * 2))
2709 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2711 _event_consume(sd, event_info, event_type, ev_flag);
2715 /* We consider FLICK as a fast line.ABORT if take too long to finish */
2716 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) >
2717 sd->flick_time_limit_ms))
2719 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2721 _event_consume(sd, event_info, event_type, ev_flag);
2727 case EVAS_CALLBACK_MOUSE_UP:
2728 case EVAS_CALLBACK_MULTI_UP:
2729 if ((started) && (started == ended))
2731 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2732 &st->info, EINA_FALSE);
2733 _event_consume(sd, event_info, event_type, ev_flag);
2738 case EVAS_CALLBACK_MOUSE_DOWN:
2739 case EVAS_CALLBACK_MULTI_DOWN:
2740 case EVAS_CALLBACK_MOUSE_MOVE:
2741 case EVAS_CALLBACK_MULTI_MOVE:
2744 /* For continues gesture */
2745 if (sd->glayer_continues_enable && (started == ended))
2747 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2748 &st->info, EINA_FALSE);
2749 _event_consume(sd, event_info, event_type, ev_flag);
2752 { /* When continues, may START on MOVE event too */
2753 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2755 /* This happens when: on n > 1 lines then one finger up */
2756 /* caused abort, then put finger down. */
2757 /* This will stop line from starting again. */
2758 /* Number of lines, MUST match touched-device in list */
2759 if ((!sd->glayer_continues_enable) &&
2760 (eina_list_count(st->list) <
2761 eina_list_count(sd->touched)))
2762 s = ELM_GESTURE_STATE_ABORT;
2764 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2765 s = ELM_GESTURE_STATE_START;
2767 ev_flag = _state_set(gesture, s, &st->info, EINA_TRUE);
2768 _event_consume(sd, event_info, event_type, ev_flag);
2774 return; /* Unhandeld event type */
2781 * This function is used to check if rotation gesture started.
2782 * @param st Contains current rotation values from user input.
2783 * @return TRUE/FALSE if we need to set rotation START.
2785 * @ingroup Elm_Gesture_Layer
2788 _on_rotation_broke_tolerance(Rotate_Type *st)
2790 if (st->info.base_angle < 0)
2791 return EINA_FALSE; /* Angle has to be computed first */
2793 if (st->rotate_angular_tolerance < 0)
2796 double low = st->info.base_angle - st->rotate_angular_tolerance;
2797 double high = st->info.base_angle + st->rotate_angular_tolerance;
2798 double t = st->info.angle;
2822 if ((t < low) || (t > high)) /* This marks that roation action has
2825 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2826 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2836 * This function is used for computing the gap between fingers.
2837 * It returns the length and center point between fingers.
2839 * @param x1 first finger x location.
2840 * @param y1 first finger y location.
2841 * @param x2 second finger x location.
2842 * @param y2 second finger y location.
2843 * @param x Gets center point x cord (output)
2844 * @param y Gets center point y cord (output)
2846 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2848 * @ingroup Elm_Gesture_Layer
2851 _finger_gap_length_get(Evas_Coord xx1,
2858 double a, b, xx, yy, gap;
2859 xx = fabs(xx2 - xx1);
2860 yy = fabs(yy2 - yy1);
2861 gap = sqrt((xx * xx) + (yy * yy));
2863 /* START - Compute zoom center point */
2864 /* The triangle defined as follows:
2872 * http://en.wikipedia.org/wiki/Trigonometric_functions
2873 *************************************/
2874 if (((int)xx) && ((int)yy))
2876 double A = atan((yy / xx));
2877 a = (Evas_Coord)((gap / 2) * sin(A));
2878 b = (Evas_Coord)((gap / 2) * cos(A));
2879 *x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
2880 *y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
2884 if ((int)xx) /* horiz line, take half width */
2886 *x = (Evas_Coord)((xx1 + xx2) / 2);
2887 *y = (Evas_Coord)(yy1);
2890 if ((int)yy) /* vert line, take half width */
2892 *x = (Evas_Coord)(xx1);
2893 *y = (Evas_Coord)((yy1 + yy2) / 2);
2896 /* END - Compute zoom center point */
2898 return (Evas_Coord)gap;
2904 * This function is used for computing zoom value.
2906 * @param st Pointer to zoom data based on user input.
2907 * @param tm_end Recent input event timestamp.
2908 * @param zoom_val Current computed zoom value.
2910 * @return zoom momentum
2912 * @ingroup Elm_Gesture_Layer
2915 _zoom_momentum_get(Zoom_Type *st,
2916 unsigned int tm_end,
2919 unsigned int tm_total;
2920 if (!st->m_st_tm) /* Init, and we don't start computing momentum yet */
2922 st->m_st_tm = st->m_prev_tm = tm_end;
2923 st->m_base = zoom_val;
2927 if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
2928 return 0.0; /* we don't start to compute momentum yet */
2930 if (st->dir) /* if direction was already defined, check if changed */
2932 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2933 /* Direction changed, reset momentum */
2934 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2937 st->dir = (-st->dir);
2942 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2944 if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
2946 st->m_st_tm = 0; /* Rest momentum when waiting too long */
2950 st->m_prev_tm = tm_end;
2951 tm_total = tm_end - st->m_st_tm;
2954 return ((zoom_val - st->m_base) * 1000) / tm_total;
2962 * This function is used for computing zoom value.
2964 * @param st Pointer to zoom data based on user input.
2965 * @param x1 first finger x location.
2966 * @param y1 first finger y location.
2967 * @param x2 second finger x location.
2968 * @param y2 second finger y location.
2969 * @param factor zoom-factor, used to determine how fast zoom works.
2971 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2973 * @ingroup Elm_Gesture_Layer
2976 _zoom_compute(Zoom_Type *st,
2981 double zoom_finger_factor)
2984 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2985 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2987 Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
2988 &st->info.x, &st->info.y);
2990 st->info.radius = diam / 2;
2994 st->zoom_base = diam;
2995 return st->info.zoom;
2998 if (st->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
2999 * zoom action NOT started yet */
3001 /* avoid jump with zoom value when break tolerance */
3002 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
3004 st->zoom_base -= st->zoom_distance_tolerance;
3005 st->zoom_distance_tolerance = 0;
3008 /* avoid jump with zoom value when break tolerance */
3009 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
3011 st->zoom_base += st->zoom_distance_tolerance;
3012 st->zoom_distance_tolerance = 0;
3018 /* We use factor only on the difference between gap-base */
3019 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
3020 rt = ((1.0) + ((((float)diam - (float)st->zoom_base) /
3021 (float)st->zoom_base) * zoom_finger_factor));
3023 /* Momentum: zoom per second: */
3024 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
3032 * This function handles zoom with mouse wheel.
3033 * thats a combination of wheel + CTRL key.
3034 * @param obj The gesture-layer object.
3035 * @param event_info Original input event pointer.
3036 * @param event_type Type of original input event.
3037 * @param g_type what Gesture we are testing.
3039 * @ingroup Elm_Gesture_Layer
3042 _zoom_with_wheel_test(Evas_Object *obj,
3044 Evas_Callback_Type event_type,
3045 Elm_Gesture_Type g_type)
3047 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3049 if (!sd->gesture[g_type]) return;
3051 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3052 Zoom_Type *st = gesture_zoom->data;
3053 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3054 if (!st) /* Allocated once on first time, used for zoom intermediate data */
3056 st = calloc(1, sizeof(Zoom_Type));
3057 gesture_zoom->data = st;
3058 _zoom_test_reset(gesture_zoom);
3063 case EVAS_CALLBACK_KEY_UP:
3065 Evas_Event_Key_Up *p = event_info;
3066 if ((!strcmp(p->keyname, "Control_L")) ||
3067 /* Test if we ended a zoom gesture when releasing CTRL */
3068 (!strcmp(p->keyname, "Control_R")))
3070 if ((st->zoom_wheel) &&
3071 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3072 /* User released CTRL after zooming */
3073 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3075 st->info.momentum = _zoom_momentum_get
3076 (st, p->timestamp, st->info.zoom);
3078 ev_flag = _state_set
3079 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3081 _event_consume(sd, event_info, event_type, ev_flag);
3089 case EVAS_CALLBACK_MOUSE_WHEEL:
3092 Elm_Gesture_State s;
3093 if (!evas_key_modifier_is_set(
3094 ((Evas_Event_Mouse_Wheel *)event_info)->modifiers,
3095 "Control")) /* if using wheel witout CTRL after starting zoom */
3097 if ((st->zoom_wheel) &&
3098 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3099 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3101 ev_flag = _state_set
3102 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3104 _event_consume(sd, event_info, event_type, ev_flag);
3109 return; /* Ignore mouse-wheel without control */
3112 /* Using mouse wheel with CTRL for zoom */
3113 /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0) we
3114 * continue a zoom gesture */
3115 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
3118 s = ELM_GESTURE_STATE_MOVE;
3121 { /* On first wheel event, report START */
3122 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
3123 evas_object_evas_get(sd->target), "Control");
3125 s = ELM_GESTURE_STATE_START;
3126 if (!evas_object_key_grab
3127 (sd->target, "Control_L", mask, 0, EINA_FALSE))
3128 ERR("Failed to Grabbed CTRL_L");
3129 if (!evas_object_key_grab
3130 (sd->target, "Control_R", mask, 0, EINA_FALSE))
3131 ERR("Failed to Grabbed CTRL_R");
3134 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
3135 st->zoom_wheel = (Evas_Event_Mouse_Wheel *)event_info;
3136 st->info.x = st->zoom_wheel->canvas.x;
3137 st->info.y = st->zoom_wheel->canvas.y;
3139 if (st->zoom_wheel->z < 0) /* zoom in */
3140 st->info.zoom += (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3142 if (st->zoom_wheel->z > 0) /* zoom out */
3143 st->info.zoom -= (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3145 if (st->info.zoom < 0.0)
3146 st->info.zoom = 0.0;
3148 st->info.momentum = _zoom_momentum_get
3149 (st, st->zoom_wheel->timestamp, st->info.zoom);
3151 ev_flag = _state_set(gesture_zoom, s, &st->info, force);
3152 _event_consume(sd, event_info, event_type, ev_flag);
3164 * This function is used to test zoom gesture.
3165 * user may combine zoom, rotation together.
3166 * so its possible that both will be detected from input.
3167 * (both are two-finger movement-oriented gestures)
3169 * @param obj The gesture-layer object.
3170 * @param event_info Pointer to recent input event.
3171 * @param event_type Recent input event type.
3172 * @param g_type what Gesture we are testing.
3174 * @ingroup Elm_Gesture_Layer
3177 _zoom_test(Evas_Object *obj,
3180 Evas_Callback_Type event_type,
3181 Elm_Gesture_Type g_type)
3183 /* Test for wheel zoom. */
3184 _zoom_with_wheel_test(obj, event_info, event_type, ELM_GESTURE_ZOOM);
3186 if (!_elm_config->glayer_zoom_finger_enable)
3191 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3193 if (!sd->gesture[g_type]) return;
3195 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3196 Zoom_Type *st = gesture_zoom->data;
3198 if (!st) /* Allocated once on first time, used for zoom data */
3200 st = calloc(1, sizeof(Zoom_Type));
3201 gesture_zoom->data = st;
3202 _zoom_test_reset(gesture_zoom);
3205 /* Start - new zoom testing, letting all fingers start */
3206 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3209 case EVAS_CALLBACK_MOUSE_MOVE:
3210 case EVAS_CALLBACK_MULTI_MOVE:
3211 /* if non-continues mode and gesture NOT started, ignore MOVE */
3212 if ((!sd->glayer_continues_enable) &&
3213 (!st->zoom_st.timestamp))
3216 case EVAS_CALLBACK_MOUSE_DOWN:
3217 case EVAS_CALLBACK_MULTI_DOWN:
3218 { /* Here we take care of zoom-start and zoom move */
3222 if (eina_list_count(sd->touched) > 2) /* Process zoom only
3226 ev_flag = _state_set
3227 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3229 _event_consume(sd, event_info, event_type, ev_flag);
3234 if (!st->zoom_st.timestamp) /* Now scan touched-devices list
3235 * and find other finger */
3237 EINA_LIST_FOREACH(sd->touched, l, p)
3238 { /* Device of other finger <> pe device */
3239 if (p->device != pe->device)
3243 if (!p) /* Single finger on touch */
3246 /* Record down fingers */
3247 _event_consume(sd, event_info, event_type, ev_flag);
3248 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
3249 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
3251 /* Set mv field as well to be ready for MOVE events */
3252 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3253 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
3255 /* Here we have zoom_st, zoom_st1 set, report START */
3256 /* Set zoom-base after BOTH down events recorded */
3257 /* Compute length of line between fingers zoom start */
3258 st->info.zoom = 1.0;
3259 st->zoom_base = _finger_gap_length_get
3260 (st->zoom_st1.x, st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
3261 &st->info.x, &st->info.y);
3263 st->info.radius = st->zoom_base / 2;
3265 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
3266 /* zoom started with mouse-wheel, don't report twice */
3267 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
3269 ev_flag = _state_set
3270 (gesture_zoom, ELM_GESTURE_STATE_START, &st->info,
3272 _event_consume(sd, event_info, event_type, ev_flag);
3275 return; /* Zoom started */
3276 } /* End of ZOOM_START handling */
3278 /* if we got here, we have (exacally) two fingers on surfce */
3279 /* we also after START, report MOVE */
3280 /* First detect which finger moved */
3281 if (pe->device == st->zoom_mv.device)
3282 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3283 else if (pe->device == st->zoom_mv1.device)
3284 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
3286 /* Compute change in zoom as fingers move */
3287 st->info.zoom = _zoom_compute(st,
3288 st->zoom_mv.x, st->zoom_mv.y,
3289 st->zoom_mv1.x, st->zoom_mv1.y,
3290 sd->zoom_finger_factor);
3292 if (!st->zoom_distance_tolerance) /* Zoom broke tolerance,
3295 double d = st->info.zoom - st->next_step;
3299 if (d >= sd->zoom_step) /* Report move in steps */
3301 st->next_step = st->info.zoom;
3303 ev_flag = _state_set(gesture_zoom,
3304 ELM_GESTURE_STATE_MOVE,
3305 &st->info, EINA_TRUE);
3306 _event_consume(sd, event_info, event_type, ev_flag);
3308 } /* End of ZOOM_MOVE handling */
3313 case EVAS_CALLBACK_MOUSE_UP:
3314 case EVAS_CALLBACK_MULTI_UP:
3315 /* Reset timestamp of finger-up.This is used later
3316 by _zoom_test_reset() to retain finger-down data */
3317 _event_consume(sd, event_info, event_type, ev_flag);
3318 if (((st->zoom_wheel) || (st->zoom_base)) &&
3319 (st->zoom_distance_tolerance == 0))
3321 ev_flag = _state_set(gesture_zoom, ELM_GESTURE_STATE_END,
3322 &st->info, EINA_FALSE);
3323 _event_consume(sd, event_info, event_type, ev_flag);
3328 /* if we got here not a ZOOM */
3329 /* Must be != undefined, if gesture started */
3330 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
3332 ev_flag = _state_set
3333 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3335 _event_consume(sd, event_info, event_type, ev_flag);
3338 _zoom_test_reset(gesture_zoom);
3348 _rotate_properties_get(Rotate_Type *st,
3355 /* FIXME: Fix momentum computation, it's wrong */
3356 double prev_angle = *angle;
3358 st->info.radius = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3359 &st->info.x, &st->info.y) / 2;
3361 *angle = _angle_get(xx1, yy1, xx2, yy2);
3363 if (angle == &st->info.angle) /* Fingers are moving, compute momentum */
3365 unsigned int tm_start =
3366 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3367 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
3368 unsigned int tm_end =
3369 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3370 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3372 unsigned int tm_total = tm_end - tm_start;
3373 if (tm_total) /* Momentum computed as:
3374 accumulated roation angle (deg) divided by time */
3377 if (((prev_angle < 90) && ((*angle) > 270)) ||
3378 /* We circle passing ZERO point */
3379 ((prev_angle > 270) && ((*angle) < 90)))
3381 prev_angle = (*angle);
3383 else m = prev_angle - (*angle);
3385 st->accum_momentum += m;
3387 if ((tm_end - st->prev_momentum_tm) < 100)
3388 st->prev_momentum += m;
3391 if (fabs(st->prev_momentum) < 0.002)
3392 st->accum_momentum = 0.0; /* reset momentum */
3394 st->prev_momentum = 0.0; /* Start again */
3397 st->prev_momentum_tm = tm_end;
3398 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3402 st->info.momentum = 0;
3408 * This function is used to test rotation gesture.
3409 * user may combine zoom, rotation together.
3410 * so its possible that both will be detected from input.
3411 * (both are two-finger movement-oriented gestures)
3413 * @param obj The gesture-layer object.
3414 * @param event_info Pointer to recent input event.
3415 * @param event_type Recent input event type.
3416 * @param g_type what Gesture we are testing.
3418 * @ingroup Elm_Gesture_Layer
3421 _rotate_test(Evas_Object *obj,
3424 Evas_Callback_Type event_type,
3425 Elm_Gesture_Type g_type)
3427 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3428 Gesture_Info *gesture;
3429 Rotate_Type *st = NULL;
3431 if (!_elm_config->glayer_rotate_finger_enable)
3437 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3439 if (!sd->gesture[g_type]) return;
3441 gesture = sd->gesture[g_type];
3443 if (!gesture) return ;
3446 if (!st) /* Allocated once on first time */
3448 st = calloc(1, sizeof(Rotate_Type));
3450 _rotate_test_reset(gesture);
3455 case EVAS_CALLBACK_MOUSE_MOVE:
3456 case EVAS_CALLBACK_MULTI_MOVE:
3457 /* if non-continues mode and gesture NOT started, ignore MOVE */
3458 if ((!sd->glayer_continues_enable) &&
3459 (!st->rotate_st.timestamp))
3462 case EVAS_CALLBACK_MOUSE_DOWN:
3463 case EVAS_CALLBACK_MULTI_DOWN:
3464 { /* Here we take care of rotate-start and rotate move */
3468 if (eina_list_count(sd->touched) > 2) /* Process rotate only
3472 ev_flag = _state_set
3473 (gesture, ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3474 _event_consume(sd, event_info, event_type, ev_flag);
3479 if (!st->rotate_st.timestamp) /* Now scan touched-devices list
3480 * and find other finger */
3482 EINA_LIST_FOREACH(sd->touched, l, p)
3483 { /* Device of other finger <> pe device */
3484 if (p->device != pe->device)
3489 return; /* Single finger on touch */
3491 /* Record down fingers */
3492 _event_consume(sd, event_info, event_type, ev_flag);
3493 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3494 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3496 /* Set mv field as well to be ready for MOVE events */
3497 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3498 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3500 /* Here we have rotate_st, rotate_st1 set, report START */
3501 /* Set rotate-base after BOTH down events recorded */
3502 /* Compute length of line between fingers rotate start */
3503 _rotate_properties_get(st,
3504 st->rotate_st.x, st->rotate_st.y,
3505 st->rotate_st1.x, st->rotate_st1.y,
3506 &st->info.base_angle);
3508 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
3509 &st->info, EINA_FALSE);
3510 _event_consume(sd, event_info, event_type, ev_flag);
3512 return; /* Rotate started */
3513 } /* End of ROTATE_START handling */
3515 /* if we got here, we have (exacally) two fingers on surfce */
3516 /* we also after START, report MOVE */
3517 /* First detect which finger moved */
3518 if (pe->device == st->rotate_mv.device)
3519 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3520 else if (pe->device == st->rotate_mv1.device)
3521 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3523 /* Compute change in rotate as fingers move */
3524 _rotate_properties_get(st,
3525 st->rotate_mv.x, st->rotate_mv.y,
3526 st->rotate_mv1.x, st->rotate_mv1.y,
3529 if (_on_rotation_broke_tolerance(st)) /* Rotation broke
3533 double d = st->info.angle - st->next_step;
3537 if (d >= sd->rotate_step) /* Report move in steps */
3539 st->next_step = st->info.angle;
3541 ev_flag = _state_set
3542 (gesture, ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3543 _event_consume(sd, event_info, event_type, ev_flag);
3545 } /* End of ROTATE_MOVE handling */
3550 case EVAS_CALLBACK_MOUSE_UP:
3551 case EVAS_CALLBACK_MULTI_UP:
3552 _event_consume(sd, event_info, event_type, ev_flag);
3553 /* Reset timestamp of finger-up.This is used later
3554 by rotate_test_reset() to retain finger-down data */
3555 if (st->rotate_angular_tolerance < 0)
3557 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
3558 &st->info, EINA_FALSE);
3559 _event_consume(sd, event_info, event_type, ev_flag);
3564 /* Must be != undefined, if gesture started */
3565 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3567 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
3568 &st->info, EINA_FALSE);
3569 _event_consume(sd, event_info, event_type, ev_flag);
3572 _rotate_test_reset(gesture);
3581 _elm_gesture_layer_smart_disable(Evas_Object *obj)
3583 if (elm_widget_disabled_get(obj))
3584 _callbacks_unregister(obj);
3586 _callbacks_register(obj);
3592 _elm_gesture_layer_smart_add(Evas_Object *obj)
3594 EVAS_SMART_DATA_ALLOC(obj, Elm_Gesture_Layer_Smart_Data);
3596 _elm_gesture_layer_parent_sc->base.add(obj);
3598 priv->target = NULL;
3599 priv->line_min_length =
3600 _elm_config->glayer_line_min_length * elm_config_finger_size_get();
3601 priv->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance
3602 * elm_config_finger_size_get();
3603 priv->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance
3604 * elm_config_finger_size_get();
3605 priv->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3606 /* mouse wheel zoom steps */
3607 priv->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor;
3608 priv->rotate_angular_tolerance =
3609 _elm_config->glayer_rotate_angular_tolerance;
3610 priv->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3611 priv->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3612 priv->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3613 priv->repeat_events = EINA_TRUE;
3614 priv->glayer_continues_enable = _elm_config->glayer_continues_enable;
3616 /* FIXME: Hack to get around old configs - if too small, enlarge. */
3617 if (_elm_config->glayer_double_tap_timeout < 0.00001)
3618 _elm_config->glayer_double_tap_timeout = 0.25;
3619 priv->double_tap_timeout = _elm_config->glayer_double_tap_timeout;
3621 memset(priv->gesture, 0, sizeof(priv->gesture));
3625 _elm_gesture_layer_smart_del(Evas_Object *obj)
3627 Pointer_Event *data;
3630 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3632 _event_history_clear(obj);
3633 eina_list_free(sd->pending);
3635 EINA_LIST_FREE (sd->touched, data)
3638 if (!elm_widget_disabled_get(obj))
3639 _callbacks_unregister(obj);
3641 /* Free all gestures internal data structures */
3642 for (i = 0; i < ELM_GESTURE_LAST; i++)
3645 if (sd->gesture[i]->data)
3646 free(sd->gesture[i]->data);
3648 free(sd->gesture[i]);
3650 if (sd->gest_taps_timeout)
3652 ecore_timer_del(sd->gest_taps_timeout);
3653 sd->gest_taps_timeout = NULL;
3656 _elm_gesture_layer_parent_sc->base.del(obj); /* handles freeing sd */
3660 _elm_gesture_layer_smart_set_user(Elm_Widget_Smart_Class *sc)
3662 sc->base.add = _elm_gesture_layer_smart_add;
3663 sc->base.del = _elm_gesture_layer_smart_del;
3665 sc->disable = _elm_gesture_layer_smart_disable;
3669 elm_gesture_layer_add(Evas_Object *parent)
3673 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3675 obj = elm_widget_add(_elm_gesture_layer_smart_class_new(), parent);
3676 if (!obj) return NULL;
3678 if (!elm_widget_sub_object_add(parent, obj))
3679 ERR("could not add %p as sub object of %p", obj, parent);
3685 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3687 ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3688 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3690 return !sd->repeat_events;
3694 elm_gesture_layer_hold_events_set(Evas_Object *obj,
3695 Eina_Bool hold_events)
3697 ELM_GESTURE_LAYER_CHECK(obj);
3698 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3700 sd->repeat_events = !(!!hold_events);
3704 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3706 ELM_GESTURE_LAYER_CHECK(obj) 0;
3707 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3709 return sd->zoom_step;
3713 elm_gesture_layer_zoom_step_set(Evas_Object *obj,
3716 ELM_GESTURE_LAYER_CHECK(obj);
3717 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3719 if (step < 0) return;
3721 sd->zoom_step = step;
3725 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3727 ELM_GESTURE_LAYER_CHECK(obj) 0;
3728 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3730 return sd->rotate_step;
3734 elm_gesture_layer_rotate_step_set(Evas_Object *obj,
3737 ELM_GESTURE_LAYER_CHECK(obj);
3738 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3740 if (step < 0) return;
3742 sd->rotate_step = step;
3746 elm_gesture_layer_attach(Evas_Object *obj,
3747 Evas_Object *target)
3749 ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3750 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3752 if (!target) return EINA_FALSE;
3754 /* if was attached before, unregister callbacks first */
3756 _callbacks_unregister(obj);
3758 sd->target = target;
3760 _callbacks_register(obj);
3765 elm_gesture_layer_cb_set(Evas_Object *obj,
3766 Elm_Gesture_Type idx,
3767 Elm_Gesture_State cb_type,
3768 Elm_Gesture_Event_Cb cb,
3773 ELM_GESTURE_LAYER_CHECK(obj);
3774 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3776 if (!sd->gesture[idx])
3777 sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3778 if (!sd->gesture[idx]) return;
3780 p = sd->gesture[idx];
3783 p->fn[cb_type].cb = cb;
3784 p->fn[cb_type].user_data = data;
3785 p->state = ELM_GESTURE_STATE_UNDEFINED;
3791 elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length)
3793 ELM_GESTURE_LAYER_CHECK(obj);
3794 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3795 sd->line_min_length = line_min_length;
3800 elm_gesture_layer_line_min_length_get(const Evas_Object *obj)
3802 ELM_GESTURE_LAYER_CHECK(obj) 0;
3803 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3804 return sd->line_min_length;
3808 elm_gesture_layer_zoom_distance_tolerance_set(Evas_Object *obj, Evas_Coord zoom_distance_tolerance)
3810 ELM_GESTURE_LAYER_CHECK(obj);
3811 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3812 sd->zoom_distance_tolerance = zoom_distance_tolerance;
3816 elm_gesture_layer_zoom_distance_tolerance_get(const Evas_Object *obj)
3818 ELM_GESTURE_LAYER_CHECK(obj) 0;
3819 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3820 return sd->zoom_distance_tolerance;
3824 elm_gesture_layer_line_distance_tolerance_set(Evas_Object *obj, Evas_Coord line_distance_tolerance)
3826 ELM_GESTURE_LAYER_CHECK(obj);
3827 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3828 sd->line_distance_tolerance = line_distance_tolerance;
3832 elm_gesture_layer_line_distance_tolerance_get(const Evas_Object *obj)
3834 ELM_GESTURE_LAYER_CHECK(obj) 0;
3835 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3836 return sd->line_distance_tolerance;
3840 elm_gesture_layer_line_angular_tolerance_set(Evas_Object *obj, double line_angular_tolerance)
3842 ELM_GESTURE_LAYER_CHECK(obj);
3843 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3844 sd->line_angular_tolerance = line_angular_tolerance;
3848 elm_gesture_layer_line_angular_tolerance_get(const Evas_Object *obj)
3850 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3851 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3852 return sd->line_angular_tolerance;
3856 elm_gesture_layer_zoom_wheel_factor_set(Evas_Object *obj, double zoom_wheel_factor)
3858 ELM_GESTURE_LAYER_CHECK(obj);
3859 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3860 sd->zoom_wheel_factor = zoom_wheel_factor;
3864 elm_gesture_layer_zoom_wheel_factor_get(const Evas_Object *obj)
3866 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3867 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3868 return sd->zoom_wheel_factor;
3872 elm_gesture_layer_zoom_finger_factor_set(Evas_Object *obj, double zoom_finger_factor)
3874 ELM_GESTURE_LAYER_CHECK(obj);
3875 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3876 sd->zoom_finger_factor = zoom_finger_factor;
3880 elm_gesture_layer_zoom_finger_factor_get(const Evas_Object *obj)
3882 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3883 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3884 return sd->zoom_finger_factor;
3888 elm_gesture_layer_rotate_angular_tolerance_set(Evas_Object *obj, double rotate_angular_tolerance)
3890 ELM_GESTURE_LAYER_CHECK(obj);
3891 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3892 sd->rotate_angular_tolerance = rotate_angular_tolerance;
3896 elm_gesture_layer_rotate_angular_tolerance_get(const Evas_Object *obj)
3898 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3899 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3900 return sd->rotate_angular_tolerance;
3904 elm_gesture_layer_flick_time_limit_ms_set(Evas_Object *obj, unsigned int flick_time_limit_ms)
3906 ELM_GESTURE_LAYER_CHECK(obj);
3907 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3908 sd->flick_time_limit_ms = flick_time_limit_ms;
3912 elm_gesture_layer_flick_time_limit_ms_get(const Evas_Object *obj)
3914 ELM_GESTURE_LAYER_CHECK(obj) 0;
3915 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3916 return sd->flick_time_limit_ms;
3920 elm_gesture_layer_long_tap_start_timeout_set(Evas_Object *obj, double long_tap_start_timeout)
3922 ELM_GESTURE_LAYER_CHECK(obj);
3923 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3924 sd->long_tap_start_timeout = long_tap_start_timeout;
3928 elm_gesture_layer_long_tap_start_timeout_get(const Evas_Object *obj)
3930 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3931 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3932 return sd->long_tap_start_timeout;
3936 elm_gesture_layer_continues_enable_set(Evas_Object *obj, Eina_Bool continues_enable)
3938 ELM_GESTURE_LAYER_CHECK(obj);
3939 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3940 sd->glayer_continues_enable = continues_enable;
3944 elm_gesture_layer_continues_enable_get(const Evas_Object *obj)
3946 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3947 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3948 return sd->glayer_continues_enable;
3952 elm_gesture_layer_double_tap_timeout_set(Evas_Object *obj, double double_tap_timeout)
3954 ELM_GESTURE_LAYER_CHECK(obj);
3955 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3956 sd->double_tap_timeout = double_tap_timeout;
3960 elm_gesture_layer_double_tap_timeout_get(const Evas_Object *obj)
3962 ELM_GESTURE_LAYER_CHECK(obj) 0.0;
3963 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3964 return sd->double_tap_timeout;