1 #include <Elementary.h>
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
10 #define ELM_GESTURE_MULTI_TIMEOUT 50
11 #define ELM_GESTURE_MINIMUM_MOMENTUM 0.001
13 /* Some Trigo values */
14 #define RAD_90DEG M_PI_2
15 #define RAD_180DEG M_PI
16 #define RAD_270DEG (M_PI_2 * 3)
17 #define RAD_360DEG (M_PI * 2)
18 /* #define DEBUG_GESTURE_LAYER 1 */
21 _glayer_bufdup(void *buf, size_t size)
28 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
31 #define SET_TEST_BIT(P) do { \
32 P->test = P->fn[ELM_GESTURE_STATE_START].cb || P->fn[ELM_GESTURE_STATE_MOVE].cb || P->fn[ELM_GESTURE_STATE_END].cb || P->fn[ELM_GESTURE_STATE_ABORT].cb; \
35 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
41 * Struct holds callback information.
43 * @ingroup Elm_Gesture_Layer
47 void *user_data; /**< Holds user data to CB (like sd) */
48 Elm_Gesture_Event_Cb cb;
55 * type for callback information
57 * @ingroup Elm_Gesture_Layer
59 typedef struct _Func_Data Func_Data;
64 * @struct _Gesture_Info
65 * Struct holds gesture info
67 * @ingroup Elm_Gesture_Layer
72 void *data; /**< Holds gesture intemidiate processing data */
73 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
74 Elm_Gesture_Types g_type; /**< gesture type */
75 Elm_Gesture_State state; /**< gesture state */
76 void *info; /**< Data for the state callback */
77 Eina_Bool test; /**< if true this gesture should be tested on input */
83 * @typedef Gesture_Info
84 * Type for _Gesture_Info
86 * @ingroup Elm_Gesture_Layer
88 typedef struct _Gesture_Info Gesture_Info;
93 * @struct _Event_History
94 * Struct holds event history.
95 * These events are repeated if no gesture found.
97 * @ingroup Elm_Gesture_Layer
103 Evas_Callback_Type event_type;
109 * @typedef Event_History
110 * Type for _Event_History
112 * @ingroup Elm_Gesture_Layer
114 typedef struct _Event_History Event_History;
119 * @struct _Pointer_Event
120 * Struct holds pointer-event info
121 * This is a generic pointer event structure
123 * @ingroup Elm_Gesture_Layer
125 struct _Pointer_Event
128 unsigned int timestamp;
130 Evas_Callback_Type event_type;
136 * @typedef Pointer_Event
137 * Type for generic pointer event structure
139 * @ingroup Elm_Gesture_Layer
141 typedef struct _Pointer_Event Pointer_Event;
143 /* All *Type structs hold result for the user in 'info' field
144 * The rest is gesture processing intermediate data.
145 * NOTE: info field must be FIRST in the struct.
146 * This is used when reporting ABORT in event_history_clear() */
149 Elm_Gesture_Taps_Info info;
152 unsigned int n_taps_needed;
156 typedef struct _Taps_Type Taps_Type;
158 struct _Long_Tap_Type
160 Elm_Gesture_Taps_Info info;
163 unsigned int max_touched;
164 Ecore_Timer *timeout; /* When this expires, long tap STARTed */
167 typedef struct _Long_Tap_Type Long_Tap_Type;
169 struct _Momentum_Type
170 { /* Fields used by _line_test() */
171 Elm_Gesture_Momentum_Info info;
172 Evas_Coord_Point line_st;
173 Evas_Coord_Point line_end;
174 unsigned int t_st_x; /* Time start on X */
175 unsigned int t_st_y; /* Time start on Y */
176 unsigned int t_end; /* Time end */
177 unsigned int t_up; /* Recent up event time */
180 typedef struct _Momentum_Type Momentum_Type;
184 Evas_Coord_Point line_st;
185 Evas_Coord_Point line_end;
186 Evas_Coord line_length;
187 unsigned int t_st; /* Time start */
188 unsigned int t_end; /* Time end */
190 double line_angle; /* Current angle of line */
192 typedef struct _Line_Data Line_Data;
195 { /* Fields used by _line_test() */
196 Elm_Gesture_Line_Info info;
197 Eina_List *list; /* List of Line_Data */
199 typedef struct _Line_Type Line_Type;
202 { /* Fields used by _zoom_test() */
203 Elm_Gesture_Zoom_Info info;
204 Pointer_Event zoom_st;
205 Pointer_Event zoom_mv;
206 Pointer_Event zoom_st1;
207 Pointer_Event zoom_mv1;
208 Evas_Event_Mouse_Wheel *zoom_wheel;
209 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
210 Evas_Coord zoom_distance_tolerance;
211 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
212 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
215 typedef struct _Zoom_Type Zoom_Type;
218 { /* Fields used by _rotation_test() */
219 Elm_Gesture_Rotate_Info info;
220 Pointer_Event rotate_st;
221 Pointer_Event rotate_mv;
222 Pointer_Event rotate_st1;
223 Pointer_Event rotate_mv1;
224 double rotate_angular_tolerance;
226 Elm_Gesture_Momentum_Info momentum1; /* For continues gesture */
227 Elm_Gesture_Momentum_Info momentum2; /* For continues gesture */
229 typedef struct _Rotate_Type Rotate_Type;
233 Evas_Object *target; /* Target Widget */
234 Event_History *event_history_list;
237 Evas_Coord zoom_distance_tolerance;
238 Evas_Coord line_distance_tolerance;
239 double line_angular_tolerance;
240 double zoom_wheel_factor; /* mouse wheel zoom steps */
241 double zoom_finger_factor; /* used for zoom factor */
242 double rotate_angular_tolerance;
243 unsigned int flick_time_limit_ms;
244 double long_tap_start_timeout;
245 Eina_Bool glayer_continues_enable;
250 Gesture_Info *gesture[ELM_GESTURE_LAST];
251 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
252 Eina_List *pending; /* List of devices need to refeed *UP event */
253 Eina_List *touched; /* Information of touched devices */
255 Eina_Bool repeat_events : 1;
257 typedef struct _Widget_Data Widget_Data;
259 static const char *widtype = NULL;
260 static void _del_hook(Evas_Object *obj);
262 static Eina_Bool _event_history_clear(Evas_Object *obj);
263 static void _reset_states(Widget_Data *wd);
264 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
265 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
266 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
267 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
268 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
269 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
270 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
272 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
273 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
274 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
276 /* START - Functions to manage touched-device list */
279 * This function is used to find if device is touched
281 * @ingroup Elm_Gesture_Layer
284 compare_device(const void *data1, const void *data2)
285 { /* Compare the two device numbers */
286 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
292 * Remove Pointer Event from touched device list
293 * @param list Pointer to touched device list.
294 * @param Pointer_Event Pointer to PE.
296 * @ingroup Elm_Gesture_Layer
299 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
301 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
305 return eina_list_remove(list, p);
314 * Recoed Pointer Event in touched device list
315 * Note: This fuction allocates memory for PE event
316 * This memory is released in _remove_touched_device()
317 * @param list Pointer to touched device list.
318 * @param Pointer_Event Pointer to PE.
320 * @ingroup Elm_Gesture_Layer
323 _add_touched_device(Eina_List *list, Pointer_Event *pe)
325 Pointer_Event *p = eina_list_search_unsorted(list, compare_device, pe);
327 { /* We like to track device touch-position, overwrite info */
328 memcpy(p, pe, sizeof(Pointer_Event));
332 if ((pe->event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
333 (pe->event_type == EVAS_CALLBACK_MULTI_DOWN))
334 { /* Add touched device on DOWN event only */
335 p = malloc(sizeof(Pointer_Event));
336 /* Freed in _remove_touched_device() */
337 memcpy(p, pe, sizeof(Pointer_Event));
338 return eina_list_append(list, p);
343 /* END - Functions to manage touched-device list */
349 * @param event_info pointer to event.
351 * @ingroup Elm_Gesture_Layer
353 static Evas_Event_Flags
354 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
358 case EVAS_CALLBACK_MOUSE_IN:
359 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
360 case EVAS_CALLBACK_MOUSE_OUT:
361 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
362 case EVAS_CALLBACK_MOUSE_DOWN:
363 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
364 case EVAS_CALLBACK_MOUSE_MOVE:
365 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
366 case EVAS_CALLBACK_MOUSE_UP:
367 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
368 case EVAS_CALLBACK_MOUSE_WHEEL:
369 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
370 case EVAS_CALLBACK_MULTI_DOWN:
371 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
372 case EVAS_CALLBACK_MULTI_MOVE:
373 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
374 case EVAS_CALLBACK_MULTI_UP:
375 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
376 case EVAS_CALLBACK_KEY_DOWN:
377 return ((Evas_Event_Key_Down *) event_info)->event_flags;
378 case EVAS_CALLBACK_KEY_UP:
379 return ((Evas_Event_Key_Up *) event_info)->event_flags;
381 return EVAS_EVENT_FLAG_NONE;
388 * Sets event flag to value returned from user callback
389 * @param wd Widget Data
390 * @param event_info pointer to event.
391 * @param event_type what type was ev (mouse down, etc...)
392 * @param ev_flags event flags
394 * @ingroup Elm_Gesture_Layer
397 consume_event(Widget_Data *wd, void *event_info,
398 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
399 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
400 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
401 /* should not refeed this event. */
403 return; /* This happens when restarting gestures */
405 if ((ev_flags) || (!wd->repeat_events))
409 case EVAS_CALLBACK_MOUSE_DOWN:
410 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
412 case EVAS_CALLBACK_MOUSE_MOVE:
413 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
415 case EVAS_CALLBACK_MOUSE_UP:
416 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
418 case EVAS_CALLBACK_MOUSE_WHEEL:
419 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
421 case EVAS_CALLBACK_MULTI_DOWN:
422 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
424 case EVAS_CALLBACK_MULTI_MOVE:
425 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
427 case EVAS_CALLBACK_MULTI_UP:
428 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
430 case EVAS_CALLBACK_KEY_DOWN:
431 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
433 case EVAS_CALLBACK_KEY_UP:
434 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
445 * Report current state of a gesture by calling user callback.
446 * @param gesture what gesture state we report.
447 * @param info inforamtion for user callback
449 * @ingroup Elm_Gesture_Layer
451 static Evas_Event_Flags
452 _report_state(Gesture_Info *gesture, void *info)
453 { /* We report current state (START, MOVE, END, ABORT), once */
454 #if defined(DEBUG_GESTURE_LAYER)
455 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, gesture->g_type,
458 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
459 (gesture->fn[gesture->state].cb))
460 { /* Fill state-info struct and send ptr to user callback */
461 return gesture->fn[gesture->state].cb(
462 gesture->fn[gesture->state].user_data, info);
465 return EVAS_EVENT_FLAG_NONE;
471 * Update state for a given gesture.
472 * We may update gesture state to:
473 * UNDEFINED - current input did not start gesure yet.
474 * START - gesture started according to input.
475 * MOVE - gusture in progress.
476 * END - gesture completed according to input.
477 * ABORT - input does not matches gesure.
478 * note that we may move from UNDEFINED to ABORT
479 * because we may detect that gesture will not START
480 * with a given input.
482 * @param g given gesture to change state.
483 * @param s gesure new state.
484 * @param info buffer to be sent to user callback on report_state.
485 * @param force makes report_state to report the new-state even
486 * if its same as current state. Works for MOVE - gesture in progress.
488 * @ingroup Elm_Gesture_Layer
490 static Evas_Event_Flags
491 _set_state(Gesture_Info *g, Elm_Gesture_State s,
492 void *info, Eina_Bool force)
494 Elm_Gesture_State old_state;
495 if ((g->state == s) && (!force))
496 return EVAS_EVENT_FLAG_NONE;
498 old_state = g->state;
501 g->info = info; /* Information for user callback */
502 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
503 (g->state == ELM_GESTURE_STATE_END))
504 g->test = EINA_FALSE;
506 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
507 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
508 (s == ELM_GESTURE_STATE_ABORT))))
509 return _report_state(g, g->info);
511 return EVAS_EVENT_FLAG_NONE;
517 * This resets all gesture states and sets test-bit.
518 * this is used for restarting gestures to listen to input.
519 * happens after we complete a gesture or no gesture was detected.
520 * @param wd Widget data of the gesture-layer object.
522 * @ingroup Elm_Gesture_Layer
525 _reset_states(Widget_Data *wd)
529 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
534 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
543 * if gesture was NOT detected AND we only have gestures in ABORT state
544 * we clear history immediately to be ready for input.
546 * @param obj The gesture-layer object.
547 * @return TRUE on event history_clear
549 * @ingroup Elm_Gesture_Layer
552 _clear_if_finished(Evas_Object *obj)
554 Widget_Data *wd = elm_widget_data_get(obj);
555 if (!wd) return EINA_FALSE;
558 /* Clear history if all we have aborted gestures */
559 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
560 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
561 { /* If no gesture started and all we have aborted gestures, reset all */
562 Gesture_Info *p = wd->gesture[i];
563 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
565 if ((p->state == ELM_GESTURE_STATE_START) ||
566 (p->state == ELM_GESTURE_STATE_MOVE))
567 reset_s = EINA_FALSE;
569 all_undefined = EINA_FALSE;
573 if (reset_s && (!all_undefined))
574 return _event_history_clear(obj);
580 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
582 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
598 /* All *test_reset() funcs are called to clear
599 * gesture intermediate data.
600 * This happens when we need to reset our tests.
601 * for example when gesture is detected or all ABORTed. */
603 _tap_gestures_test_reset(Gesture_Info *gesture)
608 Widget_Data *wd = elm_widget_data_get(gesture->obj);
609 wd->dbl_timeout = NULL;
616 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
617 EINA_LIST_FREE(data, pe)
620 memset(gesture->data, 0, sizeof(Taps_Type));
623 /* All *test_reset() funcs are called to clear
624 * gesture intermediate data.
625 * This happens when we need to reset our tests.
626 * for example when gesture is detected or all ABORTed. */
628 _n_long_tap_test_reset(Gesture_Info *gesture)
636 Long_Tap_Type *st = gesture->data;
639 EINA_LIST_FOREACH(st->touched, l, p)
642 eina_list_free(st->touched);
643 if (st->timeout) ecore_timer_del(st->timeout);
644 memset(gesture->data, 0, sizeof(Long_Tap_Type));
648 _momentum_test_reset(Gesture_Info *gesture)
656 memset(gesture->data, 0, sizeof(Momentum_Type));
660 _line_data_reset(Line_Data *st)
665 memset(st, 0, sizeof(Line_Data));
666 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
670 _line_test_reset(Gesture_Info *gesture)
678 Line_Type *st = gesture->data;
679 Eina_List *list = st->list;
682 EINA_LIST_FOREACH(list, l, t_line)
685 eina_list_free(list);
690 _zoom_test_reset(Gesture_Info *gesture)
698 Widget_Data *wd = elm_widget_data_get(gesture->obj);
699 Zoom_Type *st = gesture->data;
700 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
701 evas_object_evas_get(wd->target), "Control");
702 evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
703 evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
705 memset(st, 0, sizeof(Zoom_Type));
706 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
711 _rotate_test_reset(Gesture_Info *gesture)
719 Widget_Data *wd = elm_widget_data_get(gesture->obj);
720 Rotate_Type *st = gesture->data;
722 memset(st, 0, sizeof(Rotate_Type));
723 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
724 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
731 * We register callbacks when gesture layer is attached to an object
732 * or when its enabled after disable.
734 * @param obj The gesture-layer object.
736 * @ingroup Elm_Gesture_Layer
739 _register_callbacks(Evas_Object *obj)
741 Widget_Data *wd = elm_widget_data_get(obj);
746 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
748 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
750 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
753 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
756 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
758 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
760 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
763 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
765 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
773 * We unregister callbacks when gesture layer is disabled.
775 * @param obj The gesture-layer object.
777 * @ingroup Elm_Gesture_Layer
780 _unregister_callbacks(Evas_Object *obj)
782 Widget_Data *wd = elm_widget_data_get(obj);
787 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
789 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
791 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
794 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
797 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
800 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
803 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
806 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
808 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
813 /* START - Event history list handling functions */
816 * This function is used to find if device number
817 * is found in a list of devices.
818 * The list contains devices for refeeding *UP event
820 * @ingroup Elm_Gesture_Layer
823 device_in_pending_list(const void *data1, const void *data2)
824 { /* Compare the two device numbers */
825 return (((intptr_t) data1) - ((intptr_t) data2));
831 * This functions adds device to refeed-pending device list
832 * @ingroup Elm_Gesture_Layer
835 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
837 int device = ELM_MOUSE_DEVICE;
840 case EVAS_CALLBACK_MOUSE_DOWN:
842 case EVAS_CALLBACK_MULTI_DOWN:
843 device = ((Evas_Event_Multi_Down *) event)->device;
849 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
852 return eina_list_append(list, (intptr_t*) device);
861 * This functions returns pending-device node
862 * @ingroup Elm_Gesture_Layer
865 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
867 int device = ELM_MOUSE_DEVICE;
870 case EVAS_CALLBACK_MOUSE_UP:
872 case EVAS_CALLBACK_MULTI_UP:
873 device = ((Evas_Event_Multi_Up *) event)->device;
879 return eina_list_search_unsorted_list(list, device_in_pending_list,
880 (intptr_t *) device);
886 * This function reports ABORT to all none-detected gestures
887 * Then resets test bits for all desired gesures
888 * and clears input-events history.
889 * note: if no gesture was detected, events from history list
890 * are streamed to the widget because it's unused by layer.
891 * user may cancel refeed of events by setting repeat events.
893 * @param obj The gesture-layer object.
895 * @ingroup Elm_Gesture_Layer
898 _event_history_clear(Evas_Object *obj)
900 Widget_Data *wd = elm_widget_data_get(obj);
901 if (!wd) return EINA_FALSE;
905 Evas *e = evas_object_evas_get(obj);
906 Eina_Bool gesture_found = EINA_FALSE;
907 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
912 if (p->state == ELM_GESTURE_STATE_END)
913 gesture_found = EINA_TRUE;
915 { /* Report ABORT to all gestures that still not finished */
916 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
922 _reset_states(wd); /* we are ready to start testing for gestures again */
924 /* Clear all gestures intermediate data */
925 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
926 { /* We do not clear a long-tap gesture if fingers still on surface */
927 /* and gesture timer still pending to test gesture state */
928 Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data;
929 if ((st) && /* st not allocated if clear occurs before 1st input */
930 ((!eina_list_count(st->touched)) || (!st->timeout)))
931 _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]);
936 ecore_timer_del(wd->dbl_timeout);
937 wd->dbl_timeout = NULL;
940 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
941 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
942 _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
943 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
944 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
945 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
946 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
947 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
949 /* Disable gesture layer so refeeded events won't be consumed by it */
950 _unregister_callbacks(obj);
951 while (wd->event_history_list)
954 t = wd->event_history_list;
955 Eina_List *pending = _device_is_pending(wd->pending,
956 wd->event_history_list->event,
957 wd->event_history_list->event_type);
959 /* Refeed events if no gesture matched input */
960 if (pending || ((!gesture_found) && (!wd->repeat_events)))
962 evas_event_refeed_event(e, wd->event_history_list->event,
963 wd->event_history_list->event_type);
967 wd->pending = eina_list_remove_list(wd->pending, pending);
971 wd->pending = _add_device_pending(wd->pending,
972 wd->event_history_list->event,
973 wd->event_history_list->event_type);
977 free(wd->event_history_list->event);
978 wd->event_history_list = (Event_History *) eina_inlist_remove(
979 EINA_INLIST_GET(wd->event_history_list),
980 EINA_INLIST_GET(wd->event_history_list));
983 _register_callbacks(obj);
990 * This function copies input events.
991 * We copy event info before adding it to history.
992 * The memory is freed when we clear history.
994 * @param event the event to copy
995 * @param event_type event type to copy
997 * @ingroup Elm_Gesture_Layer
1000 _copy_event_info(void *event, Evas_Callback_Type event_type)
1004 case EVAS_CALLBACK_MOUSE_DOWN:
1005 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
1007 case EVAS_CALLBACK_MOUSE_MOVE:
1008 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
1010 case EVAS_CALLBACK_MOUSE_UP:
1011 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
1013 case EVAS_CALLBACK_MOUSE_WHEEL:
1014 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
1016 case EVAS_CALLBACK_MULTI_DOWN:
1017 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
1019 case EVAS_CALLBACK_MULTI_MOVE:
1020 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
1022 case EVAS_CALLBACK_MULTI_UP:
1023 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
1025 case EVAS_CALLBACK_KEY_DOWN:
1026 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
1028 case EVAS_CALLBACK_KEY_UP:
1029 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1037 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1039 Widget_Data *wd = elm_widget_data_get(obj);
1041 if (!wd) return EINA_FALSE;
1043 ev = malloc(sizeof(Event_History));
1044 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1045 ev->event_type = event_type;
1046 wd->event_history_list = (Event_History *) eina_inlist_append(
1047 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1051 /* END - Event history list handling functions */
1054 _del_hook(Evas_Object *obj)
1056 Widget_Data *wd = elm_widget_data_get(obj);
1059 _event_history_clear(obj);
1060 eina_list_free(wd->pending);
1062 Pointer_Event *data;
1063 EINA_LIST_FREE(wd->touched, data)
1066 if (!elm_widget_disabled_get(obj))
1067 _unregister_callbacks(obj);
1069 /* Free all gestures internal data structures */
1071 for (i = 0; i < ELM_GESTURE_LAST; i++)
1074 if (wd->gesture[i]->data)
1075 free(wd->gesture[i]->data);
1077 free(wd->gesture[i]);
1084 compare_match_fingers(const void *data1, const void *data2)
1085 { /* Compare coords of first item in list to cur coords */
1086 const Pointer_Event *pe1 = eina_list_data_get(data1);
1087 const Pointer_Event *pe2 = data2;
1089 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1091 else if (pe1->x < pe2->x)
1095 if (pe1->x == pe2->x)
1096 return pe1->y - pe2->y;
1103 compare_pe_device(const void *data1, const void *data2)
1104 { /* Compare device of first item in list to our pe device */
1105 const Pointer_Event *pe1 = eina_list_data_get(data1);
1106 const Pointer_Event *pe2 = data2;
1108 /* Only match if last was a down event */
1109 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1110 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1114 if (pe1->device == pe2->device)
1116 else if (pe1->device < pe2->device)
1123 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1124 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1125 { /* Keep copy of pe and record it in list */
1126 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1127 memcpy(p, pe, sizeof(Pointer_Event));
1128 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1134 /* This will also update middle-point to report to user later */
1135 st->info.x = st->sum_x / st->n_taps;
1136 st->info.y = st->sum_y / st->n_taps;
1137 st->info.timestamp = pe->timestamp;
1141 pe_list = eina_list_append(pe_list, p);
1142 st->l = eina_list_append(st->l, pe_list);
1145 pe_list = eina_list_append(pe_list, p);
1153 * This function sets state a tap-gesture to END or ABORT
1155 * @param data gesture info pointer
1157 * @ingroup Elm_Gesture_Layer
1160 _tap_gesture_finish(void *data)
1161 { /* This function will test each tap gesture when timer expires */
1162 Gesture_Info *gesture = data;
1163 Elm_Gesture_State s = ELM_GESTURE_STATE_END;
1164 /* Here we check if taps-gesture was completed successfuly */
1165 /* Count how many taps were recieved on each device then */
1166 /* determine if it matches n_taps_needed defined on START */
1167 Taps_Type *st = gesture->data;
1170 EINA_LIST_FOREACH(st->l, l, pe_list)
1172 if (eina_list_count(pe_list) != st->n_taps_needed)
1173 { /* No match taps number on device, ABORT */
1174 s = ELM_GESTURE_STATE_ABORT;
1179 st->info.n = eina_list_count(st->l);
1180 _set_state(gesture, s, gesture->info, EINA_FALSE);
1181 _tap_gestures_test_reset(gesture);
1187 * when this timer expires we finish tap gestures.
1189 * @param data The gesture-layer object.
1190 * @return cancles callback for this timer.
1192 * @ingroup Elm_Gesture_Layer
1195 _multi_tap_timeout(void *data)
1197 Widget_Data *wd = elm_widget_data_get(data);
1198 if (!wd) return EINA_FALSE;
1200 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1201 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]);
1203 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1204 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
1206 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1207 _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
1209 _clear_if_finished(data);
1210 wd->dbl_timeout = NULL;
1211 return ECORE_CALLBACK_CANCEL;
1217 * when this timer expires we START long tap gesture
1219 * @param data The gesture-layer object.
1220 * @return cancles callback for this timer.
1222 * @ingroup Elm_Gesture_Layer
1225 _long_tap_timeout(void *data)
1227 Gesture_Info *gesture = data;
1228 Long_Tap_Type *st = gesture->data;
1231 _set_state(gesture, ELM_GESTURE_STATE_START,
1232 gesture->data, EINA_FALSE);
1234 return ECORE_CALLBACK_CANCEL;
1241 * This function checks if a tap gesture should start
1243 * @param wd Gesture Layer Widget Data.
1244 * @param pe The recent input event as stored in pe struct.
1245 * @param event_info Original input event pointer.
1246 * @param event_type Type of original input event.
1247 * @param gesture what gesture is tested
1248 * @param how many taps for this gesture (1, 2 or 3)
1250 * @return Flag to determine if we need to set a timer for finish
1252 * @ingroup Elm_Gesture_Layer
1255 _tap_gesture_start(Widget_Data *wd, Pointer_Event *pe,
1256 void *event_info, Evas_Callback_Type event_type,
1257 Gesture_Info *gesture, int taps)
1258 { /* Here we fill Tap struct */
1259 Taps_Type *st = gesture->data;
1261 { /* Allocated once on first time */
1262 st = calloc(1, sizeof(Taps_Type));
1264 _tap_gestures_test_reset(gesture);
1267 Eina_List *pe_list = NULL;
1268 Pointer_Event *pe_down = NULL;
1269 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1270 switch (pe->event_type)
1272 case EVAS_CALLBACK_MULTI_DOWN:
1273 case EVAS_CALLBACK_MOUSE_DOWN:
1274 /* Check if got tap on same cord was tapped before */
1275 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1278 eina_list_search_unsorted(st->l, compare_pe_device, pe))
1279 { /* This device was touched in other cord before completion */
1280 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1281 &st->info, EINA_FALSE);
1282 consume_event(wd, event_info, event_type, ev_flag);
1287 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1288 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1289 { /* This is the first mouse down we got */
1290 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1291 &st->info, EINA_FALSE);
1292 consume_event(wd, event_info, event_type, ev_flag);
1294 st->n_taps_needed = taps * 2; /* count DOWN and UP */
1301 case EVAS_CALLBACK_MULTI_UP:
1302 case EVAS_CALLBACK_MOUSE_UP:
1303 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1307 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1310 case EVAS_CALLBACK_MULTI_MOVE:
1311 case EVAS_CALLBACK_MOUSE_MOVE:
1312 /* Get first event in first list, this has to be a Mouse Down event */
1313 /* and verify that user didn't move out of this area before next tap */
1314 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1317 pe_down = eina_list_data_get(pe_list);
1318 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1320 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1321 &st->info, EINA_FALSE);
1322 consume_event(wd, event_info, event_type, ev_flag);
1338 * This function checks all click/tap and double/triple taps
1340 * @param obj The gesture-layer object.
1341 * @param pe The recent input event as stored in pe struct.
1342 * @param event_info Original input event pointer.
1343 * @param event_type Type of original input event.
1345 * @ingroup Elm_Gesture_Layer
1348 _tap_gestures_test(Evas_Object *obj, Pointer_Event *pe,
1349 void *event_info, Evas_Callback_Type event_type)
1350 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1351 Eina_Bool need_timer = EINA_FALSE;
1352 Widget_Data *wd = elm_widget_data_get(obj);
1355 if (!pe) /* this happens when unhandled event arrived */
1356 return; /* see _make_pointer_event function */
1358 if (IS_TESTED(ELM_GESTURE_N_TAPS))
1359 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1360 wd->gesture[ELM_GESTURE_N_TAPS], 1);
1362 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
1363 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1364 wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2);
1366 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
1367 need_timer |= _tap_gesture_start(wd, pe, event_info, event_type,
1368 wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3);
1370 if ((need_timer) && (!wd->dbl_timeout))
1371 { /* Set a timer to finish these gestures */
1372 wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout,
1380 * This function computes center-point for long-tap gesture
1382 * @param st Long Tap gesture info pointer
1383 * @param pe The recent input event as stored in pe struct.
1385 * @ingroup Elm_Gesture_Layer
1388 _compute_taps_center(Long_Tap_Type *st,
1389 Evas_Coord *x_out, Evas_Coord *y_out, Pointer_Event *pe)
1391 if(!eina_list_count(st->touched))
1396 Evas_Coord x = 0, y = 0;
1397 EINA_LIST_FOREACH(st->touched, l, p)
1398 { /* Accumulate all then take avarage */
1399 if (p->device == pe->device)
1400 { /* This will take care of values coming from MOVE event */
1411 *x_out = x / eina_list_count(st->touched);
1412 *y_out = y / eina_list_count(st->touched);
1418 * This function checks N long-tap gesture.
1420 * @param obj The gesture-layer object.
1421 * @param pe The recent input event as stored in pe struct.
1422 * @param event_info Original input event pointer.
1423 * @param event_type Type of original input event.
1424 * @param g_type what Gesture we are testing.
1425 * @param taps How many click/taps we test for.
1427 * @ingroup Elm_Gesture_Layer
1430 _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe,
1431 void *event_info, Evas_Callback_Type event_type,
1432 Elm_Gesture_Types g_type)
1433 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1434 Widget_Data *wd = elm_widget_data_get(obj);
1437 if (!pe) /* this happens when unhandled event arrived */
1438 return; /* see _make_pointer_event function */
1439 Gesture_Info *gesture = wd->gesture[g_type];
1440 if (!gesture) return;
1442 Long_Tap_Type *st = gesture->data;
1444 { /* Allocated once on first time */
1445 st = calloc(1, sizeof(Long_Tap_Type));
1447 _n_long_tap_test_reset(gesture);
1450 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1451 switch (pe->event_type)
1453 case EVAS_CALLBACK_MULTI_DOWN:
1454 case EVAS_CALLBACK_MOUSE_DOWN:
1455 st->touched = _add_touched_device(st->touched, pe);
1456 st->info.n = eina_list_count(st->touched);
1457 if (st->info.n > st->max_touched)
1458 st->max_touched = st->info.n;
1460 { /* User removed finger from touch, then put back - ABORT */
1461 if ((gesture->state == ELM_GESTURE_STATE_START) ||
1462 (gesture->state == ELM_GESTURE_STATE_MOVE))
1464 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1465 &st->info, EINA_FALSE);
1466 consume_event(wd, event_info, event_type, ev_flag);
1470 if ((pe->device == 0) && (eina_list_count(st->touched) == 1))
1471 { /* This is the first mouse down we got */
1472 st->info.timestamp = pe->timestamp;
1474 /* To test long tap */
1475 /* When this timer expires, gesture STARTED */
1477 st->timeout = ecore_timer_add(wd->long_tap_start_timeout,
1478 _long_tap_timeout, gesture);
1481 consume_event(wd, event_info, event_type, ev_flag);
1482 _compute_taps_center(st, &st->info.x, &st->info.y, pe);
1483 st->center_x = st->info.x;
1484 st->center_y = st->info.y;
1487 case EVAS_CALLBACK_MULTI_UP:
1488 case EVAS_CALLBACK_MOUSE_UP:
1489 st->touched = _remove_touched_device(st->touched, pe);
1490 _compute_taps_center(st, &st->center_x, &st->center_y, pe);
1492 ((gesture->state == ELM_GESTURE_STATE_START) ||
1493 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1494 { /* Report END only for gesture that STARTed */
1495 if (eina_list_count(st->touched) == 0)
1496 { /* Report END only at last release event */
1497 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1498 &st->info, EINA_FALSE);
1499 consume_event(wd, event_info, event_type, ev_flag);
1503 { /* Stop test, user lifts finger before long-start */
1504 if (st->timeout) ecore_timer_del(st->timeout);
1506 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT,
1507 &st->info, EINA_FALSE);
1508 consume_event(wd, event_info, event_type, ev_flag);
1513 case EVAS_CALLBACK_MULTI_MOVE:
1514 case EVAS_CALLBACK_MOUSE_MOVE:
1516 ((gesture->state == ELM_GESTURE_STATE_START) ||
1517 (gesture->state == ELM_GESTURE_STATE_MOVE)))
1518 { /* Report MOVE only if STARTED */
1521 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1523 _compute_taps_center(st, &x, &y, pe);
1524 /* ABORT if user moved fingers out of tap area */
1525 #if defined(DEBUG_GESTURE_LAYER)
1526 printf("%s x,y=(%d,%d) st->info.x,st->info.y=(%d,%d)\n",__func__,x,y,st->info.x,st->info.y);
1528 if (!_inside(x, y, st->center_x, st->center_y))
1529 state_to_report = ELM_GESTURE_STATE_ABORT;
1531 /* Report MOVE if gesture started */
1532 ev_flag = _set_state(gesture, state_to_report,
1533 &st->info, EINA_TRUE);
1534 consume_event(wd, event_info, event_type, ev_flag);
1546 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1547 * This momentum value will be sent to widget when gesture is completed.
1549 * @param momentum pointer to buffer where we record momentum value.
1550 * @param x1 x coord where user started gesture.
1551 * @param y1 y coord where user started gesture.
1552 * @param x2 x coord where user completed gesture.
1553 * @param y2 y coord where user completed gesture.
1554 * @param t1x timestamp for X, when user started gesture.
1555 * @param t1y timestamp for Y, when user started gesture.
1556 * @param t2 timestamp when user completed gesture.
1558 * @ingroup Elm_Gesture_Layer
1561 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1562 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1565 Evas_Coord velx = 0, vely = 0, vel;
1566 Evas_Coord dx = x2 - x1;
1567 Evas_Coord dy = y2 - y1;
1571 velx = (dx * 1000) / dtx;
1574 vely = (dy * 1000) / dty;
1576 vel = sqrt((velx * velx) + (vely * vely));
1578 if ((_elm_config->thumbscroll_friction > 0.0) &&
1579 (vel > _elm_config->thumbscroll_momentum_threshold))
1580 { /* report momentum */
1581 momentum->mx = velx;
1582 momentum->my = vely;
1594 * This function is used for computing rotation angle (DEG).
1596 * @param x1 first finger x location.
1597 * @param y1 first finger y location.
1598 * @param x2 second finger x location.
1599 * @param y2 second finger y location.
1601 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1603 * @ingroup Elm_Gesture_Layer
1606 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1612 if (((int) xx) && ((int) yy))
1619 return RAD_360DEG - a;
1630 return RAD_180DEG + a;
1634 return RAD_180DEG - a;
1640 { /* Horizontal line */
1665 * This function is used for computing the magnitude and direction
1666 * of vector between two points.
1668 * @param x1 first finger x location.
1669 * @param y1 first finger y location.
1670 * @param x2 second finger x location.
1671 * @param y2 second finger y location.
1672 * @param l length computed (output)
1673 * @param a angle computed (output)
1675 * @ingroup Elm_Gesture_Layer
1678 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1679 Evas_Coord *l, double *a)
1684 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1685 *a = get_angle(x1, y1, x2, y2);
1689 _get_direction(Evas_Coord x1, Evas_Coord x2)
1701 * This function tests momentum gesture.
1702 * @param obj The gesture-layer object.
1703 * @param pe The recent input event as stored in pe struct.
1704 * @param event_info recent input event.
1705 * @param event_type recent event type.
1706 * @param g_type what Gesture we are testing.
1708 * @ingroup Elm_Gesture_Layer
1711 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1712 void *event_info, Evas_Callback_Type event_type,
1713 Elm_Gesture_Types g_type)
1715 Widget_Data *wd = elm_widget_data_get(obj);
1717 Gesture_Info *gesture = wd->gesture[g_type];
1718 if (!gesture ) return;
1720 /* When continues enable = TRUE a gesture may START on MOVE event */
1721 /* We don't allow this to happen with the if-statement below. */
1722 /* When continues enable = FALSE a gesture may START on DOWN only */
1723 /* Therefor it would NOT start on MOVE event. */
1724 /* NOTE that touched list is updated AFTER this function returns */
1725 /* so (count == 0) when we get here on first touch on surface. */
1726 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1727 return; /* Got move on mouse-over move */
1729 Momentum_Type *st = gesture->data;
1730 Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
1732 { /* Allocated once on first time */
1733 st = calloc(1, sizeof(Momentum_Type));
1735 _momentum_test_reset(gesture);
1741 /* First make avarage of all touched devices to determine center point */
1744 Pointer_Event pe_local = *pe; /* Copy pe event info to local */
1745 unsigned int cnt = 1; /* We start counter counting current pe event */
1746 EINA_LIST_FOREACH(wd->touched, l, p)
1747 if (p->device != pe_local.device)
1755 /* Compute avarage to get center point */
1759 /* If user added finger - reset gesture */
1760 if ((st->info.n) && (st->info.n < cnt))
1761 state_to_report = ELM_GESTURE_STATE_ABORT;
1763 if (st->info.n < cnt)
1766 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1769 case EVAS_CALLBACK_MOUSE_DOWN:
1770 case EVAS_CALLBACK_MULTI_DOWN:
1771 case EVAS_CALLBACK_MOUSE_MOVE:
1772 case EVAS_CALLBACK_MULTI_MOVE:
1775 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1776 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
1777 (wd->glayer_continues_enable)) /* start also on MOVE */
1778 { /* We start on MOVE when cont-enabled only */
1779 st->line_st.x = st->line_end.x = pe_local.x;
1780 st->line_st.y = st->line_end.y = pe_local.y;
1781 st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
1782 st->xdir = st->ydir = 0;
1783 st->info.x2 = st->info.x1 = pe_local.x;
1784 st->info.y2 = st->info.y1 = pe_local.y;
1785 st->info.tx = st->info.ty = pe_local.timestamp;
1786 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1787 &st->info, EINA_FALSE);
1788 consume_event(wd, event_info, event_type, ev_flag);
1795 /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
1797 ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
1798 state_to_report = ELM_GESTURE_STATE_ABORT;
1800 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1801 { /* Too long of a wait, reset all values */
1802 st->line_st.x = pe_local.x;
1803 st->line_st.y = pe_local.y;
1804 st->t_st_y = st->t_st_x = pe_local.timestamp;
1805 st->info.tx = st->t_st_x;
1806 st->info.ty = st->t_st_y;
1807 st->xdir = st->ydir = 0;
1812 xdir = _get_direction(st->line_st.x, pe_local.x);
1813 ydir = _get_direction(st->line_st.y, pe_local.y);
1814 if (!xdir || (xdir == (-st->xdir)))
1816 st->line_st.x = st->line_end.x;
1817 st->info.tx = st->t_st_x = st->t_end;
1821 if (!ydir || (ydir == (-st->ydir)))
1823 st->line_st.y = st->line_end.y;
1824 st->info.ty = st->t_st_y = st->t_end;
1829 st->info.x2 = st->line_end.x = pe_local.x;
1830 st->info.y2 = st->line_end.y = pe_local.y;
1831 st->t_end = pe_local.timestamp;
1832 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1833 st->t_st_x, st->t_st_y, pe_local.timestamp);
1834 ev_flag = _set_state(gesture, state_to_report, &st->info,
1836 consume_event(wd, event_info, event_type, ev_flag);
1840 case EVAS_CALLBACK_MOUSE_UP:
1841 case EVAS_CALLBACK_MULTI_UP:
1842 st->t_up = pe_local.timestamp; /* Record recent up event time */
1843 if ((cnt > 1) || /* Ignore if more fingers touch surface */
1844 (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
1847 if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1848 { /* Too long of a wait, reset all values */
1849 st->line_st.x = pe_local.x;
1850 st->line_st.y = pe_local.y;
1851 st->t_st_y = st->t_st_x = pe_local.timestamp;
1852 st->xdir = st->ydir = 0;
1855 st->info.x2 = pe_local.x;
1856 st->info.y2 = pe_local.y;
1857 st->line_end.x = pe_local.x;
1858 st->line_end.y = pe_local.y;
1859 st->t_end = pe_local.timestamp;
1861 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
1862 st->t_st_x, st->t_st_y, pe_local.timestamp);
1864 if ((fabs(st->info.mx) > ELM_GESTURE_MINIMUM_MOMENTUM) ||
1865 (fabs(st->info.my) > ELM_GESTURE_MINIMUM_MOMENTUM))
1866 state_to_report = ELM_GESTURE_STATE_END;
1868 state_to_report = ELM_GESTURE_STATE_ABORT;
1870 ev_flag = _set_state(gesture, state_to_report, &st->info,
1872 consume_event(wd, event_info, event_type, ev_flag);
1881 compare_line_device(const void *data1, const void *data2)
1882 { /* Compare device component of line struct */
1883 const Line_Data *ln1 = data1;
1884 const int *device = data2;
1886 if (ln1->t_st) /* Compare only with lines that started */
1887 return (ln1->device - (*device));
1895 * This function construct line struct from input.
1896 * @param info pointer to store line momentum.
1897 * @param st line info to store input data.
1898 * @param pe The recent input event as stored in pe struct.
1900 * @ingroup Elm_Gesture_Layer
1903 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1904 Pointer_Event *pe, Evas_Callback_Type event_type)
1905 { /* Record events and set momentum for line pointed by st */
1911 case EVAS_CALLBACK_MOUSE_DOWN:
1912 case EVAS_CALLBACK_MOUSE_MOVE:
1913 case EVAS_CALLBACK_MULTI_DOWN:
1914 case EVAS_CALLBACK_MULTI_MOVE:
1916 { /* This happens only when line starts */
1917 st->line_st.x = pe->x;
1918 st->line_st.y = pe->y;
1919 st->t_st = pe->timestamp;
1920 st->device = pe->device;
1921 info->momentum.x1 = pe->x;
1922 info->momentum.y1 = pe->y;
1923 info->momentum.tx = pe->timestamp;
1924 info->momentum.ty = pe->timestamp;
1931 case EVAS_CALLBACK_MOUSE_UP:
1932 case EVAS_CALLBACK_MULTI_UP:
1933 /* IGNORE if line info was cleared, like long press, move */
1937 st->line_end.x = pe->x;
1938 st->line_end.y = pe->y;
1939 st->t_end = pe->timestamp;
1948 _line_data_reset(st);
1952 info->momentum.x2 = pe->x;
1953 info->momentum.y2 = pe->y;
1954 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1955 st->t_st, st->t_st, pe->timestamp);
1963 * This function test for (n) line gesture.
1964 * @param obj The gesture-layer object.
1965 * @param pe The recent input event as stored in pe struct.
1966 * @param event_info Original input event pointer.
1967 * @param event_type Type of original input event.
1968 * @param g_type what Gesture we are testing.
1970 * @ingroup Elm_Gesture_Layer
1973 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1974 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1978 Widget_Data *wd = elm_widget_data_get(obj);
1980 Gesture_Info *gesture = wd->gesture[g_type];
1981 if (!gesture ) return;
1983 /* When continues enable = TRUE a gesture may START on MOVE event */
1984 /* We don't allow this to happen with the if-statement below. */
1985 /* When continues enable = FALSE a gesture may START on DOWN only */
1986 /* Therefor it would NOT start on MOVE event. */
1987 /* NOTE that touched list is updated AFTER this function returns */
1988 /* so (count == 0) when we get here on first touch on surface. */
1989 if ((wd->glayer_continues_enable) && (!eina_list_count(wd->touched)))
1990 return; /* Got move on mouse-over move */
1992 Line_Type *st = gesture->data;
1995 st = calloc(1, sizeof(Line_Type));
1999 Line_Data *line = NULL;
2000 Eina_List *list = st->list;
2001 unsigned cnt = eina_list_count(list);
2004 { /* list is not empty, locate this device on list */
2005 line = (Line_Data *) eina_list_search_unsorted(st->list,
2006 compare_line_device, &pe->device);
2010 { /* List is empty or device not found, new line-struct on START only */
2011 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2012 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
2013 ((wd->glayer_continues_enable) && /* START on MOVE also */
2014 ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2015 (event_type == EVAS_CALLBACK_MULTI_MOVE))))
2016 { /* Allocate new item on START only */
2017 line = calloc(1, sizeof(Line_Data));
2018 _line_data_reset(line);
2019 list = eina_list_append(list, line);
2024 if (!line) /* This may happen on MOVE that comes before DOWN */
2025 return; /* No line-struct to work with, can't continue testing */
2027 if (_single_line_process(&st->info, line, pe, event_type)) /* update st with input */
2028 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
2030 /* Get direction and magnitude of the line */
2032 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
2033 &line->line_length, &angle);
2035 /* These are used later to compare lines length */
2036 Evas_Coord shortest_line_len = line->line_length;
2037 Evas_Coord longest_line_len = line->line_length;
2038 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2040 /* Now update line-state */
2042 { /* Analyze line only if line started */
2043 if (line->line_angle >= 0.0)
2044 { /* if line direction was set, we test if broke tolerance */
2045 double a = fabs(angle - line->line_angle);
2047 double d = (tan(a)) * line->line_length; /* Distance from line */
2048 #if defined(DEBUG_GESTURE_LAYER)
2049 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
2051 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
2052 { /* Broke tolerance: abort line and start a new one */
2053 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2054 &st->info, EINA_FALSE);
2055 consume_event(wd, event_info, event_type, ev_flag);
2059 if (wd->glayer_continues_enable)
2060 { /* We may finish line if momentum is zero */
2061 /* This is for continues-gesture */
2062 if ((!st->info.momentum.mx) && (!st->info.momentum.my))
2063 { /* Finish line on zero momentum for continues gesture */
2064 line->line_end.x = pe->x;
2065 line->line_end.y = pe->y;
2066 line->t_end = pe->timestamp;
2071 { /* Record the line angle as it broke minimum length for line */
2072 if (line->line_length >= wd->line_min_length)
2073 st->info.angle = line->line_angle = angle;
2079 if (line->line_angle < 0.0)
2080 { /* it's not a line, too short more close to a tap */
2081 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2082 &st->info, EINA_FALSE);
2083 consume_event(wd, event_info, event_type, ev_flag);
2089 /* Count how many lines already started / ended */
2092 unsigned int tm_start = pe->timestamp;
2093 unsigned int tm_end = pe->timestamp;
2096 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
2097 Eina_Bool lines_parallel = EINA_TRUE;
2098 EINA_LIST_FOREACH(list, l, t_line)
2101 base_angle = t_line->line_angle;
2104 if (t_line->line_angle >= 0)
2105 { /* Compare angle only with lines with direction defined */
2106 if (fabs(base_angle - t_line->line_angle) >
2107 wd->line_angular_tolerance)
2108 lines_parallel = EINA_FALSE;
2112 if (t_line->line_length)
2113 { /* update only if this line is used */
2114 if (shortest_line_len > t_line->line_length)
2115 shortest_line_len = t_line->line_length;
2117 if (longest_line_len < t_line->line_length)
2118 longest_line_len = t_line->line_length;
2124 if (t_line->t_st < tm_start)
2125 tm_start = t_line->t_st;
2131 if (t_line->t_end < tm_end)
2132 tm_end = t_line->t_end;
2136 st->info.momentum.n = started;
2140 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2141 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
2142 { /* user lift one finger then starts again without line-end - ABORT */
2143 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2145 consume_event(wd, event_info, event_type, ev_flag);
2149 if (!lines_parallel)
2150 { /* Lines are NOT at same direction, abort this gesture */
2151 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2153 consume_event(wd, event_info, event_type, ev_flag);
2158 /* We report ABORT if lines length are NOT matching when fingers are up */
2159 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
2161 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2163 consume_event(wd, event_info, event_type, ev_flag);
2167 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
2168 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
2169 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
2171 consume_event(wd, event_info, event_type, ev_flag);
2177 case EVAS_CALLBACK_MOUSE_UP:
2178 case EVAS_CALLBACK_MULTI_UP:
2179 if ((started) && (started == ended))
2181 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2182 &st->info, EINA_FALSE);
2183 consume_event(wd, event_info, event_type, ev_flag);
2188 case EVAS_CALLBACK_MOUSE_DOWN:
2189 case EVAS_CALLBACK_MULTI_DOWN:
2190 case EVAS_CALLBACK_MOUSE_MOVE:
2191 case EVAS_CALLBACK_MULTI_MOVE:
2194 if (wd->glayer_continues_enable && (started == ended))
2195 { /* For continues gesture */
2196 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2197 &st->info, EINA_FALSE);
2198 consume_event(wd, event_info, event_type, ev_flag);
2201 { /* When continues, may START on MOVE event too */
2202 Elm_Gesture_State s = ELM_GESTURE_STATE_MOVE;
2204 /* This happens when: on n > 1 lines then one finger up */
2205 /* caused abort, then put finger down. */
2206 /* This will stop line from starting again. */
2207 /* Number of lines, MUST match touched-device in list */
2208 if ((!wd->glayer_continues_enable) &&
2209 (eina_list_count(st->list) < eina_list_count(wd->touched)))
2210 s = ELM_GESTURE_STATE_ABORT;
2212 if (gesture->state == ELM_GESTURE_STATE_UNDEFINED)
2213 s = ELM_GESTURE_STATE_START;
2215 ev_flag = _set_state(gesture, s, &st->info, EINA_TRUE);
2216 consume_event(wd, event_info, event_type, ev_flag);
2222 return; /* Unhandeld event type */
2229 * This function is used to check if rotation gesture started.
2230 * @param st Contains current rotation values from user input.
2231 * @return TRUE/FALSE if we need to set rotation START.
2233 * @ingroup Elm_Gesture_Layer
2236 rotation_broke_tolerance(Rotate_Type *st)
2238 if (st->info.base_angle < 0)
2239 return EINA_FALSE; /* Angle has to be computed first */
2241 if (st->rotate_angular_tolerance < 0)
2244 double low = st->info.base_angle - st->rotate_angular_tolerance;
2245 double high = st->info.base_angle + st->rotate_angular_tolerance;
2246 double t = st->info.angle;
2259 if (high > RAD_360DEG)
2270 #if defined(DEBUG_GESTURE_LAYER)
2271 printf("%s angle=<%f> low=<%f> high=<%f>\n", __func__, t, low, high);
2273 if ((t < low) || (t > high))
2274 { /* This marks that roation action has started */
2275 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
2276 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
2286 * This function is used for computing the gap between fingers.
2287 * It returns the length and center point between fingers.
2289 * @param x1 first finger x location.
2290 * @param y1 first finger y location.
2291 * @param x2 second finger x location.
2292 * @param y2 second finger y location.
2293 * @param x Gets center point x cord (output)
2294 * @param y Gets center point y cord (output)
2296 * @return length of the line between (x1,y1), (x2,y2) in pixels.
2298 * @ingroup Elm_Gesture_Layer
2301 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
2302 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
2304 double a, b, xx, yy, gap;
2307 gap = sqrt(xx*xx + yy*yy);
2309 /* START - Compute zoom center point */
2310 /* The triangle defined as follows:
2318 * http://en.wikipedia.org/wiki/Trigonometric_functions
2319 *************************************/
2320 if (((int) xx) && ((int) yy))
2322 double A = atan((yy / xx));
2323 #if defined(DEBUG_GESTURE_LAYER)
2324 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
2326 a = (Evas_Coord) ((gap / 2) * sin(A));
2327 b = (Evas_Coord) ((gap / 2) * cos(A));
2328 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2329 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2334 { /* horiz line, take half width */
2335 #if defined(DEBUG_GESTURE_LAYER)
2336 printf("==== HORIZ ====\n");
2338 *x = (Evas_Coord) (xx / 2);
2339 *y = (Evas_Coord) (y1);
2343 { /* vert line, take half width */
2344 #if defined(DEBUG_GESTURE_LAYER)
2345 printf("==== VERT ====\n");
2347 *x = (Evas_Coord) (x1);
2348 *y = (Evas_Coord) (yy / 2);
2351 /* END - Compute zoom center point */
2353 return (Evas_Coord) gap;
2359 * This function is used for computing zoom value.
2361 * @param st Pointer to zoom data based on user input.
2362 * @param x1 first finger x location.
2363 * @param y1 first finger y location.
2364 * @param x2 second finger x location.
2365 * @param y2 second finger y location.
2366 * @param factor zoom-factor, used to determine how fast zoom works.
2368 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2370 * @ingroup Elm_Gesture_Layer
2373 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2374 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2377 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2378 &st->info.x, &st->info.y);
2380 st->info.radius = diam / 2;
2384 st->zoom_base = diam;
2385 return st->info.zoom;
2388 if (st->zoom_distance_tolerance)
2389 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2390 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2391 { /* avoid jump with zoom value when break tolerance */
2392 st->zoom_base -= st->zoom_distance_tolerance;
2393 st->zoom_distance_tolerance = 0;
2396 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2397 { /* avoid jump with zoom value when break tolerance */
2398 st->zoom_base += st->zoom_distance_tolerance;
2399 st->zoom_distance_tolerance = 0;
2405 /* We use factor only on the difference between gap-base */
2406 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2407 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2408 (float) st->zoom_base) * zoom_finger_factor));
2411 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2412 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2423 * This function handles zoom with mouse wheel.
2424 * thats a combination of wheel + CTRL key.
2425 * @param obj The gesture-layer object.
2426 * @param event_info Original input event pointer.
2427 * @param event_type Type of original input event.
2428 * @param g_type what Gesture we are testing.
2430 * @ingroup Elm_Gesture_Layer
2433 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2434 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2436 Widget_Data *wd = elm_widget_data_get(obj);
2438 if (!wd->gesture[g_type]) return;
2440 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2441 Zoom_Type *st = gesture_zoom->data;
2442 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2444 { /* Allocated once on first time, used for zoom intermediate data */
2445 st = calloc(1, sizeof(Zoom_Type));
2446 gesture_zoom->data = st;
2447 _zoom_test_reset(gesture_zoom);
2452 case EVAS_CALLBACK_KEY_UP:
2454 Evas_Event_Key_Up *p = event_info;
2455 if ((!strcmp(p->keyname, "Control_L")) ||
2456 (!strcmp(p->keyname, "Control_R")))
2457 { /* Test if we ended a zoom gesture when releasing CTRL */
2458 if ((st->zoom_wheel) &&
2459 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2460 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2461 { /* User released CTRL after zooming */
2462 ev_flag = _set_state(gesture_zoom,
2463 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2464 consume_event(wd, event_info, event_type, ev_flag);
2472 case EVAS_CALLBACK_MOUSE_WHEEL:
2475 Elm_Gesture_State s;
2476 if (!evas_key_modifier_is_set(
2477 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2479 { /* if using wheel witout CTRL after starting zoom */
2480 if ((st->zoom_wheel) &&
2481 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2482 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2484 ev_flag = _set_state(gesture_zoom,
2485 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2486 consume_event(wd, event_info, event_type, ev_flag);
2491 return; /* Ignore mouse-wheel without control */
2494 /* Using mouse wheel with CTRL for zoom */
2495 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2496 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2497 we continue a zoom gesture */
2499 s = ELM_GESTURE_STATE_MOVE;
2502 { /* On first wheel event, report START */
2503 Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2504 evas_object_evas_get(wd->target), "Control");
2506 s = ELM_GESTURE_STATE_START;
2507 if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2508 ERR("Failed to Grabbed CTRL_L");
2509 if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2510 ERR("Failed to Grabbed CTRL_R");
2513 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2514 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2515 st->info.x = st->zoom_wheel->canvas.x;
2516 st->info.y = st->zoom_wheel->canvas.y;
2518 if (st->zoom_wheel->z < 0) /* zoom in */
2519 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2521 if (st->zoom_wheel->z > 0) /* zoom out */
2522 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2524 if (st->info.zoom < 0.0)
2525 st->info.zoom = 0.0;
2527 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2528 consume_event(wd, event_info, event_type, ev_flag);
2540 * This function is used to test zoom gesture.
2541 * user may combine zoom, rotation together.
2542 * so its possible that both will be detected from input.
2543 * (both are two-finger movement-oriented gestures)
2545 * @param obj The gesture-layer object.
2546 * @param event_info Pointer to recent input event.
2547 * @param event_type Recent input event type.
2548 * @param g_type what Gesture we are testing.
2550 * @ingroup Elm_Gesture_Layer
2553 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2554 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2558 Widget_Data *wd = elm_widget_data_get(obj);
2560 if (!wd->gesture[g_type]) return;
2562 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2563 Zoom_Type *st = gesture_zoom->data;
2566 { /* Allocated once on first time, used for zoom data */
2567 st = calloc(1, sizeof(Zoom_Type));
2568 gesture_zoom->data = st;
2569 _zoom_test_reset(gesture_zoom);
2573 /* Start - new zoom testing, letting all fingers start */
2574 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2577 case EVAS_CALLBACK_MOUSE_MOVE:
2578 case EVAS_CALLBACK_MULTI_MOVE:
2579 /* if non-continues mode and gesture NOT started, ignore MOVE */
2580 if ((!wd->glayer_continues_enable) &&
2581 (!st->zoom_st.timestamp))
2584 case EVAS_CALLBACK_MOUSE_DOWN:
2585 case EVAS_CALLBACK_MULTI_DOWN:
2586 { /* Here we take care of zoom-start and zoom move */
2590 if(eina_list_count(wd->touched) > 2)
2591 { /* Process zoom only when 2 fingers on surface */
2592 ev_flag = _set_state(gesture_zoom,
2593 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2594 consume_event(wd, event_info, event_type, ev_flag);
2599 if (!st->zoom_st.timestamp)
2600 { /* Now scan touched-devices list and find other finger */
2601 EINA_LIST_FOREACH(wd->touched, l, p)
2602 { /* Device of other finger <> pe device */
2603 if (p->device != pe->device)
2607 if (!p) /* Single finger on touch */
2610 /* Record down fingers */
2611 consume_event(wd, event_info, event_type, ev_flag);
2612 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2613 memcpy(&st->zoom_st1, p, sizeof(Pointer_Event));
2615 /* Set mv field as well to be ready for MOVE events */
2616 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2617 memcpy(&st->zoom_mv1, p, sizeof(Pointer_Event));
2619 /* Here we have zoom_st, zoom_st1 set, report START */
2620 /* Set zoom-base after BOTH down events recorded */
2621 /* Compute length of line between fingers zoom start */
2622 st->info.zoom = 1.0;
2623 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2624 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2625 &st->info.x, &st->info.y);
2627 st->info.radius = st->zoom_base / 2;
2629 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2630 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2631 { /* zoom started with mouse-wheel, don't report twice */
2632 ev_flag = _set_state(gesture_zoom,
2633 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2634 consume_event(wd, event_info, event_type, ev_flag);
2637 return; /* Zoom started */
2638 } /* End of ZOOM_START handling */
2641 /* if we got here, we have (exacally) two fingers on surfce */
2642 /* we also after START, report MOVE */
2643 /* First detect which finger moved */
2644 if (pe->device == st->zoom_mv.device)
2645 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2646 else if (pe->device == st->zoom_mv1.device)
2647 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2649 /* Compute change in zoom as fingers move */
2650 st->info.zoom = compute_zoom(st,
2651 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2652 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2653 wd->zoom_finger_factor);
2655 if (!st->zoom_distance_tolerance)
2656 { /* Zoom broke tolerance, report move */
2657 double d = st->info.zoom - st->next_step;
2661 if (d >= wd->zoom_step)
2662 { /* Report move in steps */
2663 st->next_step = st->info.zoom;
2665 ev_flag = _set_state(gesture_zoom,
2666 ELM_GESTURE_STATE_MOVE,
2667 &st->info, EINA_TRUE);
2668 consume_event(wd, event_info, event_type, ev_flag);
2670 } /* End of ZOOM_MOVE handling */
2675 case EVAS_CALLBACK_MOUSE_UP:
2676 case EVAS_CALLBACK_MULTI_UP:
2677 /* Reset timestamp of finger-up.This is used later
2678 by _zoom_test_reset() to retain finger-down data */
2679 consume_event(wd, event_info, event_type, ev_flag);
2680 if (((st->zoom_wheel) || (st->zoom_base)) &&
2681 (st->zoom_distance_tolerance == 0))
2683 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2684 &st->info, EINA_FALSE);
2685 consume_event(wd, event_info, event_type, ev_flag);
2690 /* if we got here not a ZOOM */
2691 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2692 { /* Must be != undefined, if gesture started */
2693 ev_flag = _set_state(gesture_zoom,
2694 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2695 consume_event(wd, event_info, event_type, ev_flag);
2698 _zoom_test_reset(gesture_zoom);
2708 _get_rotate_properties(Rotate_Type *st,
2709 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2710 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2713 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2714 &st->info.x, &st->info.y) / 2;
2716 *angle = get_angle(x1, y1, x2, y2);
2717 #if 0 /* (NOT YET SUPPORTED) */
2718 if (angle == &st->info.angle)
2719 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2720 st->info.momentum = (((*angle) - st->info.base_angle) /
2721 (fabs(tm2 - tm1))) * 1000;
2724 st->info.momentum = 0;
2734 * This function is used to test rotation gesture.
2735 * user may combine zoom, rotation together.
2736 * so its possible that both will be detected from input.
2737 * (both are two-finger movement-oriented gestures)
2739 * @param obj The gesture-layer object.
2740 * @param event_info Pointer to recent input event.
2741 * @param event_type Recent input event type.
2742 * @param g_type what Gesture we are testing.
2744 * @ingroup Elm_Gesture_Layer
2747 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2748 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2753 Widget_Data *wd = elm_widget_data_get(obj);
2755 if (!wd->gesture[g_type]) return;
2757 Gesture_Info *gesture = wd->gesture[g_type];
2758 Rotate_Type *st = gesture->data;
2763 { /* Allocated once on first time */
2764 st = calloc(1, sizeof(Rotate_Type));
2766 _rotate_test_reset(gesture);
2770 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2773 case EVAS_CALLBACK_MOUSE_MOVE:
2774 case EVAS_CALLBACK_MULTI_MOVE:
2775 /* if non-continues mode and gesture NOT started, ignore MOVE */
2776 if ((!wd->glayer_continues_enable) &&
2777 (!st->rotate_st.timestamp))
2780 case EVAS_CALLBACK_MOUSE_DOWN:
2781 case EVAS_CALLBACK_MULTI_DOWN:
2782 { /* Here we take care of rotate-start and rotate move */
2786 if(eina_list_count(wd->touched) > 2)
2787 { /* Process rotate only when 2 fingers on surface */
2788 ev_flag = _set_state(gesture,
2789 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2790 consume_event(wd, event_info, event_type, ev_flag);
2795 if (!st->rotate_st.timestamp)
2796 { /* Now scan touched-devices list and find other finger */
2797 EINA_LIST_FOREACH(wd->touched, l, p)
2798 { /* Device of other finger <> pe device */
2799 if (p->device != pe->device)
2804 return; /* Single finger on touch */
2806 /* Record down fingers */
2807 consume_event(wd, event_info, event_type, ev_flag);
2808 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2809 memcpy(&st->rotate_st1, p, sizeof(Pointer_Event));
2811 /* Set mv field as well to be ready for MOVE events */
2812 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2813 memcpy(&st->rotate_mv1, p, sizeof(Pointer_Event));
2815 /* Here we have rotate_st, rotate_st1 set, report START */
2816 /* Set rotate-base after BOTH down events recorded */
2817 /* Compute length of line between fingers rotate start */
2818 _get_rotate_properties(st,
2819 st->rotate_st.x, st->rotate_st.y,
2820 st->rotate_st.timestamp,
2821 st->rotate_st1.x, st->rotate_st1.y,
2822 st->rotate_st1.timestamp, &st->info.base_angle);
2824 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2825 &st->info, EINA_FALSE);
2826 consume_event(wd, event_info, event_type, ev_flag);
2828 return; /* Rotate started */
2829 } /* End of ROTATE_START handling */
2832 /* if we got here, we have (exacally) two fingers on surfce */
2833 /* we also after START, report MOVE */
2834 /* First detect which finger moved */
2835 if (pe->device == st->rotate_mv.device)
2836 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2837 else if (pe->device == st->rotate_mv1.device)
2838 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2840 /* Compute change in rotate as fingers move */
2841 _get_rotate_properties(st,
2842 st->rotate_mv.x, st->rotate_mv.y,
2843 st->rotate_mv.timestamp,
2844 st->rotate_mv1.x, st->rotate_mv1.y,
2845 st->rotate_mv1.timestamp, &st->info.angle);
2847 if (rotation_broke_tolerance(st))
2848 { /* Rotation broke tolerance, report move */
2849 double d = st->info.angle - st->next_step;
2853 if (d >= wd->rotate_step)
2854 { /* Report move in steps */
2855 st->next_step = st->info.angle;
2857 ev_flag = _set_state(gesture,
2858 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2859 consume_event(wd, event_info, event_type, ev_flag);
2861 } /* End of ROTATE_MOVE handling */
2866 case EVAS_CALLBACK_MOUSE_UP:
2867 case EVAS_CALLBACK_MULTI_UP:
2868 consume_event(wd, event_info, event_type, ev_flag);
2869 /* Reset timestamp of finger-up.This is used later
2870 by rotate_test_reset() to retain finger-down data */
2871 if (st->rotate_angular_tolerance < 0)
2873 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2874 &st->info, EINA_FALSE);
2875 consume_event(wd, event_info, event_type, ev_flag);
2880 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2881 { /* Must be != undefined, if gesture started */
2882 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2883 &st->info, EINA_FALSE);
2884 consume_event(wd, event_info, event_type, ev_flag);
2887 _rotate_test_reset(gesture);
2898 * This function is used to save input events in an abstract struct
2899 * to be used later by getsure-testing functions.
2901 * @param data The gesture-layer object.
2902 * @param event_info Pointer to recent input event.
2903 * @param event_type Recent input event type.
2904 * @param pe The abstract data-struct (output).
2906 * @ingroup Elm_Gesture_Layer
2909 _make_pointer_event(void *data, void *event_info,
2910 Evas_Callback_Type event_type, Pointer_Event *pe)
2912 Widget_Data *wd = elm_widget_data_get(data);
2913 if (!wd) return EINA_FALSE;
2915 memset(pe, '\0', sizeof(*pe));
2918 case EVAS_CALLBACK_MOUSE_DOWN:
2919 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2920 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2921 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2922 pe->device = ELM_MOUSE_DEVICE;
2925 case EVAS_CALLBACK_MOUSE_UP:
2926 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2927 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2928 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2929 pe->device = ELM_MOUSE_DEVICE;
2932 case EVAS_CALLBACK_MOUSE_MOVE:
2933 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2934 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2935 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2936 pe->device = ELM_MOUSE_DEVICE;
2939 case EVAS_CALLBACK_MULTI_DOWN:
2940 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2941 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2942 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2943 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2946 case EVAS_CALLBACK_MULTI_UP:
2947 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2948 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2949 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2950 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2953 case EVAS_CALLBACK_MULTI_MOVE:
2954 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2955 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2956 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2957 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2964 pe->event_type = event_type;
2971 * This function restartes line, flick, zoom and rotate gestures
2972 * when gesture-layer continues-gestures enabled.
2973 * Example of continues-gesture:
2974 * When doing a line, user stops moving finger but keeps fingers on touch.
2975 * This will cause line-end, then as user continues moving his finger
2976 * it re-starts line gesture.
2977 * When continue mode is disabled, user has to lift finger from touch
2978 * to end a gesture. Them touch-again to start a new one.
2980 * @param data The gesture-layer object.
2981 * @param wd gesture layer widget data.
2982 * @param states_reset flag that marks gestures were reset in history clear.
2984 * @ingroup Elm_Gesture_Layer
2986 void continues_gestures_restart(void *data, Eina_Bool states_reset)
2988 Widget_Data *wd = elm_widget_data_get(data);
2991 /* Run through events to restart gestures */
2993 Eina_Bool n_momentum, n_lines, n_flicks, zoom, rotate;
2994 /* We turn-on flag for finished, aborted, not-started gestures */
2995 g = wd->gesture[ELM_GESTURE_MOMENTUM];
2996 n_momentum = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
2997 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3000 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
3001 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3005 g = wd->gesture[ELM_GESTURE_N_LINES];
3006 n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3007 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3010 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
3011 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3015 g = wd->gesture[ELM_GESTURE_N_FLICKS];
3016 n_flicks = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3017 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3020 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
3021 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3025 g = wd->gesture[ELM_GESTURE_ZOOM];
3026 zoom = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3027 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3030 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
3031 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3035 g = wd->gesture[ELM_GESTURE_ROTATE];
3036 rotate = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START)
3037 && (g->state != ELM_GESTURE_STATE_MOVE))) : EINA_FALSE;
3040 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
3041 _set_state(g, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
3049 * This function the core-function where input handling is done.
3050 * Here we get user input and stream it to gesture testing.
3051 * We notify user about any gestures with new state:
3053 * START - gesture started.
3054 * MOVE - gesture is ongoing.
3055 * END - gesture was completed.
3056 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
3058 * We also check if a gesture was detected, then reset event history
3059 * If no gestures were found we reset gesture test flag
3060 * after streaming event-history to widget.
3061 * (stream to the widget all events not consumed as a gesture)
3063 * @param data The gesture-layer object.
3064 * @param event_info Pointer to recent input event.
3065 * @param event_type Recent input event type.
3067 * @ingroup Elm_Gesture_Layer
3070 _event_process(void *data, Evas_Object *obj __UNUSED__,
3071 void *event_info, Evas_Callback_Type event_type)
3074 Pointer_Event *pe = NULL;
3075 Widget_Data *wd = elm_widget_data_get(data);
3078 #if defined(DEBUG_GESTURE_LAYER)
3081 printf("Gesture | State | is tested\n");
3082 for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++)
3086 printf(" %d %d %d\n", i, g->state, g->test);
3090 /* Start testing candidate gesture from here */
3091 if (_make_pointer_event(data, event_info, event_type, &_pe))
3094 if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS))
3095 _n_long_tap_test(data, pe, event_info, event_type,
3096 ELM_GESTURE_N_LONG_TAPS);
3098 /* This takes care of single, double and tripple tap */
3099 _tap_gestures_test(data, pe, event_info, event_type);
3101 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
3102 _momentum_test(data, pe, event_info, event_type,
3103 ELM_GESTURE_MOMENTUM);
3105 if (IS_TESTED(ELM_GESTURE_N_LINES))
3106 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
3108 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
3109 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
3111 if (IS_TESTED(ELM_GESTURE_ZOOM))
3112 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
3114 if (IS_TESTED(ELM_GESTURE_ZOOM))
3115 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
3117 if (IS_TESTED(ELM_GESTURE_ROTATE))
3118 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
3120 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
3121 _event_history_add(data, event_info, event_type);
3122 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3123 (event_type == EVAS_CALLBACK_MULTI_UP))
3125 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
3128 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
3129 _event_history_add(data, event_info, event_type);
3133 /* we maintain list of touched devices */
3134 /* We also use move to track current device x.y pos */
3135 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
3136 (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
3137 (event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
3138 (event_type == EVAS_CALLBACK_MULTI_MOVE))
3140 wd->touched = _add_touched_device(wd->touched, pe);
3142 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
3143 (event_type == EVAS_CALLBACK_MULTI_UP))
3145 wd->touched = _remove_touched_device(wd->touched, pe);
3148 /* Report current states and clear history if needed */
3149 Eina_Bool states_reset = _clear_if_finished(data);
3150 if (wd->glayer_continues_enable)
3151 continues_gestures_restart(data, states_reset);
3156 * For all _mouse_* / multi_* functions wethen send this event to
3157 * _event_process function.
3159 * @param data The gesture-layer object.
3160 * @param event_info Pointer to recent input event.
3162 * @ingroup Elm_Gesture_Layer
3165 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3168 Widget_Data *wd = elm_widget_data_get(data);
3170 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
3171 return; /* We only process left-click at the moment */
3173 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
3177 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3180 Widget_Data *wd = elm_widget_data_get(data);
3183 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
3187 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3190 Widget_Data *wd = elm_widget_data_get(data);
3193 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
3197 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3200 Widget_Data *wd = elm_widget_data_get(data);
3203 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
3207 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3210 Widget_Data *wd = elm_widget_data_get(data);
3213 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
3214 return; /* We only process left-click at the moment */
3216 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
3220 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3223 Widget_Data *wd = elm_widget_data_get(data);
3226 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
3230 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3233 Widget_Data *wd = elm_widget_data_get(data);
3236 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
3240 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3243 Widget_Data *wd = elm_widget_data_get(data);
3246 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
3250 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
3253 Widget_Data *wd = elm_widget_data_get(data);
3256 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
3260 elm_gesture_layer_hold_events_get(Evas_Object *obj)
3262 Widget_Data *wd = elm_widget_data_get(obj);
3263 if (!wd) return EINA_FALSE;
3265 return !wd->repeat_events;
3269 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
3271 Widget_Data *wd = elm_widget_data_get(obj);
3274 wd->repeat_events = !r;
3278 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
3280 Widget_Data *wd = elm_widget_data_get(obj);
3290 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
3292 Widget_Data *wd = elm_widget_data_get(obj);
3298 wd->rotate_step = s;
3302 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
3304 Widget_Data *wd = elm_widget_data_get(obj);
3305 if (!wd) return EINA_FALSE;
3310 /* if was attached before, unregister callbacks first */
3312 _unregister_callbacks(obj);
3316 _register_callbacks(obj);
3321 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
3322 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
3324 Widget_Data *wd = elm_widget_data_get(obj);
3328 if (!wd->gesture[idx])
3329 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
3330 if (!wd->gesture[idx]) return;
3332 p = wd->gesture[idx];
3335 p->fn[cb_type].cb = cb;
3336 p->fn[cb_type].user_data = data;
3337 p->state = ELM_GESTURE_STATE_UNDEFINED;
3342 _disable_hook(Evas_Object *obj)
3344 if (elm_widget_disabled_get(obj))
3345 _unregister_callbacks(obj);
3347 _register_callbacks(obj);
3351 elm_gesture_layer_add(Evas_Object *parent)
3357 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3359 wd = ELM_NEW(Widget_Data);
3360 e = evas_object_evas_get(parent);
3361 if (!e) return NULL;
3362 obj = elm_widget_add(e);
3363 ELM_SET_WIDTYPE(widtype, "gesture_layer");
3364 elm_widget_type_set(obj, "gesture_layer");
3365 elm_widget_sub_object_add(parent, obj);
3366 elm_widget_data_set(obj, wd);
3367 elm_widget_del_hook_set(obj, _del_hook);
3368 elm_widget_disable_hook_set(obj, _disable_hook);
3371 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3372 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3373 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3374 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3375 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3376 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3377 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3378 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3379 wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout;
3380 wd->repeat_events = EINA_TRUE;
3381 wd->glayer_continues_enable = _elm_config->glayer_continues_enable;
3383 #if defined(DEBUG_GESTURE_LAYER)
3384 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3385 printf("initial values:\n\tzoom_finger_factor=<%f>\n\tzoom_distance_tolerance=<%d>\n\tline_min_length=<%d>\n\tline_distance_tolerance=<%d>\n\tzoom_wheel_factor=<%f>\n\trotate_angular_tolerance=<%f>\n\twd->line_angular_tolerance=<%f>\n\twd->flick_time_limit_ms=<%d>\n\twd->long_tap_start_timeout=<%f>\n\twd->zoom_step=<%f>\n\twd->rotate_step=<%f>\n\twd->glayer_continues_enable=<%d>\n ", wd->zoom_finger_factor, wd->zoom_distance_tolerance, wd->line_min_length, wd->line_distance_tolerance, wd->zoom_wheel_factor, wd->rotate_angular_tolerance, wd->line_angular_tolerance, wd->flick_time_limit_ms, wd->long_tap_start_timeout, wd->zoom_step, wd->rotate_step, wd->glayer_continues_enable);
3387 memset(wd->gesture, 0, sizeof(wd->gesture));