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;
379 Gesture_Info *gesture[ELM_GESTURE_LAST];
380 Eina_List *pending; /* List of devices need to refeed
382 Eina_List *touched; /* Information of touched devices */
385 Ecore_Timer *gest_taps_timeout; /* When this expires, dbl
386 * click/taps ABORTed */
388 Eina_Bool repeat_events : 1;
391 /* START - Functions to manage touched-device list */
394 * This function is used to find if device is touched
396 * @ingroup Elm_Gesture_Layer
399 _device_compare(const void *data1,
402 /* Compare the two device numbers */
403 return ((Pointer_Event *)data1)->device - ((Pointer_Event *)data2)->device;
409 * Remove Pointer Event from touched device list
410 * @param list Pointer to touched device list.
411 * @param Pointer_Event Pointer to PE.
413 * @ingroup Elm_Gesture_Layer
416 _touched_device_remove(Eina_List *list,
419 Eina_List *lst = NULL;
420 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
423 lst = eina_list_remove(list, p);
434 * Recoed Pointer Event in touched device list
435 * Note: This fuction allocates memory for PE event
436 * This memory is released in _touched_device_remove()
437 * @param list Pointer to touched device list.
438 * @param Pointer_Event Pointer to PE.
440 * @ingroup Elm_Gesture_Layer
443 _touched_device_add(Eina_List *list,
446 Pointer_Event *p = eina_list_search_unsorted(list, _device_compare, pe);
448 if (p) /* We like to track device touch-position, overwrite info */
450 memcpy(p, pe, sizeof(Pointer_Event));
454 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
455 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN)) /* Add touched
459 p = malloc(sizeof(Pointer_Event));
460 /* Freed in _touched_device_remove() */
461 memcpy(p, pe, sizeof(Pointer_Event));
462 return eina_list_append(list, p);
468 /* END - Functions to manage touched-device list */
474 * @param event_info pointer to event.
476 * @ingroup Elm_Gesture_Layer
478 static Evas_Event_Flags
479 _event_flag_get(void *event_info,
480 Evas_Callback_Type event_type)
484 case EVAS_CALLBACK_MOUSE_IN:
485 return ((Evas_Event_Mouse_In *)event_info)->event_flags;
487 case EVAS_CALLBACK_MOUSE_OUT:
488 return ((Evas_Event_Mouse_Out *)event_info)->event_flags;
490 case EVAS_CALLBACK_MOUSE_DOWN:
491 return ((Evas_Event_Mouse_Down *)event_info)->event_flags;
493 case EVAS_CALLBACK_MOUSE_MOVE:
494 return ((Evas_Event_Mouse_Move *)event_info)->event_flags;
496 case EVAS_CALLBACK_MOUSE_UP:
497 return ((Evas_Event_Mouse_Up *)event_info)->event_flags;
499 case EVAS_CALLBACK_MOUSE_WHEEL:
500 return ((Evas_Event_Mouse_Wheel *)event_info)->event_flags;
502 case EVAS_CALLBACK_MULTI_DOWN:
503 return ((Evas_Event_Multi_Down *)event_info)->event_flags;
505 case EVAS_CALLBACK_MULTI_MOVE:
506 return ((Evas_Event_Multi_Move *)event_info)->event_flags;
508 case EVAS_CALLBACK_MULTI_UP:
509 return ((Evas_Event_Multi_Up *)event_info)->event_flags;
511 case EVAS_CALLBACK_KEY_DOWN:
512 return ((Evas_Event_Key_Down *)event_info)->event_flags;
514 case EVAS_CALLBACK_KEY_UP:
515 return ((Evas_Event_Key_Up *)event_info)->event_flags;
518 return EVAS_EVENT_FLAG_NONE;
525 * Sets event flag to value returned from user callback
526 * @param sd Widget Data
527 * @param event_info pointer to event.
528 * @param event_type what type was ev (mouse down, etc...)
529 * @param ev_flags event flags
531 * @ingroup Elm_Gesture_Layer
534 _event_consume(Elm_Gesture_Layer_Smart_Data *sd,
536 Evas_Callback_Type event_type,
537 Evas_Event_Flags ev_flags)
539 /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
540 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
541 /* should not refeed this event. */
543 return; /* This happens when restarting gestures */
545 if (!sd->repeat_events) ev_flags |= EVAS_EVENT_FLAG_ON_HOLD;
551 case EVAS_CALLBACK_MOUSE_DOWN:
552 ((Evas_Event_Mouse_Down *)event_info)->event_flags |= ev_flags;
555 case EVAS_CALLBACK_MOUSE_MOVE:
556 ((Evas_Event_Mouse_Move *)event_info)->event_flags |= ev_flags;
559 case EVAS_CALLBACK_MOUSE_UP:
560 ((Evas_Event_Mouse_Up *)event_info)->event_flags |= ev_flags;
563 case EVAS_CALLBACK_MOUSE_WHEEL:
564 ((Evas_Event_Mouse_Wheel *)event_info)->event_flags |= ev_flags;
567 case EVAS_CALLBACK_MULTI_DOWN:
568 ((Evas_Event_Multi_Down *)event_info)->event_flags |= ev_flags;
571 case EVAS_CALLBACK_MULTI_MOVE:
572 ((Evas_Event_Multi_Move *)event_info)->event_flags |= ev_flags;
575 case EVAS_CALLBACK_MULTI_UP:
576 ((Evas_Event_Multi_Up *)event_info)->event_flags |= ev_flags;
579 case EVAS_CALLBACK_KEY_DOWN:
580 ((Evas_Event_Key_Down *)event_info)->event_flags |= ev_flags;
583 case EVAS_CALLBACK_KEY_UP:
584 ((Evas_Event_Key_Up *)event_info)->event_flags |= ev_flags;
596 * Report current state of a gesture by calling user callback.
597 * @param gesture what gesture state we report.
598 * @param info inforamtion for user callback
600 * @ingroup Elm_Gesture_Layer
602 static Evas_Event_Flags
603 _state_report(Gesture_Info *gesture,
606 /* We report current state (START, MOVE, END, ABORT), once */
607 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
608 (gesture->fn[gesture->state].cb)) /* Fill state-info struct and
612 return gesture->fn[gesture->state].cb(
613 gesture->fn[gesture->state].user_data, info);
616 return EVAS_EVENT_FLAG_NONE;
622 * Update state for a given gesture.
623 * We may update gesture state to:
624 * - @c UNDEFINED - current input did not start gesure yet.
625 * - @c START - gesture started according to input.
626 * - @c MOVE - gusture in progress.
627 * - @c END - gesture completed according to input.
628 * - @c ABORT - input does not matches gesure.
629 * note that we may move from UNDEFINED to ABORT
630 * because we may detect that gesture will not START
631 * with a given input.
633 * @param g given gesture to change state.
634 * @param s gesure new state.
635 * @param info buffer to be sent to user callback on report_state.
636 * @param force makes report_state to report the new-state even
637 * if its same as current state. Works for MOVE - gesture in progress.
639 * @ingroup Elm_Gesture_Layer
641 static Evas_Event_Flags
642 _state_set(Gesture_Info *g,
647 Elm_Gesture_State old_state;
649 if ((g->state == s) && (!force))
650 return EVAS_EVENT_FLAG_NONE;
652 old_state = g->state;
655 g->info = info; /* Information for user callback */
656 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
657 (g->state == ELM_GESTURE_STATE_END))
658 g->test = EINA_FALSE;
660 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
661 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
662 (s == ELM_GESTURE_STATE_ABORT))))
663 return _state_report(g, g->info);
665 return EVAS_EVENT_FLAG_NONE;
671 * This resets all gesture states and sets test-bit.
672 * this is used for restarting gestures to listen to input.
673 * happens after we complete a gesture or no gesture was detected.
674 * @param sd Widget data of the gesture-layer object.
676 * @ingroup Elm_Gesture_Layer
679 _states_reset(Elm_Gesture_Layer_Smart_Data *sd)
684 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
689 _state_set(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
698 * This function is used to save input events in an abstract struct
699 * to be used later by getsure-testing functions.
701 * @param data The gesture-layer object.
702 * @param event_info Pointer to recent input event.
703 * @param event_type Recent input event type.
704 * @param pe The abstract data-struct (output).
706 * @ingroup Elm_Gesture_Layer
709 _pointer_event_make(void *data __UNUSED__,
711 Evas_Callback_Type event_type,
714 memset(pe, '\0', sizeof(*pe));
717 case EVAS_CALLBACK_MOUSE_DOWN:
718 pe->x = ((Evas_Event_Mouse_Down *)event_info)->canvas.x;
719 pe->y = ((Evas_Event_Mouse_Down *)event_info)->canvas.y;
720 pe->timestamp = ((Evas_Event_Mouse_Down *)event_info)->timestamp;
721 pe->device = ELM_MOUSE_DEVICE;
724 case EVAS_CALLBACK_MOUSE_UP:
725 pe->x = ((Evas_Event_Mouse_Up *)event_info)->canvas.x;
726 pe->y = ((Evas_Event_Mouse_Up *)event_info)->canvas.y;
727 pe->timestamp = ((Evas_Event_Mouse_Up *)event_info)->timestamp;
728 pe->device = ELM_MOUSE_DEVICE;
731 case EVAS_CALLBACK_MOUSE_MOVE:
732 pe->x = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.x;
733 pe->y = ((Evas_Event_Mouse_Move *)event_info)->cur.canvas.y;
734 pe->timestamp = ((Evas_Event_Mouse_Move *)event_info)->timestamp;
735 pe->device = ELM_MOUSE_DEVICE;
738 case EVAS_CALLBACK_MULTI_DOWN:
739 pe->x = ((Evas_Event_Multi_Down *)event_info)->canvas.x;
740 pe->y = ((Evas_Event_Multi_Down *)event_info)->canvas.y;
741 pe->timestamp = ((Evas_Event_Multi_Down *)event_info)->timestamp;
742 pe->device = ((Evas_Event_Multi_Down *)event_info)->device;
745 case EVAS_CALLBACK_MULTI_UP:
746 pe->x = ((Evas_Event_Multi_Up *)event_info)->canvas.x;
747 pe->y = ((Evas_Event_Multi_Up *)event_info)->canvas.y;
748 pe->timestamp = ((Evas_Event_Multi_Up *)event_info)->timestamp;
749 pe->device = ((Evas_Event_Multi_Up *)event_info)->device;
752 case EVAS_CALLBACK_MULTI_MOVE:
753 pe->x = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.x;
754 pe->y = ((Evas_Event_Multi_Move *)event_info)->cur.canvas.y;
755 pe->timestamp = ((Evas_Event_Multi_Move *)event_info)->timestamp;
756 pe->device = ((Evas_Event_Multi_Move *)event_info)->device;
763 pe->event_type = event_type;
770 * This function copies input events.
771 * We copy event info before adding it to history.
772 * The memory is freed when we clear history.
774 * @param event the event to copy
775 * @param event_type event type to copy
777 * @ingroup Elm_Gesture_Layer
780 _event_info_copy(void *event,
781 Evas_Callback_Type event_type)
785 case EVAS_CALLBACK_MOUSE_DOWN:
786 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *)event);
789 case EVAS_CALLBACK_MOUSE_MOVE:
790 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *)event);
793 case EVAS_CALLBACK_MOUSE_UP:
794 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *)event);
797 case EVAS_CALLBACK_MOUSE_WHEEL:
798 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *)event);
801 case EVAS_CALLBACK_MULTI_DOWN:
802 return COPY_EVENT_INFO((Evas_Event_Multi_Down *)event);
805 case EVAS_CALLBACK_MULTI_MOVE:
806 return COPY_EVENT_INFO((Evas_Event_Multi_Move *)event);
809 case EVAS_CALLBACK_MULTI_UP:
810 return COPY_EVENT_INFO((Evas_Event_Multi_Up *)event);
813 case EVAS_CALLBACK_KEY_DOWN:
814 return COPY_EVENT_INFO((Evas_Event_Key_Down *)event);
817 case EVAS_CALLBACK_KEY_UP:
818 return COPY_EVENT_INFO((Evas_Event_Key_Up *)event);
827 _event_history_add(Evas_Object *obj,
829 Evas_Callback_Type event_type)
833 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
835 ev = malloc(sizeof(Event_History));
836 ev->event = _event_info_copy(event, event_type); /* Freed on
837 * _event_history_clear */
838 ev->event_type = event_type;
839 sd->event_history_list = (Event_History *)eina_inlist_append(
840 EINA_INLIST_GET(sd->event_history_list), EINA_INLIST_GET(ev));
846 * For all _mouse_* / multi_* functions wethen send this event to
847 * _event_process function.
849 * @param data The gesture-layer object.
850 * @param event_info Pointer to recent input event.
852 * @ingroup Elm_Gesture_Layer
855 _mouse_down_cb(void *data,
857 Evas_Object *obj __UNUSED__,
860 if (((Evas_Event_Mouse_Down *)event_info)->button != 1)
861 return; /* We only process left-click at the moment */
863 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
867 _mouse_move_cb(void *data,
869 Evas_Object *obj __UNUSED__,
872 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
876 _key_down_cb(void *data,
878 Evas_Object *obj __UNUSED__,
881 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
885 _key_up_cb(void *data,
887 Evas_Object *obj __UNUSED__,
890 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
894 _mouse_up_cb(void *data,
896 Evas_Object *obj __UNUSED__,
899 if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
900 return; /* We only process left-click at the moment */
902 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
906 _mouse_wheel_cb(void *data,
908 Evas_Object *obj __UNUSED__,
911 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
915 _multi_down_cb(void *data,
917 Evas_Object *obj __UNUSED__,
920 /* Skip the mouse duplicates. */
921 if (((Evas_Event_Multi_Down *) event_info)->device == 0) return;
923 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
927 _multi_move_cb(void *data,
929 Evas_Object *obj __UNUSED__,
932 /* Skip the mouse duplicates. */
933 if (((Evas_Event_Multi_Move *) event_info)->device == 0) return;
935 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
939 _multi_up_cb(void *data,
941 Evas_Object *obj __UNUSED__,
944 /* Skip the mouse duplicates. */
945 if (((Evas_Event_Multi_Up *) event_info)->device == 0) return;
947 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
953 * We register callbacks when gesture layer is attached to an object
954 * or when its enabled after disable.
956 * @param obj The gesture-layer object.
958 * @ingroup Elm_Gesture_Layer
961 _callbacks_register(Evas_Object *obj)
963 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
965 if (!sd->target) return;
967 evas_object_event_callback_add
968 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
969 evas_object_event_callback_add
970 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
971 evas_object_event_callback_add
972 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
974 evas_object_event_callback_add
975 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
977 evas_object_event_callback_add
978 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, obj);
979 evas_object_event_callback_add
980 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, obj);
981 evas_object_event_callback_add
982 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, obj);
984 evas_object_event_callback_add
985 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
986 evas_object_event_callback_add
987 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
993 * We unregister callbacks when gesture layer is disabled.
995 * @param obj The gesture-layer object.
997 * @ingroup Elm_Gesture_Layer
1000 _callbacks_unregister(Evas_Object *obj)
1002 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1004 if (!sd->target) return;
1006 evas_object_event_callback_del
1007 (sd->target, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb);
1008 evas_object_event_callback_del
1009 (sd->target, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb);
1010 evas_object_event_callback_del
1011 (sd->target, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb);
1013 evas_object_event_callback_del
1014 (sd->target, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb);
1016 evas_object_event_callback_del
1017 (sd->target, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb);
1019 evas_object_event_callback_del
1020 (sd->target, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb);
1022 evas_object_event_callback_del
1023 (sd->target, EVAS_CALLBACK_MULTI_UP, _multi_up_cb);
1025 evas_object_event_callback_del
1026 (sd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb);
1027 evas_object_event_callback_del
1028 (sd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb);
1033 * This function is used to find if device number
1034 * is found in a list of devices.
1035 * The list contains devices for refeeding *UP event
1037 * @ingroup Elm_Gesture_Layer
1040 _device_in_pending_cmp(const void *data1,
1043 /* Compare the two device numbers */
1044 return ((intptr_t)data1) - ((intptr_t)data2);
1050 * This functions returns pending-device node
1051 * @ingroup Elm_Gesture_Layer
1054 _device_is_pending(Eina_List *list,
1056 Evas_Callback_Type event_type)
1058 int device = ELM_MOUSE_DEVICE;
1062 case EVAS_CALLBACK_MOUSE_UP:
1065 case EVAS_CALLBACK_MULTI_UP:
1066 device = ((Evas_Event_Multi_Up *)event)->device;
1073 return eina_list_search_unsorted_list
1074 (list, _device_in_pending_cmp, (void *)(intptr_t)device);
1080 * This functions adds device to refeed-pending device list
1081 * @ingroup Elm_Gesture_Layer
1084 _pending_device_add(Eina_List *list,
1086 Evas_Callback_Type event_type)
1088 int device = ELM_MOUSE_DEVICE;
1092 case EVAS_CALLBACK_MOUSE_DOWN:
1095 case EVAS_CALLBACK_MULTI_DOWN:
1096 device = ((Evas_Event_Multi_Down *)event)->device;
1103 if (!eina_list_search_unsorted_list
1104 (list, _device_in_pending_cmp, (void *)(intptr_t)device))
1106 return eina_list_append(list, (void *)(intptr_t)device);
1115 * This function reports ABORT to all none-detected gestures
1116 * Then resets test bits for all desired gesures
1117 * and clears input-events history.
1118 * note: if no gesture was detected, events from history list
1119 * are streamed to the widget because it's unused by layer.
1120 * user may cancel refeed of events by setting repeat events.
1122 * @param obj The gesture-layer object.
1124 * @ingroup Elm_Gesture_Layer
1127 _event_history_clear(Evas_Object *obj)
1131 Evas *e = evas_object_evas_get(obj);
1132 Eina_Bool gesture_found = EINA_FALSE;
1134 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1136 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1141 if (p->state == ELM_GESTURE_STATE_END)
1143 gesture_found = EINA_TRUE;
1146 { /* Report ABORT to all gestures that still not finished */
1147 _state_set(p, ELM_GESTURE_STATE_ABORT, sd->gesture[i]->info,
1153 _states_reset(sd); /* we are ready to start testing for gestures again */
1155 /* Clear all gestures intermediate data */
1157 /* FIXME: +1 because of the mistake in the enum. */
1158 Gesture_Info **gitr = sd->gesture + 1;
1159 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1160 for (; fitr->reset; fitr++, gitr++)
1162 if (IS_TESTED_GESTURE(*gitr))
1167 /* Disable gesture layer so refeeded events won't be consumed by it */
1168 _callbacks_unregister(obj);
1169 while (sd->event_history_list)
1172 t = sd->event_history_list;
1173 Eina_List *pending = _device_is_pending
1174 (sd->pending, sd->event_history_list->event,
1175 sd->event_history_list->event_type);
1177 /* Refeed events if no gesture matched input */
1178 if (pending || ((!gesture_found) && (!sd->repeat_events)))
1180 evas_event_refeed_event(e, sd->event_history_list->event,
1181 sd->event_history_list->event_type);
1185 sd->pending = eina_list_remove_list(sd->pending, pending);
1189 sd->pending = _pending_device_add
1190 (sd->pending, sd->event_history_list->event,
1191 sd->event_history_list->event_type);
1195 free(sd->event_history_list->event);
1196 sd->event_history_list = (Event_History *)eina_inlist_remove(
1197 EINA_INLIST_GET(sd->event_history_list),
1198 EINA_INLIST_GET(sd->event_history_list));
1201 _callbacks_register(obj);
1208 * if gesture was NOT detected AND we only have gestures in ABORT state
1209 * we clear history immediately to be ready for input.
1211 * @param obj The gesture-layer object.
1212 * @return TRUE on event history_clear
1214 * @ingroup Elm_Gesture_Layer
1217 _clear_if_finished(Evas_Object *obj)
1220 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
1222 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1224 /* Clear history if all we have aborted gestures */
1225 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
1226 { /* If no gesture started and all we have aborted gestures, reset all */
1227 Gesture_Info *p = sd->gesture[i];
1229 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
1231 if ((p->state == ELM_GESTURE_STATE_START) ||
1232 (p->state == ELM_GESTURE_STATE_MOVE))
1233 reset_s = EINA_FALSE;
1235 all_undefined = EINA_FALSE;
1239 if (reset_s && (!all_undefined))
1240 return _event_history_clear(obj);
1248 * This function restartes line, flick, zoom and rotate gestures
1249 * when gesture-layer continues-gestures enabled.
1250 * Example of continues-gesture:
1251 * When doing a line, user stops moving finger but keeps fingers on touch.
1252 * This will cause line-end, then as user continues moving his finger
1253 * it re-starts line gesture.
1254 * When continue mode is disabled, user has to lift finger from touch
1255 * to end a gesture. Them touch-again to start a new one.
1257 * @param data The gesture-layer object.
1258 * @param sd gesture layer widget data.
1259 * @param states_reset flag that marks gestures were reset in history clear.
1261 * @ingroup Elm_Gesture_Layer
1264 _continues_gestures_restart(void *data,
1265 Eina_Bool states_reset)
1267 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1269 /* Test all the gestures */
1271 /* FIXME: +1 because of the mistake in the enum. */
1272 Gesture_Info **gitr = sd->gesture + 1;
1273 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1274 for (; fitr->test; fitr++, gitr++)
1276 Gesture_Info *g = *gitr;
1277 Eina_Bool tmp = (g) ?
1278 ((states_reset) || ((g->state != ELM_GESTURE_STATE_START)
1279 && (g->state != ELM_GESTURE_STATE_MOVE)))
1281 if (tmp && fitr->cont_reset)
1283 fitr->cont_reset(g);
1284 _state_set(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
1294 * This function the core-function where input handling is done.
1295 * Here we get user input and stream it to gesture testing.
1296 * We notify user about any gestures with new state:
1298 * START - gesture started.
1299 * MOVE - gesture is ongoing.
1300 * END - gesture was completed.
1301 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
1303 * We also check if a gesture was detected, then reset event history
1304 * If no gestures were found we reset gesture test flag
1305 * after streaming event-history to widget.
1306 * (stream to the widget all events not consumed as a gesture)
1308 * @param data The gesture-layer object.
1309 * @param event_info Pointer to recent input event.
1310 * @param event_type Recent input event type.
1312 * @ingroup Elm_Gesture_Layer
1315 _event_process(void *data,
1316 Evas_Object *obj __UNUSED__,
1318 Evas_Callback_Type event_type)
1321 Pointer_Event *pe = NULL;
1323 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1325 /* Start testing candidate gesture from here */
1326 if (_pointer_event_make(data, event_info, event_type, &_pe))
1329 /* Test all the gestures */
1331 /* FIXME: +1 because of the mistake in the enum. */
1332 Gesture_Info **gitr = sd->gesture + 1;
1333 Tests_Array_Funcs *fitr = _glayer_tests_array + 1;
1334 for (; fitr->test; fitr++, gitr++)
1336 if (IS_TESTED_GESTURE(*gitr))
1337 fitr->test(data, pe, event_info, event_type, (*gitr)->g_type);
1341 if (_event_flag_get(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
1342 _event_history_add(data, event_info, event_type);
1344 /* we maintain list of touched devices */
1345 /* We also use move to track current device x.y pos */
1346 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1347 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1348 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
1349 (event_type == EVAS_CALLBACK_MULTI_MOVE))
1351 sd->touched = _touched_device_add(sd->touched, pe);
1353 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
1354 (event_type == EVAS_CALLBACK_MULTI_UP))
1356 sd->touched = _touched_device_remove(sd->touched, pe);
1359 /* Report current states and clear history if needed */
1360 Eina_Bool states_reset = _clear_if_finished(data);
1361 if (sd->glayer_continues_enable)
1362 _continues_gestures_restart(data, states_reset);
1366 _inside(Evas_Coord xx1,
1371 int w = elm_config_finger_size_get() >> 1; /* Finger size devided by 2 */
1373 if (xx1 < (xx2 - w))
1376 if (xx1 > (xx2 + w))
1379 if (yy1 < (yy2 - w))
1382 if (yy1 > (yy2 + w))
1388 /* All *test_reset() funcs are called to clear
1389 * gesture intermediate data.
1390 * This happens when we need to reset our tests.
1391 * for example when gesture is detected or all ABORTed. */
1393 _tap_gestures_test_reset(Gesture_Info *gesture)
1398 EINA_SAFETY_ON_NULL_RETURN(gesture);
1399 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1401 if (sd->gest_taps_timeout)
1403 ecore_timer_del(sd->gest_taps_timeout);
1404 sd->gest_taps_timeout = NULL;
1410 EINA_LIST_FREE (((Taps_Type *)gesture->data)->l, data)
1411 EINA_LIST_FREE (data, pe)
1414 memset(gesture->data, 0, sizeof(Taps_Type));
1417 /* All *test_reset() funcs are called to clear
1418 * gesture intermediate data.
1419 * This happens when we need to reset our tests.
1420 * for example when gesture is detected or all ABORTed. */
1422 _n_long_tap_test_reset(Gesture_Info *gesture)
1428 EINA_SAFETY_ON_NULL_RETURN(gesture);
1429 if (!gesture->data) return;
1433 EINA_LIST_FOREACH (st->touched, l, p)
1436 eina_list_free(st->touched);
1439 ecore_timer_del(st->timeout);
1442 memset(gesture->data, 0, sizeof(Long_Tap_Type));
1446 _momentum_test_reset(Gesture_Info *gesture)
1448 EINA_SAFETY_ON_NULL_RETURN(gesture);
1449 if (!gesture->data) return;
1451 memset(gesture->data, 0, sizeof(Momentum_Type));
1455 _line_data_reset(Line_Data *st)
1460 memset(st, 0, sizeof(Line_Data));
1461 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1465 _line_test_reset(Gesture_Info *gesture)
1472 EINA_SAFETY_ON_NULL_RETURN(gesture);
1473 if (!gesture->data) return;
1478 EINA_LIST_FOREACH (list, l, t_line)
1481 eina_list_free(list);
1486 _zoom_test_reset(Gesture_Info *gesture)
1489 Evas_Modifier_Mask mask;
1491 EINA_SAFETY_ON_NULL_RETURN(gesture);
1492 if (!gesture->data) return;
1493 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1496 mask = evas_key_modifier_mask_get(
1497 evas_object_evas_get(sd->target), "Control");
1498 evas_object_key_ungrab(sd->target, "Control_L", mask, 0);
1499 evas_object_key_ungrab(sd->target, "Control_R", mask, 0);
1501 memset(st, 0, sizeof(Zoom_Type));
1502 st->zoom_distance_tolerance = sd->zoom_distance_tolerance;
1503 st->info.zoom = 1.0;
1507 _rotate_test_reset(Gesture_Info *gesture)
1511 EINA_SAFETY_ON_NULL_RETURN(gesture);
1512 if (!gesture->data) return;
1514 ELM_GESTURE_LAYER_DATA_GET(gesture->obj, sd);
1517 memset(st, 0, sizeof(Rotate_Type));
1518 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1519 st->rotate_angular_tolerance = sd->rotate_angular_tolerance;
1523 _match_fingers_compare(const void *data1,
1526 /* Compare coords of first item in list to cur coords */
1527 const Pointer_Event *pe1 = eina_list_data_get(data1);
1528 const Pointer_Event *pe2 = data2;
1530 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1532 else if (pe1->x < pe2->x)
1536 if (pe1->x == pe2->x)
1537 return pe1->y - pe2->y;
1544 _pe_device_compare(const void *data1,
1547 /* Compare device of first item in list to our pe device */
1548 const Pointer_Event *pe1 = eina_list_data_get(data1);
1549 const Pointer_Event *pe2 = data2;
1551 /* Only match if last was a down event */
1552 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1553 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1556 if (pe1->device == pe2->device)
1558 else if (pe1->device < pe2->device)
1565 _pointer_event_record(Taps_Type *st,
1568 Elm_Gesture_Layer_Smart_Data *sd,
1570 Evas_Callback_Type event_type)
1572 /* Keep copy of pe and record it in list */
1573 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1575 memcpy(p, pe, sizeof(Pointer_Event));
1576 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1582 /* This will also update middle-point to report to user later */
1583 st->info.x = st->sum_x / st->n_taps;
1584 st->info.y = st->sum_y / st->n_taps;
1585 st->info.timestamp = pe->timestamp;
1589 pe_list = eina_list_append(pe_list, p);
1590 st->l = eina_list_append(st->l, pe_list);
1593 pe_list = eina_list_append(pe_list, p);
1601 * This function checks if the tap gesture is done.
1603 * @param data gesture info pointer
1604 * @return EINA_TRUE if it is done.
1606 * @ingroup Elm_Gesture_Layer
1609 _tap_gesture_check_finish(Gesture_Info *gesture)
1611 /* Here we check if taps-gesture was completed successfuly */
1612 /* Count how many taps were recieved on each device then */
1613 /* determine if it matches n_taps_needed defined on START */
1614 Taps_Type *st = gesture->data;
1618 if (!st->l) return EINA_FALSE;
1619 EINA_LIST_FOREACH (st->l, l, pe_list)
1621 /* No match taps number on device, ABORT */
1622 if (eina_list_count(pe_list) != st->n_taps_needed)
1634 * This function sets state a tap-gesture to END or ABORT
1636 * @param data gesture info pointer
1638 * @ingroup Elm_Gesture_Layer
1641 _tap_gesture_finish(void *data)
1643 /* This function will test each tap gesture when timer expires */
1644 Elm_Gesture_State s = ELM_GESTURE_STATE_ABORT;
1645 Gesture_Info *gesture = data;
1646 Taps_Type *st = gesture->data;
1648 if (_tap_gesture_check_finish(gesture))
1650 s = ELM_GESTURE_STATE_END;
1653 st->info.n = eina_list_count(st->l);
1654 _state_set(gesture, s, gesture->info, EINA_FALSE);
1655 _tap_gestures_test_reset(gesture);
1661 * when this timer expires we finish tap gestures.
1663 * @param data The gesture-layer object.
1664 * @return cancles callback for this timer.
1666 * @ingroup Elm_Gesture_Layer
1669 _multi_tap_timeout(void *data)
1671 ELM_GESTURE_LAYER_DATA_GET(data, sd);
1673 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1674 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TAPS]);
1676 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1677 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1679 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1680 _tap_gesture_finish(sd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1682 _clear_if_finished(data);
1683 sd->gest_taps_timeout = NULL;
1685 return ECORE_CALLBACK_CANCEL;
1691 * when this timer expires we START long tap gesture
1693 * @param data The gesture-layer object.
1694 * @return cancles callback for this timer.
1696 * @ingroup Elm_Gesture_Layer
1699 _long_tap_timeout(void *data)
1701 Gesture_Info *gesture = data;
1703 _state_set(gesture, ELM_GESTURE_STATE_MOVE,
1704 gesture->data, EINA_TRUE);
1706 return ECORE_CALLBACK_RENEW;
1712 * This function checks the state of a tap gesture.
1714 * @param sd Gesture Layer Widget Data.
1715 * @param pe The recent input event as stored in pe struct.
1716 * @param event_info Original input event pointer.
1717 * @param event_type Type of original input event.
1718 * @param gesture what gesture is tested
1719 * @param how many taps for this gesture (1, 2 or 3)
1721 * @ingroup Elm_Gesture_Layer
1724 _tap_gesture_test(Evas_Object *obj,
1727 Evas_Callback_Type event_type,
1728 Elm_Gesture_Type g_type)
1732 Gesture_Info *gesture;
1733 Eina_List *pe_list = NULL;
1734 Pointer_Event *pe_down = NULL;
1735 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1737 /* Here we fill Tap struct */
1738 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1743 gesture = sd->gesture[g_type];
1744 if (!gesture) return;
1748 case ELM_GESTURE_N_TAPS:
1752 case ELM_GESTURE_N_DOUBLE_TAPS:
1756 case ELM_GESTURE_N_TRIPLE_TAPS:
1766 if (!st) /* Allocated once on first time */
1768 st = calloc(1, sizeof(Taps_Type));
1770 _tap_gestures_test_reset(gesture);
1773 switch (pe->event_type)
1775 case EVAS_CALLBACK_MULTI_DOWN:
1776 case EVAS_CALLBACK_MOUSE_DOWN:
1777 /* Check if got tap on same cord was tapped before */
1778 pe_list = eina_list_search_unsorted(st->l, _match_fingers_compare, pe);
1781 /* This device was touched in other cord before completion */
1782 eina_list_search_unsorted(st->l, _pe_device_compare, pe))
1784 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1785 &st->info, EINA_FALSE);
1786 _event_consume(sd, event_info, event_type, ev_flag);
1791 pe_list = _pointer_event_record
1792 (st, pe_list, pe, sd, event_info, event_type);
1793 if ((!sd->gest_taps_timeout) &&
1794 (_elm_config->glayer_double_tap_timeout > 0.0))
1795 sd->gest_taps_timeout =
1796 ecore_timer_add(_elm_config->glayer_double_tap_timeout,
1797 _multi_tap_timeout, gesture->obj);
1798 else if (sd->gest_taps_timeout)
1799 ecore_timer_reset(sd->gest_taps_timeout);
1801 /* This is the first mouse down we got */
1802 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1804 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
1805 &st->info, EINA_FALSE);
1806 _event_consume(sd, event_info, event_type, ev_flag);
1808 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1812 else if (eina_list_count(pe_list) > st->n_taps_needed)
1813 /* If we arleady got too many touches for this gesture. */
1814 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1815 &st->info, EINA_FALSE);
1819 case EVAS_CALLBACK_MULTI_UP:
1820 case EVAS_CALLBACK_MOUSE_UP:
1821 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1822 if (!pe_list) return;
1824 pe_list = _pointer_event_record
1825 (st, pe_list, pe, sd, event_info, event_type);
1827 if (((gesture->g_type == ELM_GESTURE_N_TAPS) &&
1828 !IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS) &&
1829 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) ||
1830 ((gesture->g_type == ELM_GESTURE_N_DOUBLE_TAPS) &&
1831 !IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)))
1833 if (_tap_gesture_check_finish(gesture))
1835 _tap_gesture_finish(gesture);
1842 case EVAS_CALLBACK_MULTI_MOVE:
1843 case EVAS_CALLBACK_MOUSE_MOVE:
1844 /* Get first event in first list, this has to be a Mouse Down event */
1845 /* and verify that user didn't move out of this area before next tap */
1846 pe_list = eina_list_search_unsorted(st->l, _pe_device_compare, pe);
1849 pe_down = eina_list_data_get(pe_list);
1850 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1852 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1853 &st->info, EINA_FALSE);
1854 _event_consume(sd, event_info, event_type, ev_flag);
1867 * This function computes center-point for long-tap gesture
1869 * @param st Long Tap gesture info pointer
1870 * @param pe The recent input event as stored in pe struct.
1872 * @ingroup Elm_Gesture_Layer
1875 _compute_taps_center(Long_Tap_Type *st,
1882 Evas_Coord x = 0, y = 0;
1884 if (!eina_list_count(st->touched))
1887 EINA_LIST_FOREACH (st->touched, l, p)
1888 { /* Accumulate all then take avarage */
1889 if (p->device == pe->device) /* This will take care of values
1890 * coming from MOVE event */
1902 *x_out = x / eina_list_count(st->touched);
1903 *y_out = y / eina_list_count(st->touched);
1909 * This function checks N long-tap gesture.
1911 * @param obj The gesture-layer object.
1912 * @param pe The recent input event as stored in pe struct.
1913 * @param event_info Original input event pointer.
1914 * @param event_type Type of original input event.
1915 * @param g_type what Gesture we are testing.
1916 * @param taps How many click/taps we test for.
1918 * @ingroup Elm_Gesture_Layer
1921 _n_long_tap_test(Evas_Object *obj,
1924 Evas_Callback_Type event_type,
1925 Elm_Gesture_Type g_type)
1927 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1928 Gesture_Info *gesture;
1931 /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1932 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
1934 if (!pe) /* this happens when unhandled event arrived */
1935 return; /* see _make_pointer_event function */
1937 gesture = sd->gesture[g_type];
1938 if (!gesture) return;
1941 if (!st) /* Allocated once on first time */
1943 st = calloc(1, sizeof(Long_Tap_Type));
1945 _n_long_tap_test_reset(gesture);
1948 switch (pe->event_type)
1950 case EVAS_CALLBACK_MULTI_DOWN:
1951 case EVAS_CALLBACK_MOUSE_DOWN:
1952 st->touched = _touched_device_add(st->touched, pe);
1953 st->info.n = eina_list_count(st->touched);
1955 /* This is the first mouse down we got */
1956 if (eina_list_count(st->touched) == 1)
1958 _state_set(gesture, ELM_GESTURE_STATE_START,
1959 gesture->data, EINA_FALSE);
1960 st->info.timestamp = pe->timestamp;
1962 /* To test long tap */
1963 /* When this timer expires, gesture STARTED */
1964 if ((!st->timeout) && (sd->long_tap_start_timeout > 0.0))
1965 st->timeout = ecore_timer_add(sd->long_tap_start_timeout,
1966 _long_tap_timeout, gesture);
1971 ecore_timer_reset(st->timeout);
1975 _event_consume(sd, event_info, event_type, ev_flag);
1976 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1977 st->center_x = st->info.x;
1978 st->center_y = st->info.y;
1981 case EVAS_CALLBACK_MULTI_UP:
1982 case EVAS_CALLBACK_MOUSE_UP:
1983 st->touched = _touched_device_remove(st->touched, pe);
1984 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1987 if (gesture->state == ELM_GESTURE_STATE_MOVE)
1988 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
1989 &st->info, EINA_FALSE);
1991 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
1992 &st->info, EINA_FALSE);
1996 ecore_timer_del(st->timeout);
1999 _event_consume(sd, event_info, event_type, ev_flag);
2004 case EVAS_CALLBACK_MULTI_MOVE:
2005 case EVAS_CALLBACK_MOUSE_MOVE:
2007 ((gesture->state == ELM_GESTURE_STATE_START) ||
2008 /* Report MOVE only if STARTED */
2009 (gesture->state == ELM_GESTURE_STATE_MOVE)))
2014 _compute_taps_center(st, &x, &y, pe);
2015 /* ABORT if user moved fingers out of tap area */
2016 if (!_inside(x, y, st->center_x, st->center_y))
2020 ecore_timer_del(st->timeout);
2024 /* Report MOVE if gesture started */
2025 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2026 &st->info, EINA_FALSE);
2029 _event_consume(sd, event_info, event_type, ev_flag);
2041 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
2042 * This momentum value will be sent to widget when gesture is completed.
2044 * @param momentum pointer to buffer where we record momentum value.
2045 * @param x1 x coord where user started gesture.
2046 * @param y1 y coord where user started gesture.
2047 * @param x2 x coord where user completed gesture.
2048 * @param y2 y coord where user completed gesture.
2049 * @param t1x timestamp for X, when user started gesture.
2050 * @param t1y timestamp for Y, when user started gesture.
2051 * @param t2 timestamp when user completed gesture.
2053 * @ingroup Elm_Gesture_Layer
2056 _momentum_set(Elm_Gesture_Momentum_Info *momentum,
2065 Evas_Coord velx = 0, vely = 0, vel;
2066 Evas_Coord dx = xx2 - xx1;
2067 Evas_Coord dy = yy2 - yy1;
2072 velx = (dx * 1000) / dtx;
2075 vely = (dy * 1000) / dty;
2077 vel = sqrt((velx * velx) + (vely * vely));
2079 if ((_elm_config->thumbscroll_friction > 0.0) &&
2080 (vel > _elm_config->thumbscroll_momentum_threshold)) /* report
2083 momentum->mx = velx;
2084 momentum->my = vely;
2096 * This function is used for computing rotation angle (DEG).
2098 * @param x1 first finger x location.
2099 * @param y1 first finger y location.
2100 * @param x2 second finger x location.
2101 * @param y2 second finger y location.
2103 * @return angle of the line between (x1,y1), (x2,y2) in Deg.
2104 * Angles now are given in DEG, not RAD.
2105 * ZERO angle at 12-oclock, growing clockwise.
2107 * @ingroup Elm_Gesture_Layer
2110 _angle_get(Evas_Coord xx1,
2115 double a, xx, yy, rt = (-1);
2117 xx = fabs(xx2 - xx1);
2118 yy = fabs(yy2 - yy1);
2120 if (((int)xx) && ((int)yy))
2122 rt = a = RAD2DEG(atan(yy / xx));
2125 if (yy1 < yy2) rt = 360 - a;
2130 if (yy1 < yy2) rt = 180 + a;
2135 if (rt < 0) /* Do this only if rt is not set */
2137 if (((int)xx)) /* Horizontal line */
2139 if (xx2 < xx1) rt = 180;
2143 { /* Vertical line */
2144 if (yy2 < yy1) rt = 90;
2149 /* Now we want to change from:
2151 * original circle 180 0 We want: 270 90
2155 if (rt >= 360) rt -= 360;
2163 * This function is used for computing the magnitude and direction
2164 * of vector between two points.
2166 * @param x1 first finger x location.
2167 * @param y1 first finger y location.
2168 * @param x2 second finger x location.
2169 * @param y2 second finger y location.
2170 * @param l length computed (output)
2171 * @param a angle computed (output)
2173 * @ingroup Elm_Gesture_Layer
2176 _vector_get(Evas_Coord xx1,
2187 *l = (Evas_Coord)sqrt((xx * xx) + (yy * yy));
2188 *a = _angle_get(xx1, yy1, xx2, yy2);
2192 _direction_get(Evas_Coord xx1,
2195 if (xx2 < xx1) return -1;
2196 if (xx2 > xx1) return 1;
2204 * This function tests momentum gesture.
2205 * @param obj The gesture-layer object.
2206 * @param pe The recent input event as stored in pe struct.
2207 * @param event_info recent input event.
2208 * @param event_type recent event type.
2209 * @param g_type what Gesture we are testing.
2211 * @ingroup Elm_Gesture_Layer
2214 _momentum_test(Evas_Object *obj,
2217 Evas_Callback_Type event_type,
2218 Elm_Gesture_Type g_type)
2223 Gesture_Info *gesture;
2224 Pointer_Event pe_local;
2225 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2226 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
2227 unsigned int cnt = 1; /* We start counter counting current pe event */
2229 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2231 gesture = sd->gesture[g_type];
2232 if (!gesture) return;
2234 /* When continues enable = TRUE a gesture may START on MOVE event */
2235 /* We don't allow this to happen with the if-statement below. */
2236 /* When continues enable = FALSE a gesture may START on DOWN only */
2237 /* Therefor it would NOT start on MOVE event. */
2238 /* NOTE that touched list is updated AFTER this function returns */
2239 /* so (count == 0) when we get here on first touch on surface. */
2240 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2241 return; /* Got move on mouse-over move */
2244 if (!st) /* Allocated once on first time */
2246 st = calloc(1, sizeof(Momentum_Type));
2248 _momentum_test_reset(gesture);
2254 /* First make avarage of all touched devices to determine center point */
2255 pe_local = *pe; /* Copy pe event info to local */
2256 EINA_LIST_FOREACH (sd->touched, l, p)
2257 if (p->device != pe_local.device)
2264 /* Compute avarage to get center point */
2268 /* If user added finger - reset gesture */
2269 if ((st->info.n) && (st->info.n < cnt))
2270 state_to_report = ELM_GESTURE_STATE_ABORT;
2272 if (st->info.n < cnt)
2277 case EVAS_CALLBACK_MOUSE_DOWN:
2278 case EVAS_CALLBACK_MULTI_DOWN:
2279 case EVAS_CALLBACK_MOUSE_MOVE:
2280 case EVAS_CALLBACK_MULTI_MOVE:
2283 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2284 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2285 (sd->glayer_continues_enable)) /* start also on MOVE */
2286 { /* We start on MOVE when cont-enabled only */
2287 st->line_st.x = st->line_end.x = pe_local.x;
2288 st->line_st.y = st->line_end.y = pe_local.y;
2289 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
2290 st->xdir = st->ydir = 0;
2291 st->info.x2 = st->info.x1 = pe_local.x;
2292 st->info.y2 = st->info.y1 = pe_local.y;
2293 st->info.tx = st->info.ty = pe_local.timestamp;
2294 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
2295 &st->info, EINA_FALSE);
2296 _event_consume(sd, event_info, event_type, ev_flag);
2304 Eina_Bool force = EINA_TRUE; /* for move state */
2306 /* ABORT if got DOWN or MOVE event after UP+timeout */
2307 if ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp)
2309 state_to_report = ELM_GESTURE_STATE_ABORT;
2313 /* We report state but don't compute momentum now */
2314 ev_flag = _state_set(gesture, state_to_report, &st->info,
2316 _event_consume(sd, event_info, event_type, ev_flag);
2317 return; /* Stop computing when user remove finger */
2320 /* Too long of a wait, reset all values */
2321 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2323 st->line_st.x = pe_local.x;
2324 st->line_st.y = pe_local.y;
2325 st->t_st_y = st->t_st_x = pe_local.timestamp;
2326 st->info.tx = st->t_st_x;
2327 st->info.ty = st->t_st_y;
2328 st->xdir = st->ydir = 0;
2334 xdir = _direction_get(st->line_end.x, pe_local.x);
2335 ydir = _direction_get(st->line_end.y, pe_local.y);
2336 if (xdir && (xdir != st->xdir))
2338 st->line_st.x = st->line_end.x;
2339 st->info.tx = st->t_st_x = st->t_end;
2343 if (ydir && (ydir != st->ydir))
2345 st->line_st.y = st->line_end.y;
2346 st->info.ty = st->t_st_y = st->t_end;
2351 st->info.x2 = st->line_end.x = pe_local.x;
2352 st->info.y2 = st->line_end.y = pe_local.y;
2353 st->t_end = pe_local.timestamp;
2354 _momentum_set(&st->info, st->line_st.x, st->line_st.y,
2355 pe_local.x, pe_local.y, st->t_st_x, st->t_st_y,
2356 pe_local.timestamp);
2358 ev_flag = _state_set(gesture, state_to_report, &st->info,
2360 _event_consume(sd, event_info, event_type, ev_flag);
2363 case EVAS_CALLBACK_MOUSE_UP:
2364 case EVAS_CALLBACK_MULTI_UP:
2365 st->t_up = pe_local.timestamp; /* Record recent up event time */
2366 if ((cnt > 1) || /* Ignore if more fingers touch surface */
2367 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
2370 /* Too long of a wait, reset all values */
2371 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
2373 st->line_st.x = pe_local.x;
2374 st->line_st.y = pe_local.y;
2375 st->t_st_y = st->t_st_x = pe_local.timestamp;
2376 st->xdir = st->ydir = 0;
2379 st->info.x2 = pe_local.x;
2380 st->info.y2 = pe_local.y;
2381 st->line_end.x = pe_local.x;
2382 st->line_end.y = pe_local.y;
2383 st->t_end = pe_local.timestamp;
2385 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
2386 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
2387 state_to_report = ELM_GESTURE_STATE_END;
2389 state_to_report = ELM_GESTURE_STATE_ABORT;
2391 ev_flag = _state_set(gesture, state_to_report, &st->info,
2393 _event_consume(sd, event_info, event_type, ev_flag);
2402 _line_device_compare(const void *data1,
2405 /* Compare device component of line struct */
2406 const Line_Data *ln1 = data1;
2407 const int *device = data2;
2409 if (ln1->t_st) /* Compare only with lines that started */
2410 return ln1->device - (*device);
2418 * This function construct line struct from input.
2419 * @param info pointer to store line momentum.
2420 * @param st line info to store input data.
2421 * @param pe The recent input event as stored in pe struct.
2423 * @ingroup Elm_Gesture_Layer
2426 _single_line_process(Elm_Gesture_Line_Info *info,
2429 Evas_Callback_Type event_type)
2431 /* Record events and set momentum for line pointed by st */
2437 case EVAS_CALLBACK_MOUSE_DOWN:
2438 case EVAS_CALLBACK_MOUSE_MOVE:
2439 case EVAS_CALLBACK_MULTI_DOWN:
2440 case EVAS_CALLBACK_MULTI_MOVE:
2441 if (!st->t_st) /* This happens only when line starts */
2443 st->line_st.x = pe->x;
2444 st->line_st.y = pe->y;
2445 st->t_st = pe->timestamp;
2446 st->device = pe->device;
2447 info->momentum.x1 = pe->x;
2448 info->momentum.y1 = pe->y;
2449 info->momentum.tx = pe->timestamp;
2450 info->momentum.ty = pe->timestamp;
2457 case EVAS_CALLBACK_MOUSE_UP:
2458 case EVAS_CALLBACK_MULTI_UP:
2459 /* IGNORE if line info was cleared, like long press, move */
2463 st->line_end.x = pe->x;
2464 st->line_end.y = pe->y;
2465 st->t_end = pe->timestamp;
2474 _line_data_reset(st);
2478 info->momentum.x2 = pe->x;
2479 info->momentum.y2 = pe->y;
2480 _momentum_set(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
2481 st->t_st, st->t_st, pe->timestamp);
2489 * This function test for (n) line gesture.
2490 * @param obj The gesture-layer object.
2491 * @param pe The recent input event as stored in pe struct.
2492 * @param event_info Original input event pointer.
2493 * @param event_type Type of original input event.
2494 * @param g_type what Gesture we are testing.
2496 * @ingroup Elm_Gesture_Layer
2499 _n_line_test(Evas_Object *obj,
2502 Evas_Callback_Type event_type,
2503 Elm_Gesture_Type g_type)
2508 Gesture_Info *gesture;
2509 Line_Data *line = NULL;
2514 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
2516 gesture = sd->gesture[g_type];
2517 if (!gesture ) return;
2519 /* When continues enable = TRUE a gesture may START on MOVE event */
2520 /* We don't allow this to happen with the if-statement below. */
2521 /* When continues enable = FALSE a gesture may START on DOWN only */
2522 /* Therefor it would NOT start on MOVE event. */
2523 /* NOTE that touched list is updated AFTER this function returns */
2524 /* so (count == 0) when we get here on first touch on surface. */
2525 if ((sd->glayer_continues_enable) && (!eina_list_count(sd->touched)))
2526 return; /* Got move on mouse-over move */
2531 st = calloc(1, sizeof(Line_Type));
2536 cnt = eina_list_count(list);
2538 if (cnt) /* list is not empty, locate this device on list */
2540 line = (Line_Data *)eina_list_search_unsorted
2541 (st->list, _line_device_compare, &pe->device);
2544 if (!line) /* List is empty or device not found, new line-struct on
2547 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2548 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2549 ((sd->glayer_continues_enable) && /* START on MOVE also */
2550 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2551 /* Allocate new item on START only */
2552 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2554 line = calloc(1, sizeof(Line_Data));
2555 _line_data_reset(line);
2556 list = eina_list_append(list, line);
2561 if (!line) /* This may happen on MOVE that comes before DOWN */
2562 return; /* No line-struct to work with, can't continue testing */
2564 /* update st with input */
2565 if (_single_line_process(&st->info, line, pe, event_type))
2566 _event_consume(sd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2568 /* Get direction and magnitude of the line */
2570 _vector_get(line->line_st.x, line->line_st.y, pe->x, pe->y,
2571 &line->line_length, &angle);
2573 /* These are used later to compare lines length */
2574 Evas_Coord shortest_line_len = line->line_length;
2575 Evas_Coord longest_line_len = line->line_length;
2576 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2578 /* Now update line-state */
2579 if (line->t_st) /* Analyze line only if line started */
2581 if (line->line_angle >= 0.0) /* if line direction was set, we
2582 * test if broke tolerance */
2584 double a = fabs(angle - line->line_angle);
2585 /* Distance from line */
2586 double d = (tan(DEG2RAD(a))) * line->line_length;
2587 /* Broke tolerance: abort line and start a new one */
2588 if ((d > sd->line_distance_tolerance) ||
2589 (a > sd->line_angular_tolerance))
2591 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2592 &st->info, EINA_FALSE);
2593 _event_consume(sd, event_info, event_type, ev_flag);
2597 /* We may finish line if momentum is zero */
2598 if (sd->glayer_continues_enable)
2600 /* This is for continues-gesture */
2601 /* Finish line on zero momentum for continues gesture */
2602 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2604 line->line_end.x = pe->x;
2605 line->line_end.y = pe->y;
2606 line->t_end = pe->timestamp;
2611 { /* Record the line angle as it broke minimum length for line */
2612 if (line->line_length >= sd->line_min_length)
2613 st->info.angle = line->line_angle = angle;
2618 if (line->line_angle < 0.0) /* it's not a line, too short
2619 * more close to a tap */
2621 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
2622 &st->info, EINA_FALSE);
2623 _event_consume(sd, event_info, event_type, ev_flag);
2629 /* Count how many lines already started / ended */
2632 unsigned int tm_start = pe->timestamp;
2633 unsigned int tm_end = pe->timestamp;
2636 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2637 Eina_Bool lines_parallel = EINA_TRUE;
2638 EINA_LIST_FOREACH (list, l, t_line)
2641 base_angle = t_line->line_angle;
2644 if (t_line->line_angle >= 0) /* Compare angle only with
2645 * lines with direction
2648 if (fabs(base_angle - t_line->line_angle) >
2649 sd->line_angular_tolerance)
2650 lines_parallel = EINA_FALSE;
2654 if (t_line->line_length) /* update only if this line is used */
2656 if (shortest_line_len > t_line->line_length)
2657 shortest_line_len = t_line->line_length;
2659 if (longest_line_len < t_line->line_length)
2660 longest_line_len = t_line->line_length;
2666 if (t_line->t_st < tm_start)
2667 tm_start = t_line->t_st;
2673 if (t_line->t_end < tm_end)
2674 tm_end = t_line->t_end;
2678 st->info.momentum.n = started;
2681 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2682 /* user lift one finger then starts again without line-end - ABORT */
2683 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2685 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2687 _event_consume(sd, event_info, event_type, ev_flag);
2691 if (!lines_parallel) /* Lines are NOT at same direction, abort this
2694 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2696 _event_consume(sd, event_info, event_type, ev_flag);
2700 /* We report ABORT if lines length are NOT matching when fingers are up */
2701 if ((longest_line_len - shortest_line_len) >
2702 (elm_config_finger_size_get() * 2))
2704 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2706 _event_consume(sd, event_info, event_type, ev_flag);
2710 /* We consider FLICK as a fast line.ABORT if take too long to finish */
2711 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) >
2712 sd->flick_time_limit_ms))
2714 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2716 _event_consume(sd, event_info, event_type, ev_flag);
2722 case EVAS_CALLBACK_MOUSE_UP:
2723 case EVAS_CALLBACK_MULTI_UP:
2724 if ((started) && (started == ended))
2726 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2727 &st->info, EINA_FALSE);
2728 _event_consume(sd, event_info, event_type, ev_flag);
2733 case EVAS_CALLBACK_MOUSE_DOWN:
2734 case EVAS_CALLBACK_MULTI_DOWN:
2735 case EVAS_CALLBACK_MOUSE_MOVE:
2736 case EVAS_CALLBACK_MULTI_MOVE:
2739 /* For continues gesture */
2740 if (sd->glayer_continues_enable && (started == ended))
2742 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
2743 &st->info, EINA_FALSE);
2744 _event_consume(sd, event_info, event_type, ev_flag);
2747 { /* When continues, may START on MOVE event too */
2748 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2750 /* This happens when: on n > 1 lines then one finger up */
2751 /* caused abort, then put finger down. */
2752 /* This will stop line from starting again. */
2753 /* Number of lines, MUST match touched-device in list */
2754 if ((!sd->glayer_continues_enable) &&
2755 (eina_list_count(st->list) <
2756 eina_list_count(sd->touched)))
2757 s = ELM_GESTURE_STATE_ABORT;
2759 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2760 s = ELM_GESTURE_STATE_START;
2762 ev_flag = _state_set(gesture, s, &st->info, EINA_TRUE);
2763 _event_consume(sd, event_info, event_type, ev_flag);
2769 return; /* Unhandeld event type */
2776 * This function is used to check if rotation gesture started.
2777 * @param st Contains current rotation values from user input.
2778 * @return TRUE/FALSE if we need to set rotation START.
2780 * @ingroup Elm_Gesture_Layer
2783 _on_rotation_broke_tolerance(Rotate_Type *st)
2785 if (st->info.base_angle < 0)
2786 return EINA_FALSE; /* Angle has to be computed first */
2788 if (st->rotate_angular_tolerance < 0)
2791 double low = st->info.base_angle - st->rotate_angular_tolerance;
2792 double high = st->info.base_angle + st->rotate_angular_tolerance;
2793 double t = st->info.angle;
2817 if ((t < low) || (t > high)) /* This marks that roation action has
2820 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2821 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2831 * This function is used for computing the gap between fingers.
2832 * It returns the length and center point between fingers.
2834 * @param x1 first finger x location.
2835 * @param y1 first finger y location.
2836 * @param x2 second finger x location.
2837 * @param y2 second finger y location.
2838 * @param x Gets center point x cord (output)
2839 * @param y Gets center point y cord (output)
2841 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2843 * @ingroup Elm_Gesture_Layer
2846 _finger_gap_length_get(Evas_Coord xx1,
2853 double a, b, xx, yy, gap;
2854 xx = fabs(xx2 - xx1);
2855 yy = fabs(yy2 - yy1);
2856 gap = sqrt((xx * xx) + (yy * yy));
2858 /* START - Compute zoom center point */
2859 /* The triangle defined as follows:
2867 * http://en.wikipedia.org/wiki/Trigonometric_functions
2868 *************************************/
2869 if (((int)xx) && ((int)yy))
2871 double A = atan((yy / xx));
2872 a = (Evas_Coord)((gap / 2) * sin(A));
2873 b = (Evas_Coord)((gap / 2) * cos(A));
2874 *x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
2875 *y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
2879 if ((int)xx) /* horiz line, take half width */
2881 *x = (Evas_Coord)((xx1 + xx2) / 2);
2882 *y = (Evas_Coord)(yy1);
2885 if ((int)yy) /* vert line, take half width */
2887 *x = (Evas_Coord)(xx1);
2888 *y = (Evas_Coord)((yy1 + yy2) / 2);
2891 /* END - Compute zoom center point */
2893 return (Evas_Coord)gap;
2899 * This function is used for computing zoom value.
2901 * @param st Pointer to zoom data based on user input.
2902 * @param tm_end Recent input event timestamp.
2903 * @param zoom_val Current computed zoom value.
2905 * @return zoom momentum
2907 * @ingroup Elm_Gesture_Layer
2910 _zoom_momentum_get(Zoom_Type *st,
2911 unsigned int tm_end,
2914 unsigned int tm_total;
2915 if (!st->m_st_tm) /* Init, and we don't start computing momentum yet */
2917 st->m_st_tm = st->m_prev_tm = tm_end;
2918 st->m_base = zoom_val;
2922 if ((tm_end - ELM_GESTURE_MOMENTUM_DELAY) < st->m_st_tm)
2923 return 0.0; /* we don't start to compute momentum yet */
2925 if (st->dir) /* if direction was already defined, check if changed */
2927 if (((st->dir < 0) && (zoom_val > st->info.zoom)) ||
2928 /* Direction changed, reset momentum */
2929 ((st->dir > 0) && (zoom_val < st->info.zoom)))
2932 st->dir = (-st->dir);
2937 st->dir = (zoom_val > st->info.zoom) ? 1 : -1; /* init */
2939 if ((tm_end - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->m_prev_tm)
2941 st->m_st_tm = 0; /* Rest momentum when waiting too long */
2945 st->m_prev_tm = tm_end;
2946 tm_total = tm_end - st->m_st_tm;
2949 return ((zoom_val - st->m_base) * 1000) / tm_total;
2957 * This function is used for computing zoom value.
2959 * @param st Pointer to zoom data based on user input.
2960 * @param x1 first finger x location.
2961 * @param y1 first finger y location.
2962 * @param x2 second finger x location.
2963 * @param y2 second finger y location.
2964 * @param factor zoom-factor, used to determine how fast zoom works.
2966 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2968 * @ingroup Elm_Gesture_Layer
2971 _zoom_compute(Zoom_Type *st,
2976 double zoom_finger_factor)
2979 unsigned int tm_end = (st->zoom_mv.timestamp > st->zoom_mv1.timestamp) ?
2980 st->zoom_mv.timestamp : st->zoom_mv1.timestamp;
2982 Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
2983 &st->info.x, &st->info.y);
2985 st->info.radius = diam / 2;
2989 st->zoom_base = diam;
2990 return st->info.zoom;
2993 if (st->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
2994 * zoom action NOT started yet */
2996 /* avoid jump with zoom value when break tolerance */
2997 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2999 st->zoom_base -= st->zoom_distance_tolerance;
3000 st->zoom_distance_tolerance = 0;
3003 /* avoid jump with zoom value when break tolerance */
3004 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
3006 st->zoom_base += st->zoom_distance_tolerance;
3007 st->zoom_distance_tolerance = 0;
3013 /* We use factor only on the difference between gap-base */
3014 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
3015 rt = ((1.0) + ((((float)diam - (float)st->zoom_base) /
3016 (float)st->zoom_base) * zoom_finger_factor));
3018 /* Momentum: zoom per second: */
3019 st->info.momentum = _zoom_momentum_get(st, tm_end, rt);
3027 * This function handles zoom with mouse wheel.
3028 * thats a combination of wheel + CTRL key.
3029 * @param obj The gesture-layer object.
3030 * @param event_info Original input event pointer.
3031 * @param event_type Type of original input event.
3032 * @param g_type what Gesture we are testing.
3034 * @ingroup Elm_Gesture_Layer
3037 _zoom_with_wheel_test(Evas_Object *obj,
3039 Evas_Callback_Type event_type,
3040 Elm_Gesture_Type g_type)
3042 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3044 if (!sd->gesture[g_type]) return;
3046 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3047 Zoom_Type *st = gesture_zoom->data;
3048 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3049 if (!st) /* Allocated once on first time, used for zoom intermediate data */
3051 st = calloc(1, sizeof(Zoom_Type));
3052 gesture_zoom->data = st;
3053 _zoom_test_reset(gesture_zoom);
3058 case EVAS_CALLBACK_KEY_UP:
3060 Evas_Event_Key_Up *p = event_info;
3061 if ((!strcmp(p->keyname, "Control_L")) ||
3062 /* Test if we ended a zoom gesture when releasing CTRL */
3063 (!strcmp(p->keyname, "Control_R")))
3065 if ((st->zoom_wheel) &&
3066 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3067 /* User released CTRL after zooming */
3068 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3070 st->info.momentum = _zoom_momentum_get
3071 (st, p->timestamp, st->info.zoom);
3073 ev_flag = _state_set
3074 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3076 _event_consume(sd, event_info, event_type, ev_flag);
3084 case EVAS_CALLBACK_MOUSE_WHEEL:
3087 Elm_Gesture_State s;
3088 if (!evas_key_modifier_is_set(
3089 ((Evas_Event_Mouse_Wheel *)event_info)->modifiers,
3090 "Control")) /* if using wheel witout CTRL after starting zoom */
3092 if ((st->zoom_wheel) &&
3093 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
3094 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
3096 ev_flag = _state_set
3097 (gesture_zoom, ELM_GESTURE_STATE_END, &st->info,
3099 _event_consume(sd, event_info, event_type, ev_flag);
3104 return; /* Ignore mouse-wheel without control */
3107 /* Using mouse wheel with CTRL for zoom */
3108 /* (zoom_wheel == NULL) and (zoom_distance_tolerance == 0) we
3109 * continue a zoom gesture */
3110 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
3113 s = ELM_GESTURE_STATE_MOVE;
3116 { /* On first wheel event, report START */
3117 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
3118 evas_object_evas_get(sd->target), "Control");
3120 s = ELM_GESTURE_STATE_START;
3121 if (!evas_object_key_grab
3122 (sd->target, "Control_L", mask, 0, EINA_FALSE))
3123 ERR("Failed to Grabbed CTRL_L");
3124 if (!evas_object_key_grab
3125 (sd->target, "Control_R", mask, 0, EINA_FALSE))
3126 ERR("Failed to Grabbed CTRL_R");
3129 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
3130 st->zoom_wheel = (Evas_Event_Mouse_Wheel *)event_info;
3131 st->info.x = st->zoom_wheel->canvas.x;
3132 st->info.y = st->zoom_wheel->canvas.y;
3134 if (st->zoom_wheel->z < 0) /* zoom in */
3135 st->info.zoom += (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3137 if (st->zoom_wheel->z > 0) /* zoom out */
3138 st->info.zoom -= (sd->zoom_finger_factor * sd->zoom_wheel_factor);
3140 if (st->info.zoom < 0.0)
3141 st->info.zoom = 0.0;
3143 st->info.momentum = _zoom_momentum_get
3144 (st, st->zoom_wheel->timestamp, st->info.zoom);
3146 ev_flag = _state_set(gesture_zoom, s, &st->info, force);
3147 _event_consume(sd, event_info, event_type, ev_flag);
3159 * This function is used to test zoom gesture.
3160 * user may combine zoom, rotation together.
3161 * so its possible that both will be detected from input.
3162 * (both are two-finger movement-oriented gestures)
3164 * @param obj The gesture-layer object.
3165 * @param event_info Pointer to recent input event.
3166 * @param event_type Recent input event type.
3167 * @param g_type what Gesture we are testing.
3169 * @ingroup Elm_Gesture_Layer
3172 _zoom_test(Evas_Object *obj,
3175 Evas_Callback_Type event_type,
3176 Elm_Gesture_Type g_type)
3178 /* Test for wheel zoom. */
3179 _zoom_with_wheel_test(obj, event_info, event_type, ELM_GESTURE_ZOOM);
3181 if (!_elm_config->glayer_zoom_finger_enable)
3186 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3188 if (!sd->gesture[g_type]) return;
3190 Gesture_Info *gesture_zoom = sd->gesture[g_type];
3191 Zoom_Type *st = gesture_zoom->data;
3193 if (!st) /* Allocated once on first time, used for zoom data */
3195 st = calloc(1, sizeof(Zoom_Type));
3196 gesture_zoom->data = st;
3197 _zoom_test_reset(gesture_zoom);
3200 /* Start - new zoom testing, letting all fingers start */
3201 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3204 case EVAS_CALLBACK_MOUSE_MOVE:
3205 case EVAS_CALLBACK_MULTI_MOVE:
3206 /* if non-continues mode and gesture NOT started, ignore MOVE */
3207 if ((!sd->glayer_continues_enable) &&
3208 (!st->zoom_st.timestamp))
3211 case EVAS_CALLBACK_MOUSE_DOWN:
3212 case EVAS_CALLBACK_MULTI_DOWN:
3213 { /* Here we take care of zoom-start and zoom move */
3217 if (eina_list_count(sd->touched) > 2) /* Process zoom only
3221 ev_flag = _state_set
3222 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3224 _event_consume(sd, event_info, event_type, ev_flag);
3229 if (!st->zoom_st.timestamp) /* Now scan touched-devices list
3230 * and find other finger */
3232 EINA_LIST_FOREACH (sd->touched, l, p)
3233 { /* Device of other finger <> pe device */
3234 if (p->device != pe->device)
3238 if (!p) /* Single finger on touch */
3241 /* Record down fingers */
3242 _event_consume(sd, event_info, event_type, ev_flag);
3243 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
3244 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
3246 /* Set mv field as well to be ready for MOVE events */
3247 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3248 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
3250 /* Here we have zoom_st, zoom_st1 set, report START */
3251 /* Set zoom-base after BOTH down events recorded */
3252 /* Compute length of line between fingers zoom start */
3253 st->info.zoom = 1.0;
3254 st->zoom_base = _finger_gap_length_get
3255 (st->zoom_st1.x, st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
3256 &st->info.x, &st->info.y);
3258 st->info.radius = st->zoom_base / 2;
3260 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
3261 /* zoom started with mouse-wheel, don't report twice */
3262 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
3264 ev_flag = _state_set
3265 (gesture_zoom, ELM_GESTURE_STATE_START, &st->info,
3267 _event_consume(sd, event_info, event_type, ev_flag);
3270 return; /* Zoom started */
3271 } /* End of ZOOM_START handling */
3273 /* if we got here, we have (exacally) two fingers on surfce */
3274 /* we also after START, report MOVE */
3275 /* First detect which finger moved */
3276 if (pe->device == st->zoom_mv.device)
3277 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
3278 else if (pe->device == st->zoom_mv1.device)
3279 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
3281 /* Compute change in zoom as fingers move */
3282 st->info.zoom = _zoom_compute(st,
3283 st->zoom_mv.x, st->zoom_mv.y,
3284 st->zoom_mv1.x, st->zoom_mv1.y,
3285 sd->zoom_finger_factor);
3287 if (!st->zoom_distance_tolerance) /* Zoom broke tolerance,
3290 double d = st->info.zoom - st->next_step;
3294 if (d >= sd->zoom_step) /* Report move in steps */
3296 st->next_step = st->info.zoom;
3298 ev_flag = _state_set(gesture_zoom,
3299 ELM_GESTURE_STATE_MOVE,
3300 &st->info, EINA_TRUE);
3301 _event_consume(sd, event_info, event_type, ev_flag);
3303 } /* End of ZOOM_MOVE handling */
3308 case EVAS_CALLBACK_MOUSE_UP:
3309 case EVAS_CALLBACK_MULTI_UP:
3310 /* Reset timestamp of finger-up.This is used later
3311 by _zoom_test_reset() to retain finger-down data */
3312 _event_consume(sd, event_info, event_type, ev_flag);
3313 if (((st->zoom_wheel) || (st->zoom_base)) &&
3314 (st->zoom_distance_tolerance == 0))
3316 ev_flag = _state_set(gesture_zoom, ELM_GESTURE_STATE_END,
3317 &st->info, EINA_FALSE);
3318 _event_consume(sd, event_info, event_type, ev_flag);
3323 /* if we got here not a ZOOM */
3324 /* Must be != undefined, if gesture started */
3325 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
3327 ev_flag = _state_set
3328 (gesture_zoom, ELM_GESTURE_STATE_ABORT, &st->info,
3330 _event_consume(sd, event_info, event_type, ev_flag);
3333 _zoom_test_reset(gesture_zoom);
3343 _rotate_properties_get(Rotate_Type *st,
3350 /* FIXME: Fix momentum computation, it's wrong */
3351 double prev_angle = *angle;
3353 st->info.radius = _finger_gap_length_get(xx1, yy1, xx2, yy2,
3354 &st->info.x, &st->info.y) / 2;
3356 *angle = _angle_get(xx1, yy1, xx2, yy2);
3358 if (angle == &st->info.angle) /* Fingers are moving, compute momentum */
3360 unsigned int tm_start =
3361 (st->rotate_st.timestamp > st->rotate_st1.timestamp)
3362 ? st->rotate_st.timestamp : st->rotate_st1.timestamp;
3363 unsigned int tm_end =
3364 (st->rotate_mv.timestamp > st->rotate_mv1.timestamp)
3365 ? st->rotate_mv.timestamp : st->rotate_mv1.timestamp;
3367 unsigned int tm_total = tm_end - tm_start;
3368 if (tm_total) /* Momentum computed as:
3369 accumulated roation angle (deg) divided by time */
3372 if (((prev_angle < 90) && ((*angle) > 270)) ||
3373 /* We circle passing ZERO point */
3374 ((prev_angle > 270) && ((*angle) < 90)))
3376 prev_angle = (*angle);
3378 else m = prev_angle - (*angle);
3380 st->accum_momentum += m;
3382 if ((tm_end - st->prev_momentum_tm) < 100)
3383 st->prev_momentum += m;
3386 if (fabs(st->prev_momentum) < 0.002)
3387 st->accum_momentum = 0.0; /* reset momentum */
3389 st->prev_momentum = 0.0; /* Start again */
3392 st->prev_momentum_tm = tm_end;
3393 st->info.momentum = (st->accum_momentum * 1000) / tm_total;
3397 st->info.momentum = 0;
3403 * This function is used to test rotation gesture.
3404 * user may combine zoom, rotation together.
3405 * so its possible that both will be detected from input.
3406 * (both are two-finger movement-oriented gestures)
3408 * @param obj The gesture-layer object.
3409 * @param event_info Pointer to recent input event.
3410 * @param event_type Recent input event type.
3411 * @param g_type what Gesture we are testing.
3413 * @ingroup Elm_Gesture_Layer
3416 _rotate_test(Evas_Object *obj,
3419 Evas_Callback_Type event_type,
3420 Elm_Gesture_Type g_type)
3422 if (!_elm_config->glayer_rotate_finger_enable)
3428 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3430 if (!sd->gesture[g_type]) return;
3432 Gesture_Info *gesture = sd->gesture[g_type];
3437 if (!st) /* Allocated once on first time */
3439 st = calloc(1, sizeof(Rotate_Type));
3441 _rotate_test_reset(gesture);
3445 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
3448 case EVAS_CALLBACK_MOUSE_MOVE:
3449 case EVAS_CALLBACK_MULTI_MOVE:
3450 /* if non-continues mode and gesture NOT started, ignore MOVE */
3451 if ((!sd->glayer_continues_enable) &&
3452 (!st->rotate_st.timestamp))
3455 case EVAS_CALLBACK_MOUSE_DOWN:
3456 case EVAS_CALLBACK_MULTI_DOWN:
3457 { /* Here we take care of rotate-start and rotate move */
3461 if (eina_list_count(sd->touched) > 2) /* Process rotate only
3465 ev_flag = _state_set
3466 (gesture, ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
3467 _event_consume(sd, event_info, event_type, ev_flag);
3472 if (!st->rotate_st.timestamp) /* Now scan touched-devices list
3473 * and find other finger */
3475 EINA_LIST_FOREACH (sd->touched, l, p)
3476 { /* Device of other finger <> pe device */
3477 if (p->device != pe->device)
3482 return; /* Single finger on touch */
3484 /* Record down fingers */
3485 _event_consume(sd, event_info, event_type, ev_flag);
3486 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
3487 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
3489 /* Set mv field as well to be ready for MOVE events */
3490 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3491 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
3493 /* Here we have rotate_st, rotate_st1 set, report START */
3494 /* Set rotate-base after BOTH down events recorded */
3495 /* Compute length of line between fingers rotate start */
3496 _rotate_properties_get(st,
3497 st->rotate_st.x, st->rotate_st.y,
3498 st->rotate_st1.x, st->rotate_st1.y,
3499 &st->info.base_angle);
3501 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_START,
3502 &st->info, EINA_FALSE);
3503 _event_consume(sd, event_info, event_type, ev_flag);
3505 return; /* Rotate started */
3506 } /* End of ROTATE_START handling */
3508 /* if we got here, we have (exacally) two fingers on surfce */
3509 /* we also after START, report MOVE */
3510 /* First detect which finger moved */
3511 if (pe->device == st->rotate_mv.device)
3512 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
3513 else if (pe->device == st->rotate_mv1.device)
3514 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
3516 /* Compute change in rotate as fingers move */
3517 _rotate_properties_get(st,
3518 st->rotate_mv.x, st->rotate_mv.y,
3519 st->rotate_mv1.x, st->rotate_mv1.y,
3522 if (_on_rotation_broke_tolerance(st)) /* Rotation broke
3526 double d = st->info.angle - st->next_step;
3530 if (d >= sd->rotate_step) /* Report move in steps */
3532 st->next_step = st->info.angle;
3534 ev_flag = _state_set
3535 (gesture, ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
3536 _event_consume(sd, event_info, event_type, ev_flag);
3538 } /* End of ROTATE_MOVE handling */
3543 case EVAS_CALLBACK_MOUSE_UP:
3544 case EVAS_CALLBACK_MULTI_UP:
3545 _event_consume(sd, event_info, event_type, ev_flag);
3546 /* Reset timestamp of finger-up.This is used later
3547 by rotate_test_reset() to retain finger-down data */
3548 if (st->rotate_angular_tolerance < 0)
3550 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_END,
3551 &st->info, EINA_FALSE);
3552 _event_consume(sd, event_info, event_type, ev_flag);
3557 /* Must be != undefined, if gesture started */
3558 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
3560 ev_flag = _state_set(gesture, ELM_GESTURE_STATE_ABORT,
3561 &st->info, EINA_FALSE);
3562 _event_consume(sd, event_info, event_type, ev_flag);
3565 _rotate_test_reset(gesture);
3574 _elm_gesture_layer_smart_disable(Evas_Object *obj)
3576 if (elm_widget_disabled_get(obj))
3577 _callbacks_unregister(obj);
3579 _callbacks_register(obj);
3585 _elm_gesture_layer_smart_add(Evas_Object *obj)
3587 EVAS_SMART_DATA_ALLOC(obj, Elm_Gesture_Layer_Smart_Data);
3589 _elm_gesture_layer_parent_sc->base.add(obj);
3591 priv->target = NULL;
3592 priv->line_min_length =
3593 _elm_config->glayer_line_min_length * elm_config_finger_size_get();
3594 priv->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance
3595 * elm_config_finger_size_get();
3596 priv->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance
3597 * elm_config_finger_size_get();
3598 priv->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3599 /* mouse wheel zoom steps */
3600 priv->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor;
3601 priv->rotate_angular_tolerance =
3602 _elm_config->glayer_rotate_angular_tolerance;
3603 priv->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3604 priv->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3605 priv->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3606 priv->repeat_events = EINA_TRUE;
3607 priv->glayer_continues_enable = _elm_config->glayer_continues_enable;
3609 /* FIXME: Hack to get around old configs - if too small, enlarge. */
3610 if (_elm_config->glayer_double_tap_timeout < 0.00001)
3611 _elm_config->glayer_double_tap_timeout = 0.25;
3613 memset(priv->gesture, 0, sizeof(priv->gesture));
3617 _elm_gesture_layer_smart_del(Evas_Object *obj)
3619 Pointer_Event *data;
3622 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3624 _event_history_clear(obj);
3625 eina_list_free(sd->pending);
3627 EINA_LIST_FREE (sd->touched, data)
3630 if (!elm_widget_disabled_get(obj))
3631 _callbacks_unregister(obj);
3633 /* Free all gestures internal data structures */
3634 for (i = 0; i < ELM_GESTURE_LAST; i++)
3637 if (sd->gesture[i]->data)
3638 free(sd->gesture[i]->data);
3640 free(sd->gesture[i]);
3643 _elm_gesture_layer_parent_sc->base.del(obj); /* handles freeing sd */
3647 _elm_gesture_layer_smart_set_user(Elm_Widget_Smart_Class *sc)
3649 sc->base.add = _elm_gesture_layer_smart_add;
3650 sc->base.del = _elm_gesture_layer_smart_del;
3652 sc->disable = _elm_gesture_layer_smart_disable;
3656 elm_gesture_layer_add(Evas_Object *parent)
3661 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3663 e = evas_object_evas_get(parent);
3664 if (!e) return NULL;
3666 obj = evas_object_smart_add(e, _elm_gesture_layer_smart_class_new());
3668 if (!elm_widget_sub_object_add(parent, obj))
3669 ERR("could not add %p as sub object of %p", obj, parent);
3675 elm_gesture_layer_hold_events_get(const Evas_Object *obj)
3677 ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3678 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3680 return !sd->repeat_events;
3684 elm_gesture_layer_hold_events_set(Evas_Object *obj,
3685 Eina_Bool hold_events)
3687 ELM_GESTURE_LAYER_CHECK(obj);
3688 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3690 sd->repeat_events = !(!!hold_events);
3694 elm_gesture_layer_zoom_step_get(const Evas_Object *obj)
3696 ELM_GESTURE_LAYER_CHECK(obj) 0;
3697 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3699 return sd->zoom_step;
3703 elm_gesture_layer_zoom_step_set(Evas_Object *obj,
3706 ELM_GESTURE_LAYER_CHECK(obj);
3707 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3709 if (step < 0) return;
3711 sd->zoom_step = step;
3715 elm_gesture_layer_rotate_step_get(const Evas_Object *obj)
3717 ELM_GESTURE_LAYER_CHECK(obj) 0;
3718 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3720 return sd->rotate_step;
3724 elm_gesture_layer_rotate_step_set(Evas_Object *obj,
3727 ELM_GESTURE_LAYER_CHECK(obj);
3728 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3730 if (step < 0) return;
3732 sd->rotate_step = step;
3736 elm_gesture_layer_attach(Evas_Object *obj,
3737 Evas_Object *target)
3739 ELM_GESTURE_LAYER_CHECK(obj) EINA_FALSE;
3740 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3742 if (!target) return EINA_FALSE;
3744 /* if was attached before, unregister callbacks first */
3746 _callbacks_unregister(obj);
3748 sd->target = target;
3750 _callbacks_register(obj);
3755 elm_gesture_layer_cb_set(Evas_Object *obj,
3756 Elm_Gesture_Type idx,
3757 Elm_Gesture_State cb_type,
3758 Elm_Gesture_Event_Cb cb,
3763 ELM_GESTURE_LAYER_CHECK(obj);
3764 ELM_GESTURE_LAYER_DATA_GET(obj, sd);
3766 if (!sd->gesture[idx])
3767 sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3768 if (!sd->gesture[idx]) return;
3770 p = sd->gesture[idx];
3773 p->fn[cb_type].cb = cb;
3774 p->fn[cb_type].user_data = data;
3775 p->state = ELM_GESTURE_STATE_UNDEFINED;