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 DBL_CLICK_TIME 400
12 /* Some Trigo values */
13 #define RAD_90DEG M_PI_2
14 #define RAD_180DEG M_PI
15 #define RAD_270DEG (M_PI_2 * 3)
16 #define RAD_360DEG (M_PI * 2)
19 _glayer_bufdup(void *buf, size_t size)
26 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
29 #define SET_TEST_BIT(P) do { \
30 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; \
33 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
39 * Struct holds callback information.
41 * @ingroup Elm_Gesture_Layer
45 void *user_data; /**< Holds user data to CB (like sd) */
46 Elm_Gesture_Event_Cb cb;
53 * type for callback information
55 * @ingroup Elm_Gesture_Layer
57 typedef struct _Func_Data Func_Data;
62 * @struct _Gesture_Info
63 * Struct holds gesture info
65 * @ingroup Elm_Gesture_Layer
70 void *data; /**< Holds gesture intemidiate processing data */
71 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
72 Elm_Gesture_Types g_type; /**< gesture type */
73 Elm_Gesture_State state; /**< gesture state */
74 void *info; /**< Data for the state callback */
75 Eina_Bool test; /**< if true this gesture should be tested on input */
81 * @typedef Gesture_Info
82 * Type for _Gesture_Info
84 * @ingroup Elm_Gesture_Layer
86 typedef struct _Gesture_Info Gesture_Info;
91 * @struct _Event_History
92 * Struct holds event history.
93 * These events are repeated if no gesture found.
95 * @ingroup Elm_Gesture_Layer
101 Evas_Callback_Type event_type;
107 * @typedef Event_History
108 * Type for _Event_History
110 * @ingroup Elm_Gesture_Layer
112 typedef struct _Event_History Event_History;
117 * @struct _Pointer_Event
118 * Struct holds pointer-event info
119 * This is a generic pointer event structure
121 * @ingroup Elm_Gesture_Layer
123 struct _Pointer_Event
126 unsigned int timestamp;
128 Evas_Callback_Type event_type;
134 * @typedef Pointer_Event
135 * Type for generic pointer event structure
137 * @ingroup Elm_Gesture_Layer
139 typedef struct _Pointer_Event Pointer_Event;
141 /* All *Type structs hold result for the user in 'info' field
142 * The rest is gesture processing intermediate data.
143 * NOTE: info field must be FIRST in the struct.
144 * This is used when reporting ABORT in event_history_clear() */
147 Elm_Gesture_Taps_Info info;
148 unsigned int count_ups;
154 typedef struct _Taps_Type Taps_Type;
156 struct _Momentum_Type
157 { /* Fields used by _line_test() */
158 Elm_Gesture_Momentum_Info info;
159 Evas_Coord_Point line_st;
160 Evas_Coord_Point line_end;
161 unsigned int t_st_x; /* Time start on X */
162 unsigned int t_st_y; /* Time start on Y */
163 unsigned int t_end; /* Time end */
166 typedef struct _Momentum_Type Momentum_Type;
170 Evas_Coord_Point line_st;
171 Evas_Coord_Point line_end;
172 Evas_Coord line_length;
173 unsigned int t_st; /* Time start */
174 unsigned int t_end; /* Time end */
176 double line_angle; /* Current angle of line */
178 typedef struct _Line_Data Line_Data;
181 { /* Fields used by _line_test() */
182 Elm_Gesture_Line_Info info;
183 Eina_List *list; /* List of Line_Data */
185 typedef struct _Line_Type Line_Type;
188 { /* Fields used by _zoom_test() */
189 Elm_Gesture_Zoom_Info info;
190 Pointer_Event zoom_st;
191 Pointer_Event zoom_mv;
192 Pointer_Event zoom_st1;
193 Pointer_Event zoom_mv1;
194 Evas_Event_Mouse_Wheel *zoom_wheel;
195 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
196 Evas_Coord zoom_distance_tolerance;
199 typedef struct _Zoom_Type Zoom_Type;
202 { /* Fields used by _rotation_test() */
203 Elm_Gesture_Rotate_Info info;
204 Pointer_Event rotate_st;
205 Pointer_Event rotate_mv;
206 Pointer_Event rotate_st1;
207 Pointer_Event rotate_mv1;
208 double rotate_angular_tolerance;
211 typedef struct _Rotate_Type Rotate_Type;
215 Evas_Object *target; /* Target Widget */
216 Event_History *event_history_list;
219 Evas_Coord zoom_distance_tolerance;
220 Evas_Coord line_distance_tolerance;
221 double line_angular_tolerance;
222 double zoom_wheel_factor; /* mouse wheel zoom steps */
223 double zoom_finger_factor; /* used for zoom factor */
224 double rotate_angular_tolerance;
225 unsigned int flick_time_limit_ms;
230 Gesture_Info *gesture[ELM_GESTURE_LAST];
231 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
232 Eina_List *pending; /* List of devices need to refeed *UP event */
233 Eina_List *touched; /* Information of touched devices */
235 Eina_Bool repeat_events : 1;
237 typedef struct _Widget_Data Widget_Data;
239 static const char *widtype = NULL;
240 static void _del_hook(Evas_Object *obj);
242 static void _event_history_clear(Evas_Object *obj);
243 static void _reset_states(Widget_Data *wd);
244 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
245 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
246 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
247 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
248 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
249 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
250 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
252 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
253 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
254 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
256 /* START - Functions to manage touched-device list */
259 * This function is used to find if device is touched
261 * @ingroup Elm_Gesture_Layer
264 device_is_touched(const void *data1, const void *data2)
265 { /* Compare the two device numbers */
266 return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
272 * Recoed Pointer Event in touched device list
273 * Note: This fuction allocates memory for PE event
274 * This memory is released in _remove_touched_device()
275 * @param list Pointer to touched device list.
276 * @param Pointer_Event Pointer to PE.
278 * @ingroup Elm_Gesture_Layer
281 _add_touched_device(Eina_List *list, Pointer_Event *pe)
283 if (eina_list_search_unsorted_list(list, device_is_touched, pe))
286 Pointer_Event *p = malloc(sizeof(Pointer_Event ));
287 memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
288 return eina_list_append(list, p);
294 * Remove Pointer Event from touched device list
295 * @param list Pointer to touched device list.
296 * @param Pointer_Event Pointer to PE.
298 * @ingroup Elm_Gesture_Layer
301 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
303 Pointer_Event *p = eina_list_search_unsorted(list, device_is_touched, pe);
307 return eina_list_remove(list, p);
312 /* END - Functions to manage touched-device list */
318 * @param event_info pointer to event.
320 * @ingroup Elm_Gesture_Layer
322 static Evas_Event_Flags
323 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
327 case EVAS_CALLBACK_MOUSE_IN:
328 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
329 case EVAS_CALLBACK_MOUSE_OUT:
330 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
331 case EVAS_CALLBACK_MOUSE_DOWN:
332 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
333 case EVAS_CALLBACK_MOUSE_MOVE:
334 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
335 case EVAS_CALLBACK_MOUSE_UP:
336 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
337 case EVAS_CALLBACK_MOUSE_WHEEL:
338 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
339 case EVAS_CALLBACK_MULTI_DOWN:
340 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
341 case EVAS_CALLBACK_MULTI_MOVE:
342 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
343 case EVAS_CALLBACK_MULTI_UP:
344 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
345 case EVAS_CALLBACK_KEY_DOWN:
346 return ((Evas_Event_Key_Down *) event_info)->event_flags;
347 case EVAS_CALLBACK_KEY_UP:
348 return ((Evas_Event_Key_Up *) event_info)->event_flags;
350 return EVAS_EVENT_FLAG_NONE;
357 * Sets event flag to value returned from user callback
358 * @param wd Widget Data
359 * @param event_info pointer to event.
360 * @param event_type what type was ev (mouse down, etc...)
361 * @param ev_flags event flags
363 * @ingroup Elm_Gesture_Layer
366 consume_event(Widget_Data *wd, void *event_info,
367 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
368 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
369 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer */
370 /* should not refeed this event. */
371 if ((ev_flags) || (!wd->repeat_events))
375 case EVAS_CALLBACK_MOUSE_DOWN:
376 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
378 case EVAS_CALLBACK_MOUSE_MOVE:
379 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
381 case EVAS_CALLBACK_MOUSE_UP:
382 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
384 case EVAS_CALLBACK_MOUSE_WHEEL:
385 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
387 case EVAS_CALLBACK_MULTI_DOWN:
388 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
390 case EVAS_CALLBACK_MULTI_MOVE:
391 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
393 case EVAS_CALLBACK_MULTI_UP:
394 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
396 case EVAS_CALLBACK_KEY_DOWN:
397 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
399 case EVAS_CALLBACK_KEY_UP:
400 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
411 * Report current state of a gesture by calling user callback.
412 * @param gesture what gesture state we report.
413 * @param info inforamtion for user callback
415 * @ingroup Elm_Gesture_Layer
417 static Evas_Event_Flags
418 _report_state(Gesture_Info *gesture, void *info)
419 { /* We report current state (START, MOVE, END, ABORT), once */
420 #if defined(DEBUG_GESTURE_LAYER)
421 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, g_type,
424 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
425 (gesture->fn[gesture->state].cb))
426 { /* Fill state-info struct and send ptr to user callback */
427 return gesture->fn[gesture->state].cb(
428 gesture->fn[gesture->state].user_data, info);
431 return EVAS_EVENT_FLAG_NONE;
437 * Update state for a given gesture.
438 * We may update gesture state to:
439 * UNDEFINED - current input did not start gesure yet.
440 * START - gesture started according to input.
441 * MOVE - gusture in progress.
442 * END - gesture completed according to input.
443 * ABORT - input does not matches gesure.
444 * note that we may move from UNDEFINED to ABORT
445 * because we may detect that gesture will not START
446 * with a given input.
448 * @param g given gesture to change state.
449 * @param s gesure new state.
450 * @param info buffer to be sent to user callback on report_state.
451 * @param force makes report_state to report the new-state even
452 * if its same as current state. Works for MOVE - gesture in progress.
454 * @ingroup Elm_Gesture_Layer
456 static Evas_Event_Flags
457 _set_state(Gesture_Info *g, Elm_Gesture_State s,
458 void *info, Eina_Bool force)
460 Elm_Gesture_State old_state;
461 if ((g->state == s) && (!force))
462 return EVAS_EVENT_FLAG_NONE;
464 old_state = g->state;
467 g->info = info; /* Information for user callback */
468 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
469 (g->state == ELM_GESTURE_STATE_END))
470 g->test = EINA_FALSE;
472 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
473 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
474 (s == ELM_GESTURE_STATE_ABORT))))
475 return _report_state(g, g->info);
477 return EVAS_EVENT_FLAG_NONE;
483 * This resets all gesture states and sets test-bit.
484 * this is used for restarting gestures to listen to input.
485 * happens after we complete a gesture or no gesture was detected.
486 * @param wd Widget data of the gesture-layer object.
488 * @ingroup Elm_Gesture_Layer
491 _reset_states(Widget_Data *wd)
495 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
500 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
509 * if gesture was NOT detected AND we only have gestures in ABORT state
510 * we clear history immediately to be ready for input.
512 * @param obj The gesture-layer object.
514 * @ingroup Elm_Gesture_Layer
517 _clear_if_finished(Evas_Object *obj)
519 Widget_Data *wd = elm_widget_data_get(obj);
523 /* Clear history if all we have aborted gestures */
524 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
525 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
526 { /* If no gesture started and all we have aborted gestures, reset all */
527 Gesture_Info *p = wd->gesture[i];
528 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
530 if ((p->state == ELM_GESTURE_STATE_START) ||
531 (p->state == ELM_GESTURE_STATE_MOVE))
532 reset_s = EINA_FALSE;
534 all_undefined = EINA_FALSE;
538 // if ((!wd->touched) || (reset_s && !all_undefined))
539 /* (!wd->touched && reset_s) - don't stop zoom with mouse-wheel */
540 if (reset_s && (!eina_list_count(wd->touched) || !all_undefined))
541 _event_history_clear(obj);
545 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
547 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
563 /* All *test_reset() funcs are called to clear
564 * gesture intermediate data.
565 * This happens when we need to reset our tests.
566 * for example when gesture is detected or all ABORTed. */
568 _dbl_click_test_reset(Gesture_Info *gesture)
573 Widget_Data *wd = elm_widget_data_get(gesture->obj);
574 if (wd->dbl_timeout) ecore_timer_del(wd->dbl_timeout);
575 wd->dbl_timeout = NULL;
582 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
583 EINA_LIST_FREE(data, pe)
586 memset(gesture->data, 0, sizeof(Taps_Type));
590 _momentum_test_reset(Gesture_Info *gesture)
598 memset(gesture->data, 0, sizeof(Momentum_Type));
602 _line_data_reset(Line_Data *st)
607 memset(st, 0, sizeof(Line_Data));
608 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
612 _line_test_reset(Gesture_Info *gesture)
620 Line_Type *st = gesture->data;
621 Eina_List *list = st->list;
624 EINA_LIST_FOREACH(list, l, t_line)
627 eina_list_free(list);
632 _zoom_test_reset(Gesture_Info *gesture)
640 Widget_Data *wd = elm_widget_data_get(gesture->obj);
641 Zoom_Type *st = gesture->data;
642 Pointer_Event pe, pe1;
644 pe.timestamp = pe1.timestamp = 0;
646 if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
648 memcpy(&pe, &st->zoom_st, sizeof(Pointer_Event));
650 if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
652 memcpy(&pe1, &st->zoom_st1, sizeof(Pointer_Event));
654 memset(st, 0, sizeof(Zoom_Type));
656 /* If user released one finger only, restore down-info */
657 if (pe.timestamp && (!pe1.timestamp))
658 memcpy(&st->zoom_st, &pe, sizeof(Pointer_Event));
660 if (pe1.timestamp && (!pe.timestamp))
661 memcpy(&st->zoom_st1, &pe1, sizeof(Pointer_Event));
663 st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
668 _rotate_test_reset(Gesture_Info *gesture)
676 Widget_Data *wd = elm_widget_data_get(gesture->obj);
677 Rotate_Type *st = gesture->data;
678 Pointer_Event pe, pe1;
680 pe.timestamp = pe1.timestamp = 0;
682 if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
684 memcpy(&pe, &st->rotate_st, sizeof(Pointer_Event));
686 if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
688 memcpy(&pe1, &st->rotate_st1, sizeof(Pointer_Event));
690 memset(st, 0, sizeof(Rotate_Type));
692 /* If user released one finger only, restore down-info */
693 if (pe.timestamp && (!pe1.timestamp))
694 memcpy(&st->rotate_st, &pe, sizeof(Pointer_Event));
696 if (pe1.timestamp && (!pe.timestamp))
697 memcpy(&st->rotate_st1, &pe1, sizeof(Pointer_Event));
700 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
701 st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
708 * We register callbacks when gesture layer is attached to an object
709 * or when its enabled after disable.
711 * @param obj The gesture-layer object.
713 * @ingroup Elm_Gesture_Layer
716 _register_callbacks(Evas_Object *obj)
718 Widget_Data *wd = elm_widget_data_get(obj);
723 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
725 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
727 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
730 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
733 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
735 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
737 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
740 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
742 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
750 * We unregister callbacks when gesture layer is disabled.
752 * @param obj The gesture-layer object.
754 * @ingroup Elm_Gesture_Layer
757 _unregister_callbacks(Evas_Object *obj)
759 Widget_Data *wd = elm_widget_data_get(obj);
764 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
766 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
768 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
771 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
774 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
777 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
780 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
783 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
785 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
790 /* START - Event history list handling functions */
793 * This function is used to find if device number
794 * is found in a list of devices.
795 * The list contains devices for refeeding *UP event
797 * @ingroup Elm_Gesture_Layer
800 device_in_pending_list(const void *data1, const void *data2)
801 { /* Compare the two device numbers */
802 return (((int) data1) - ((int) data2));
808 * This functions adds device to refeed-pending device list
809 * @ingroup Elm_Gesture_Layer
812 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
814 int device = ELM_MOUSE_DEVICE;
817 case EVAS_CALLBACK_MOUSE_DOWN:
819 case EVAS_CALLBACK_MULTI_DOWN:
820 device = ((Evas_Event_Multi_Down *) event)->device;
826 if (!eina_list_search_unsorted_list(list, device_in_pending_list,
829 return eina_list_append(list, (void *) device);
838 * This functions returns pending-device node
839 * @ingroup Elm_Gesture_Layer
842 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
844 int device = ELM_MOUSE_DEVICE;
847 case EVAS_CALLBACK_MOUSE_UP:
849 case EVAS_CALLBACK_MULTI_UP:
850 device = ((Evas_Event_Multi_Up *) event)->device;
856 return eina_list_search_unsorted_list(list, device_in_pending_list,
863 * This function reports ABORT to all none-detected gestures
864 * Then resets test bits for all desired gesures
865 * and clears input-events history.
866 * note: if no gesture was detected, events from history list
867 * are streamed to the widget because it's unused by layer.
868 * user may cancel refeed of events by setting repeat events.
870 * @param obj The gesture-layer object.
872 * @ingroup Elm_Gesture_Layer
875 _event_history_clear(Evas_Object *obj)
877 Widget_Data *wd = elm_widget_data_get(obj);
882 Evas *e = evas_object_evas_get(obj);
883 Eina_Bool gesture_found = EINA_FALSE;
884 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
889 if (p->state == ELM_GESTURE_STATE_END)
890 gesture_found = EINA_TRUE;
892 { /* Report ABORT to all gestures that still not finished */
893 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
899 _reset_states(wd); /* we are ready to start testing for gestures again */
901 /* Clear all gestures intermediate date */
902 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
903 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
904 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
905 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
906 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
907 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
908 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
909 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
911 /* Disable gesture layer so refeeded events won't be consumed by it */
912 _unregister_callbacks(obj);
913 while (wd->event_history_list)
916 t = wd->event_history_list;
917 Eina_List *pending = _device_is_pending(wd->pending,
918 wd->event_history_list->event,
919 wd->event_history_list->event_type);
921 /* Refeed events if no gesture matched input */
922 if (pending || ((!gesture_found) && (!wd->repeat_events)))
924 evas_event_refeed_event(e, wd->event_history_list->event,
925 wd->event_history_list->event_type);
929 wd->pending = eina_list_remove_list(wd->pending, pending);
930 int device = ELM_MOUSE_DEVICE;
931 if (wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
932 device = ((Evas_Event_Multi_Up *)
933 (wd->event_history_list->event))->device;
936 wd->pending = _add_device_pending(wd->pending,
937 wd->event_history_list->event,
938 wd->event_history_list->event_type);
941 free(wd->event_history_list->event);
942 wd->event_history_list = (Event_History *) eina_inlist_remove(
943 EINA_INLIST_GET(wd->event_history_list),
944 EINA_INLIST_GET(wd->event_history_list));
947 _register_callbacks(obj);
953 * This function copies input events.
954 * We copy event info before adding it to history.
955 * The memory is freed when we clear history.
957 * @param event the event to copy
958 * @param event_type event type to copy
960 * @ingroup Elm_Gesture_Layer
963 _copy_event_info(void *event, Evas_Callback_Type event_type)
967 case EVAS_CALLBACK_MOUSE_DOWN:
968 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
970 case EVAS_CALLBACK_MOUSE_MOVE:
971 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
973 case EVAS_CALLBACK_MOUSE_UP:
974 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
976 case EVAS_CALLBACK_MOUSE_WHEEL:
977 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
979 case EVAS_CALLBACK_MULTI_DOWN:
980 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
982 case EVAS_CALLBACK_MULTI_MOVE:
983 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
985 case EVAS_CALLBACK_MULTI_UP:
986 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
988 case EVAS_CALLBACK_KEY_DOWN:
989 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
991 case EVAS_CALLBACK_KEY_UP:
992 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
1000 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1002 Widget_Data *wd = elm_widget_data_get(obj);
1004 if (!wd) return EINA_FALSE;
1006 ev = malloc(sizeof(Event_History));
1007 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
1008 ev->event_type = event_type;
1009 wd->event_history_list = (Event_History *) eina_inlist_append(
1010 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1014 /* END - Event history list handling functions */
1017 _del_hook(Evas_Object *obj)
1019 Widget_Data *wd = elm_widget_data_get(obj);
1022 _event_history_clear(obj);
1023 eina_list_free(wd->pending);
1025 Pointer_Event *data;
1026 EINA_LIST_FREE(wd->touched, data)
1029 if (!elm_widget_disabled_get(obj))
1030 _unregister_callbacks(obj);
1032 /* Free all gestures internal data structures */
1034 for (i = 0; i < ELM_GESTURE_LAST; i++)
1037 if (wd->gesture[i]->data)
1038 free(wd->gesture[i]->data);
1040 free(wd->gesture[i]);
1047 compare_match_fingers(const void *data1, const void *data2)
1048 { /* Compare coords of first item in list to cur coords */
1049 const Pointer_Event *pe1 = eina_list_data_get(data1);
1050 const Pointer_Event *pe2 = data2;
1052 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1054 else if (pe1->x < pe2->x)
1058 if (pe1->x == pe2->x)
1059 return pe1->y - pe2->y;
1066 compare_pe_device(const void *data1, const void *data2)
1067 { /* Compare coords of first item in list to cur coords */
1068 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1069 const Pointer_Event *pe2 = data2;
1071 /* Only match if last was a down event */
1072 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1073 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1077 if (pe1->device == pe2->device)
1079 else if (pe1->device < pe2->device)
1086 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1087 Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1088 { /* Keep copy of pe and record it in list */
1089 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1090 memcpy(p, pe, sizeof(Pointer_Event));
1091 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1097 /* This will also update middle-point to report to user later */
1098 st->info.x = st->sum_x / st->n_taps;
1099 st->info.y = st->sum_y / st->n_taps;
1100 st->info.timestamp = pe->timestamp;
1104 pe_list = eina_list_append(pe_list, p);
1105 st->l = eina_list_append(st->l, pe_list);
1108 pe_list = eina_list_append(pe_list, p);
1116 * when this timer expires we ABORT double click gesture.
1118 * @param data The gesture-layer object.
1119 * @return cancles callback for this timer.
1121 * @ingroup Elm_Gesture_Layer
1124 _dbl_click_timeout(void *data)
1126 Gesture_Info *gesture = data;
1127 Widget_Data *wd = elm_widget_data_get(gesture->obj);
1129 wd->dbl_timeout = NULL;
1130 _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1131 gesture->info, EINA_FALSE);
1133 _dbl_click_test_reset(gesture);
1134 _clear_if_finished(gesture->obj);
1135 return ECORE_CALLBACK_CANCEL;
1141 * This function checks all click/tap and double/triple taps
1143 * @param obj The gesture-layer object.
1144 * @param pe The recent input event as stored in pe struct.
1145 * @param event_info Original input event pointer.
1146 * @param event_type Type of original input event.
1147 * @param g_type what Gesture we are testing.
1148 * @param taps How many click/taps we test for.
1150 * @ingroup Elm_Gesture_Layer
1153 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
1154 void *event_info, Evas_Callback_Type event_type,
1155 Elm_Gesture_Types g_type, int taps)
1156 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1157 Widget_Data *wd = elm_widget_data_get(obj);
1160 if (!pe) /* this happens when unhandled event arrived */
1161 return; /* see _make_pointer_event function */
1163 Gesture_Info *gesture = wd->gesture[g_type];
1164 if (!gesture ) return;
1166 if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1167 eina_list_count(wd->touched))
1168 return; /* user left a finger on device, do NOT start */
1170 Taps_Type *st = gesture->data;
1172 { /* Allocated once on first time */
1173 st = calloc(1, sizeof(Taps_Type));
1175 _dbl_click_test_reset(gesture);
1178 Eina_List *pe_list = NULL;
1179 Pointer_Event *pe_down = NULL;
1180 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1181 switch (pe->event_type)
1183 case EVAS_CALLBACK_MULTI_DOWN:
1184 case EVAS_CALLBACK_MOUSE_DOWN:
1185 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1186 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1187 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1188 { /* This is the first mouse down we got */
1189 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1190 &st->info, EINA_FALSE);
1191 consume_event(wd, event_info, event_type, ev_flag);
1193 /* To test dbl_click/dbl_tap */
1194 /* When this timer expires, gesture ABORTed if not completed */
1195 if (!wd->dbl_timeout && (taps > 1))
1196 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
1203 case EVAS_CALLBACK_MULTI_UP:
1204 case EVAS_CALLBACK_MOUSE_UP:
1205 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1207 return; /* Got only first mouse_down and mouse_up */
1209 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1211 if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
1212 return; /* Got only first mouse_down and mouse_up */
1214 /* Get first event in first list, this has to be Mouse Down event */
1215 pe_down = eina_list_data_get(pe_list);
1217 if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1223 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1224 &st->info, EINA_FALSE);
1225 consume_event(wd, event_info, event_type, ev_flag);
1229 if (st->count_ups == eina_list_count(st->l))
1231 /* Abort if we found a single click */
1232 if ((taps == 1) && (st->count_ups == 1))
1234 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1235 &st->info, EINA_FALSE);
1236 consume_event(wd, event_info, event_type, ev_flag);
1239 st->info.n = st->count_ups;
1240 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1241 &st->info, EINA_FALSE);
1242 consume_event(wd, event_info, event_type, ev_flag);
1249 case EVAS_CALLBACK_MULTI_MOVE:
1250 case EVAS_CALLBACK_MOUSE_MOVE:
1251 /* Get first event in first list, this has to be a Mouse Down event */
1252 /* and verify that user didn't move out of this area before next tap */
1253 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1256 pe_down = eina_list_data_get(pe_list);
1257 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1259 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1260 &st->info, EINA_FALSE);
1261 consume_event(wd, event_info, event_type, ev_flag);
1274 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1275 * This momentum value will be sent to widget when gesture is completed.
1277 * @param momentum pointer to buffer where we record momentum value.
1278 * @param x1 x coord where user started gesture.
1279 * @param y1 y coord where user started gesture.
1280 * @param x2 x coord where user completed gesture.
1281 * @param y2 y coord where user completed gesture.
1282 * @param t1x timestamp for X, when user started gesture.
1283 * @param t1y timestamp for Y, when user started gesture.
1284 * @param t2 timestamp when user completed gesture.
1286 * @ingroup Elm_Gesture_Layer
1289 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1290 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1293 Evas_Coord velx = 0, vely = 0, vel;
1294 Evas_Coord dx = x2 - x1;
1295 Evas_Coord dy = y2 - y1;
1299 velx = (dx * 1000) / dtx;
1302 vely = (dy * 1000) / dty;
1304 vel = sqrt((velx * velx) + (vely * vely));
1306 if ((_elm_config->thumbscroll_friction > 0.0) &&
1307 (vel > _elm_config->thumbscroll_momentum_threshold))
1308 { /* report momentum */
1309 momentum->mx = velx;
1310 momentum->my = vely;
1322 * This function is used for computing rotation angle (DEG).
1324 * @param x1 first finger x location.
1325 * @param y1 first finger y location.
1326 * @param x2 second finger x location.
1327 * @param y2 second finger y location.
1329 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1331 * @ingroup Elm_Gesture_Layer
1334 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1340 if (((int) xx) && ((int) yy))
1347 return RAD_360DEG - a;
1358 return RAD_180DEG + a;
1362 return RAD_180DEG - a;
1368 { /* Horizontal line */
1393 * This function is used for computing the magnitude and direction
1394 * of vector between two points.
1396 * @param x1 first finger x location.
1397 * @param y1 first finger y location.
1398 * @param x2 second finger x location.
1399 * @param y2 second finger y location.
1400 * @param l length computed (output)
1401 * @param a angle computed (output)
1403 * @ingroup Elm_Gesture_Layer
1406 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1407 Evas_Coord *l, double *a)
1412 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1413 *a = get_angle(x1, y1, x2, y2);
1417 _get_direction(Evas_Coord x1, Evas_Coord x2)
1430 * This function tests momentum gesture.
1431 * @param obj The gesture-layer object.
1432 * @param pe The recent input event as stored in pe struct.
1433 * @param event_info recent input event.
1434 * @param event_type recent event type.
1435 * @param g_type what Gesture we are testing.
1437 * @ingroup Elm_Gesture_Layer
1440 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1441 void *event_info, Evas_Callback_Type event_type,
1442 Elm_Gesture_Types g_type)
1444 Widget_Data *wd = elm_widget_data_get(obj);
1446 Gesture_Info *gesture = wd->gesture[g_type];
1447 if (!gesture ) return;
1449 if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1450 eina_list_count(wd->touched))
1451 return; /* user left a finger on device, do NOT start */
1453 Momentum_Type *st = gesture->data;
1455 { /* Allocated once on first time */
1456 st = calloc(1, sizeof(Momentum_Type));
1458 _momentum_test_reset(gesture);
1464 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1465 switch (pe->event_type)
1467 case EVAS_CALLBACK_MOUSE_DOWN:
1468 st->line_st.x = st->line_end.x = pe->x;
1469 st->line_st.y = st->line_end.y = pe->y;
1470 st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1471 st->xdir = st->ydir = 0;
1472 st->info.x2 = st->info.x1 = pe->x;
1473 st->info.y2 = st->info.y1 = pe->y;
1474 st->info.tx = st->info.ty = pe->timestamp;
1475 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1476 &st->info, EINA_FALSE);
1477 consume_event(wd, event_info, event_type, ev_flag);
1480 case EVAS_CALLBACK_MOUSE_UP:
1481 /* IGNORE if line info was cleared, like long press, move */
1485 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1487 /* Too long of a wait, reset all values */
1488 st->line_st.x = pe->x;
1489 st->line_st.y = pe->y;
1490 st->t_st_y = st->t_st_x = pe->timestamp;
1491 st->xdir = st->ydir = 0;
1494 st->info.x2 = pe->x;
1495 st->info.y2 = pe->y;
1496 st->line_end.x = pe->x;
1497 st->line_end.y = pe->y;
1498 st->t_end = pe->timestamp;
1500 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1501 st->t_st_x, st->t_st_y, pe->timestamp);
1503 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1505 consume_event(wd, event_info, event_type, ev_flag);
1509 case EVAS_CALLBACK_MOUSE_MOVE:
1510 /* IGNORE if line info was cleared, like long press, move */
1514 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1516 /* Too long of a wait, reset all values */
1517 st->line_st.x = pe->x;
1518 st->line_st.y = pe->y;
1519 st->t_st_y = st->t_st_x = pe->timestamp;
1520 st->info.tx = st->t_st_x;
1521 st->info.ty = st->t_st_y;
1522 st->xdir = st->ydir = 0;
1527 xdir = _get_direction(st->line_end.x, pe->x);
1528 ydir = _get_direction(st->line_end.y, pe->y);
1529 if (!xdir || (xdir == (-st->xdir)))
1531 st->line_st.x = st->line_end.x;
1532 st->info.tx = st->t_st_x = st->t_end;
1536 if (!ydir || (ydir == (-st->ydir)))
1538 st->line_st.y = st->line_end.y;
1539 st->info.ty = st->t_st_y = st->t_end;
1544 st->info.x2 = st->line_end.x = pe->x;
1545 st->info.y2 = st->line_end.y = pe->y;
1546 st->t_end = pe->timestamp;
1547 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1548 st->t_st_x, st->t_st_y, pe->timestamp);
1549 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE, &st->info,
1551 consume_event(wd, event_info, event_type, ev_flag);
1554 case EVAS_CALLBACK_MULTI_UP:
1555 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1557 consume_event(wd, event_info, event_type, ev_flag);
1566 compare_line_device(const void *data1, const void *data2)
1567 { /* Compare device component of line struct */
1568 const Line_Data *ln1 = data1;
1569 const int *device = data2;
1571 if (ln1->t_st) /* Compare only with lines that started */
1572 return (ln1->device - (*device));
1580 * This function construct line struct from input.
1581 * @param info pointer to store line momentum.
1582 * @param st line info to store input data.
1583 * @param pe The recent input event as stored in pe struct.
1585 * @ingroup Elm_Gesture_Layer
1588 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1590 { /* Record events and set momentum for line pointed by st */
1594 switch (pe->event_type)
1596 case EVAS_CALLBACK_MOUSE_DOWN:
1597 case EVAS_CALLBACK_MULTI_DOWN:
1598 st->line_st.x = pe->x;
1599 st->line_st.y = pe->y;
1600 st->t_st = pe->timestamp;
1601 st->device = pe->device;
1602 info->momentum.x1 = pe->x;
1603 info->momentum.y1 = pe->y;
1604 info->momentum.tx = pe->timestamp;
1605 info->momentum.ty = pe->timestamp;
1610 case EVAS_CALLBACK_MOUSE_UP:
1611 case EVAS_CALLBACK_MULTI_UP:
1612 /* IGNORE if line info was cleared, like long press, move */
1616 st->line_end.x = pe->x;
1617 st->line_end.y = pe->y;
1618 st->t_end = pe->timestamp;
1621 case EVAS_CALLBACK_MOUSE_MOVE:
1622 case EVAS_CALLBACK_MULTI_MOVE:
1623 /* IGNORE if line info was cleared, like long press, move */
1634 _line_data_reset(st);
1638 info->momentum.x2 = pe->x;
1639 info->momentum.y2 = pe->y;
1640 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1641 st->t_st, st->t_st, pe->timestamp);
1649 * This function test for (n) line gesture.
1650 * @param obj The gesture-layer object.
1651 * @param pe The recent input event as stored in pe struct.
1652 * @param event_info Original input event pointer.
1653 * @param event_type Type of original input event.
1654 * @param g_type what Gesture we are testing.
1656 * @ingroup Elm_Gesture_Layer
1659 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1660 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1664 Widget_Data *wd = elm_widget_data_get(obj);
1666 Gesture_Info *gesture = wd->gesture[g_type];
1667 if (!gesture ) return;
1669 if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1670 eina_list_count(wd->touched))
1671 return; /* user left a finger on device, do NOT start */
1673 Line_Type *st = gesture->data;
1676 st = calloc(1, sizeof(Line_Type));
1680 Line_Data *line = NULL;
1681 Eina_List *list = st->list;
1682 unsigned int i, cnt = eina_list_count(list);
1685 { /* list is not empty, locate this device on list */
1686 line = (Line_Data *) eina_list_search_unsorted(st->list,
1687 compare_line_device, &pe->device);
1690 { /* Try to locate an empty-node */
1691 for (i = 0; i < cnt; i++)
1693 line = eina_list_nth(list, i);
1695 break; /* Found a free node */
1703 { /* List is empty or device not found, new line-struct on START only */
1704 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1705 (event_type == EVAS_CALLBACK_MULTI_DOWN))
1706 { /* Allocate new item on START */
1707 line = calloc(1, sizeof(Line_Data));
1708 _line_data_reset(line);
1709 list = eina_list_append(list, line);
1714 if (!line) /* This may happen on MOVE that comes before DOWN */
1715 return; /* No line-struct to work with, can't continue testing */
1718 if (_single_line_process(&st->info, line, pe)) /* update st with input */
1719 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1721 /* Get direction and magnitude of the line */
1723 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1724 &line->line_length, &angle);
1726 /* These are used later to compare lines length */
1727 Evas_Coord shortest_line_len = line->line_length;
1728 Evas_Coord longest_line_len = line->line_length;
1729 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1731 /* Now update line-state */
1733 { /* Analyze line only if line started */
1734 if (line->line_angle >= 0.0)
1735 { /* if line direction was set, we test if broke tolerance */
1736 double a = fabs(angle - line->line_angle);
1738 double d = (tan(a)) * line->line_length; /* Distance from line */
1739 #if defined(DEBUG_GESTURE_LAYER)
1740 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
1742 if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
1743 { /* Broke tolerance: abort line and start a new one */
1744 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1745 &st->info, EINA_FALSE);
1746 consume_event(wd, event_info, event_type, ev_flag);
1751 { /* Record the line angle as it broke minimum length for line */
1752 if (line->line_length >= wd->line_min_length)
1753 st->info.angle = line->line_angle = angle;
1758 if (line->line_angle < 0.0)
1759 { /* it's not a line, too short more close to a tap */
1760 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1761 &st->info, EINA_FALSE);
1762 consume_event(wd, event_info, event_type, ev_flag);
1768 /* Count how many lines already started / ended */
1771 unsigned int tm_start = pe->timestamp;
1772 unsigned int tm_end = pe->timestamp;
1775 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1776 Eina_Bool lines_parallel = EINA_TRUE;
1777 EINA_LIST_FOREACH(list, l, t_line)
1780 base_angle = t_line->line_angle;
1783 if (t_line->line_angle >= 0)
1784 { /* Compare angle only with lines with direction defined */
1785 if (fabs(base_angle - t_line->line_angle) >
1786 wd->line_angular_tolerance)
1787 lines_parallel = EINA_FALSE;
1791 if (t_line->line_length)
1792 { /* update only if this line is used */
1793 if (shortest_line_len > t_line->line_length)
1794 shortest_line_len = t_line->line_length;
1796 if (longest_line_len < t_line->line_length)
1797 longest_line_len = t_line->line_length;
1803 if (t_line->t_st < tm_start)
1804 tm_start = t_line->t_st;
1810 if (t_line->t_end < tm_end)
1811 tm_end = t_line->t_end;
1815 st->info.n = started;
1819 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1820 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
1821 { /* user lift one finger then starts again without line-end - ABORT */
1822 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1824 consume_event(wd, event_info, event_type, ev_flag);
1828 if (!lines_parallel)
1829 { /* Lines are NOT at same direction, abort this gesture */
1830 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1832 consume_event(wd, event_info, event_type, ev_flag);
1837 /* We report ABORT if lines length are NOT matching when fingers are up */
1838 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
1840 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1842 consume_event(wd, event_info, event_type, ev_flag);
1846 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
1847 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
1848 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1850 consume_event(wd, event_info, event_type, ev_flag);
1856 case EVAS_CALLBACK_MOUSE_UP:
1857 case EVAS_CALLBACK_MULTI_UP:
1858 if ((started) && (started == ended))
1860 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
1861 &st->info, EINA_FALSE);
1862 consume_event(wd, event_info, event_type, ev_flag);
1867 case EVAS_CALLBACK_MOUSE_DOWN:
1868 case EVAS_CALLBACK_MULTI_DOWN:
1871 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1872 &st->info, EINA_TRUE);
1873 consume_event(wd, event_info, event_type, ev_flag);
1878 case EVAS_CALLBACK_MOUSE_MOVE:
1879 case EVAS_CALLBACK_MULTI_MOVE:
1882 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1883 &st->info, EINA_TRUE);
1884 consume_event(wd, event_info, event_type, ev_flag);
1890 return; /* Unhandeld event type */
1897 * This function is used to check if rotation gesture started.
1898 * @param st Contains current rotation values from user input.
1899 * @return TRUE/FALSE if we need to set rotation START.
1901 * @ingroup Elm_Gesture_Layer
1904 rotation_broke_tolerance(Rotate_Type *st)
1906 if (st->info.base_angle < 0)
1907 return EINA_FALSE; /* Angle has to be computed first */
1909 if (st->rotate_angular_tolerance < 0)
1912 double low = st->info.base_angle - st->rotate_angular_tolerance;
1913 double high = st->info.base_angle + st->rotate_angular_tolerance;
1914 double t = st->info.angle;
1927 if (high > RAD_360DEG)
1938 #if defined(DEBUG_GESTURE_LAYER)
1939 printf("%s angle=<%d> low=<%d> high=<%d>\n", __func__, t, low, high);
1941 if ((t < low) || (t > high))
1942 { /* This marks that roation action has started */
1943 st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
1944 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
1954 * This function is used for computing the gap between fingers.
1955 * It returns the length and center point between fingers.
1957 * @param x1 first finger x location.
1958 * @param y1 first finger y location.
1959 * @param x2 second finger x location.
1960 * @param y2 second finger y location.
1961 * @param x Gets center point x cord (output)
1962 * @param y Gets center point y cord (output)
1964 * @return length of the line between (x1,y1), (x2,y2) in pixels.
1966 * @ingroup Elm_Gesture_Layer
1969 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
1970 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
1972 double a, b, xx, yy, gap;
1975 gap = sqrt(xx*xx + yy*yy);
1977 /* START - Compute zoom center point */
1978 /* The triangle defined as follows:
1986 * http://en.wikipedia.org/wiki/Trigonometric_functions
1987 *************************************/
1988 if (((int) xx) && ((int) yy))
1990 double A = atan((yy / xx));
1991 #if defined(DEBUG_GESTURE_LAYER)
1992 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
1994 a = (Evas_Coord) ((gap / 2) * sin(A));
1995 b = (Evas_Coord) ((gap / 2) * cos(A));
1996 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
1997 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2002 { /* horiz line, take half width */
2003 #if defined(DEBUG_GESTURE_LAYER)
2004 printf("==== HORIZ ====\n");
2006 *x = (Evas_Coord) (xx / 2);
2007 *y = (Evas_Coord) (y1);
2011 { /* vert line, take half width */
2012 #if defined(DEBUG_GESTURE_LAYER)
2013 printf("==== VERT ====\n");
2015 *x = (Evas_Coord) (x1);
2016 *y = (Evas_Coord) (yy / 2);
2019 /* END - Compute zoom center point */
2021 return (Evas_Coord) gap;
2027 * This function is used for computing zoom value.
2029 * @param st Pointer to zoom data based on user input.
2030 * @param x1 first finger x location.
2031 * @param y1 first finger y location.
2032 * @param x2 second finger x location.
2033 * @param y2 second finger y location.
2034 * @param factor zoom-factor, used to determine how fast zoom works.
2036 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2038 * @ingroup Elm_Gesture_Layer
2040 /* FIXME change float to double */
2042 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2043 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2046 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2047 &st->info.x, &st->info.y);
2049 st->info.radius = diam / 2;
2053 st->zoom_base = diam;
2054 return st->info.zoom;
2057 if (st->zoom_distance_tolerance)
2058 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2059 if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2060 { /* avoid jump with zoom value when break tolerance */
2061 st->zoom_base -= st->zoom_distance_tolerance;
2062 st->zoom_distance_tolerance = 0;
2065 if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2066 { /* avoid jump with zoom value when break tolerance */
2067 st->zoom_base += st->zoom_distance_tolerance;
2068 st->zoom_distance_tolerance = 0;
2074 /* We use factor only on the difference between gap-base */
2075 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2076 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2077 (float) st->zoom_base) * zoom_finger_factor));
2080 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2081 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2092 * This function handles zoom with mouse wheel.
2093 * thats a combination of wheel + CTRL key.
2094 * @param obj The gesture-layer object.
2095 * @param event_info Original input event pointer.
2096 * @param event_type Type of original input event.
2097 * @param g_type what Gesture we are testing.
2099 * @ingroup Elm_Gesture_Layer
2102 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2103 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2105 Widget_Data *wd = elm_widget_data_get(obj);
2107 if (!wd->gesture[g_type]) return;
2109 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2110 Zoom_Type *st = gesture_zoom->data;
2111 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2113 { /* Allocated once on first time, used for zoom intermediate data */
2114 st = calloc(1, sizeof(Zoom_Type));
2115 gesture_zoom->data = st;
2116 _zoom_test_reset(gesture_zoom);
2121 case EVAS_CALLBACK_KEY_UP:
2123 Evas_Event_Key_Up *p = event_info;
2124 if ((!strcmp(p->keyname, "Control_L")) ||
2125 (!strcmp(p->keyname, "Control_R")))
2126 { /* Test if we ended a zoom gesture when releasing CTRL */
2127 if ((st->zoom_wheel) &&
2128 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2129 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2130 { /* User released CTRL after zooming */
2131 ev_flag = _set_state(gesture_zoom,
2132 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2133 consume_event(wd, event_info, event_type, ev_flag);
2141 case EVAS_CALLBACK_MOUSE_WHEEL:
2144 Elm_Gesture_State s;
2145 if (!evas_key_modifier_is_set(
2146 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2148 { /* if using wheel witout CTRL after starting zoom */
2149 if ((st->zoom_wheel) &&
2150 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2151 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2153 ev_flag = _set_state(gesture_zoom,
2154 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2155 consume_event(wd, event_info, event_type, ev_flag);
2160 return; /* Ignore mouse-wheel without control */
2163 /* Using mouse wheel with CTRL for zoom */
2164 if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2165 { /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2166 we continue a zoom gesture */
2168 s = ELM_GESTURE_STATE_MOVE;
2171 { /* On first wheel event, report START */
2173 s = ELM_GESTURE_STATE_START;
2176 st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2177 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2178 st->info.x = st->zoom_wheel->canvas.x;
2179 st->info.y = st->zoom_wheel->canvas.y;
2181 if (st->zoom_wheel->z > 0) /* zoom in */
2182 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2184 if (st->zoom_wheel->z < 0) /* zoom out */
2185 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2187 if (st->info.zoom < 0.0)
2188 st->info.zoom = 0.0;
2190 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2191 consume_event(wd, event_info, event_type, ev_flag);
2203 * This function is used to test zoom gesture.
2204 * user may combine zoom, rotation together.
2205 * so its possible that both will be detected from input.
2206 * (both are two-finger movement-oriented gestures)
2208 * @param obj The gesture-layer object.
2209 * @param event_info Pointer to recent input event.
2210 * @param event_type Recent input event type.
2211 * @param g_type what Gesture we are testing.
2213 * @ingroup Elm_Gesture_Layer
2216 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2217 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2221 Widget_Data *wd = elm_widget_data_get(obj);
2223 if (!wd->gesture[g_type]) return;
2225 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2226 Zoom_Type *st = gesture_zoom->data;
2229 { /* Allocated once on first time, used for zoom data */
2230 st = calloc(1, sizeof(Zoom_Type));
2231 gesture_zoom->data = st;
2232 _zoom_test_reset(gesture_zoom);
2235 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2238 case EVAS_CALLBACK_MOUSE_DOWN:
2239 consume_event(wd, event_info, event_type, ev_flag);
2240 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2244 case EVAS_CALLBACK_MOUSE_MOVE:
2245 consume_event(wd, event_info, event_type, ev_flag);
2246 if (!st->zoom_st.timestamp)
2247 return; /* we got move event before down event.Ignore it */
2249 consume_event(wd, event_info, event_type, ev_flag);
2250 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2252 /* We match this point to previous multi-move or multi-down event */
2253 if (st->zoom_mv1.timestamp)
2255 st->info.zoom = compute_zoom(st,
2256 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2257 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2258 wd->zoom_finger_factor);
2262 if (st->zoom_st1.timestamp)
2264 st->info.zoom = compute_zoom(st,
2265 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2266 st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2267 wd->zoom_finger_factor);
2273 case EVAS_CALLBACK_MULTI_MOVE:
2274 if (!st->zoom_st1.timestamp)
2275 return; /* We get move event before down event.Ignore it */
2277 consume_event(wd, event_info, event_type, ev_flag);
2278 if (st->zoom_mv1.timestamp)
2280 if (st->zoom_mv1.device !=
2281 ((Evas_Event_Multi_Move *) event_info)->device)
2282 { /* A third finger on screen, abort zoom */
2283 ev_flag = _set_state(gesture_zoom,
2284 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2285 consume_event(wd, event_info, event_type, ev_flag);
2291 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2293 /* Match this point to previous mouse-move or mouse-down event */
2294 if (st->zoom_mv.timestamp)
2296 st->info.zoom = compute_zoom(st,
2297 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2298 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2299 wd->zoom_finger_factor);
2303 if (st->zoom_st.timestamp)
2305 st->info.zoom = compute_zoom(st,
2306 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2307 st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2308 wd->zoom_finger_factor);
2314 case EVAS_CALLBACK_MULTI_DOWN:
2315 consume_event(wd, event_info, event_type, ev_flag);
2316 memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2319 case EVAS_CALLBACK_MOUSE_UP:
2320 case EVAS_CALLBACK_MULTI_UP:
2321 /* Reset timestamp of finger-up.This is used later
2322 by _zoom_test_reset() to retain finger-down data */
2323 consume_event(wd, event_info, event_type, ev_flag);
2324 if (((st->zoom_wheel) || (st->zoom_base)) &&
2325 (st->zoom_distance_tolerance == 0))
2327 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2328 &st->info, EINA_FALSE);
2329 consume_event(wd, event_info, event_type, ev_flag);
2334 /* if we got here not a ZOOM */
2335 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2336 { /* Must be != undefined, if gesture started */
2337 ev_flag = _set_state(gesture_zoom,
2338 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2339 consume_event(wd, event_info, event_type, ev_flag);
2342 _zoom_test_reset(gesture_zoom);
2351 if (!st->zoom_distance_tolerance)
2352 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2353 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2355 { /* Zoom broke tolerance, report move */
2356 double d = st->info.zoom - st->next_step;
2360 if (d >= wd->zoom_step)
2361 { /* Report move in steps */
2362 st->next_step = st->info.zoom;
2364 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2365 &st->info, EINA_TRUE);
2366 consume_event(wd, event_info, event_type, ev_flag);
2373 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2374 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2375 { /* report zoom start finger location is zoom-center temporarly */
2376 /* Zoom may have started with mouse-wheel, don't report START */
2377 if ((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2378 { /* Set zoom-base after BOTH down events were recorded */
2379 /* Compute length of line between fingers on zoom start */
2380 st->info.zoom = 1.0;
2381 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2382 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2383 &st->info.x, &st->info.y);
2385 st->info.radius = st->zoom_base / 2;
2387 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2388 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2389 { /* Report START only when two fingers touching */
2390 ev_flag = _set_state(gesture_zoom,
2391 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2392 consume_event(wd, event_info, event_type, ev_flag);
2401 _get_rotate_properties(Rotate_Type *st,
2402 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2403 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2406 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2407 &st->info.x, &st->info.y) / 2;
2409 *angle = get_angle(x1, y1, x2, y2);
2410 #if 0 /* (NOT YET SUPPORTED) */
2411 if (angle == &st->info.angle)
2412 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2413 st->info.momentum = (((*angle) - st->info.base_angle) /
2414 (fabs(tm2 - tm1))) * 1000;
2417 st->info.momentum = 0;
2427 * This function is used to test rotation gesture.
2428 * user may combine zoom, rotation together.
2429 * so its possible that both will be detected from input.
2430 * (both are two-finger movement-oriented gestures)
2432 * @param obj The gesture-layer object.
2433 * @param event_info Pointer to recent input event.
2434 * @param event_type Recent input event type.
2435 * @param g_type what Gesture we are testing.
2437 * @ingroup Elm_Gesture_Layer
2440 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2441 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2446 Widget_Data *wd = elm_widget_data_get(obj);
2448 if (!wd->gesture[g_type]) return;
2450 Gesture_Info *gesture = wd->gesture[g_type];
2451 Rotate_Type *st = gesture->data;
2456 { /* Allocated once on first time */
2457 st = calloc(1, sizeof(Rotate_Type));
2459 _rotate_test_reset(gesture);
2463 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2467 case EVAS_CALLBACK_MOUSE_DOWN:
2468 consume_event(wd, event_info, event_type, ev_flag);
2469 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2473 case EVAS_CALLBACK_MOUSE_MOVE:
2474 if (!st->rotate_st.timestamp)
2475 break; /* We got move event before down event.Ignore it */
2477 consume_event(wd, event_info, event_type, ev_flag);
2478 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2480 /* Match this point to previous multi-move or multi-down event */
2481 if (st->rotate_mv1.timestamp)
2482 { /* Compute rotation angle and report to user */
2483 _get_rotate_properties(st,
2484 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2485 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2490 if (st->rotate_st1.timestamp)
2491 { /* Compute rotation angle and report to user */
2492 _get_rotate_properties(st,
2493 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2494 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2501 case EVAS_CALLBACK_MULTI_MOVE:
2502 if (!st->rotate_st1.timestamp)
2503 break; /* We got move event before down event.Ignore it */
2505 consume_event(wd, event_info, event_type, ev_flag);
2506 if (st->rotate_mv1.timestamp)
2508 if (st->rotate_mv1.device !=
2509 ((Evas_Event_Multi_Move *) event_info)->device)
2510 { /* A third finger on screen, abort rotate */
2511 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2512 &st->info, EINA_FALSE);
2513 consume_event(wd, event_info, event_type, ev_flag);
2519 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2521 /* Match this point to previous mouse-move or mouse-down event */
2522 if (st->rotate_mv.timestamp)
2523 { /* Compute rotation angle and report to user */
2524 _get_rotate_properties(st,
2525 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2526 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2531 if (st->rotate_st.timestamp)
2532 { /* Compute rotation angle and report to user */
2533 _get_rotate_properties(st,
2534 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2535 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2542 case EVAS_CALLBACK_MULTI_DOWN:
2543 consume_event(wd, event_info, event_type, ev_flag);
2544 memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2545 _get_rotate_properties(st,
2546 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2547 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2551 case EVAS_CALLBACK_MOUSE_UP:
2552 case EVAS_CALLBACK_MULTI_UP:
2553 consume_event(wd, event_info, event_type, ev_flag);
2554 /* Reset timestamp of finger-up.This is used later
2555 by rotate_test_reset() to retain finger-down data */
2556 if (st->rotate_angular_tolerance < 0)
2558 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2559 &st->info, EINA_FALSE);
2560 consume_event(wd, event_info, event_type, ev_flag);
2565 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2566 { /* Must be != undefined, if gesture started */
2567 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2568 &st->info, EINA_FALSE);
2569 consume_event(wd, event_info, event_type, ev_flag);
2572 _rotate_test_reset(gesture);
2579 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2580 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2581 { /* Report MOVE or ABORT for *MOVE event */
2582 if (rotation_broke_tolerance(st))
2583 { /* Rotation broke tolerance, report move */
2584 double d = st->info.angle - st->next_step;
2588 if (d >= wd->rotate_step)
2589 { /* Report move in steps */
2590 st->next_step = st->info.angle;
2592 ev_flag = _set_state(gesture,
2593 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2594 consume_event(wd, event_info, event_type, ev_flag);
2601 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2602 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2604 if ((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2605 { /* two-fingers on touch screen - report rotate start */
2606 /* Set base angle, then report start. */
2607 _get_rotate_properties(st,
2608 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2609 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2610 &st->info.base_angle);
2612 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2613 &st->info, EINA_FALSE);
2614 consume_event(wd, event_info, event_type, ev_flag);
2624 * This function is used to save input events in an abstract struct
2625 * to be used later by getsure-testing functions.
2627 * @param data The gesture-layer object.
2628 * @param event_info Pointer to recent input event.
2629 * @param event_type Recent input event type.
2630 * @param pe The abstract data-struct (output).
2632 * @ingroup Elm_Gesture_Layer
2635 _make_pointer_event(void *data, void *event_info,
2636 Evas_Callback_Type event_type, Pointer_Event *pe)
2638 Widget_Data *wd = elm_widget_data_get(data);
2639 if (!wd) return EINA_FALSE;
2643 case EVAS_CALLBACK_MOUSE_DOWN:
2644 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2645 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2646 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2647 pe->device = ELM_MOUSE_DEVICE;
2650 case EVAS_CALLBACK_MOUSE_UP:
2651 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2652 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2653 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2654 pe->device = ELM_MOUSE_DEVICE;
2657 case EVAS_CALLBACK_MOUSE_MOVE:
2658 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2659 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2660 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2661 pe->device = ELM_MOUSE_DEVICE;
2664 case EVAS_CALLBACK_MULTI_DOWN:
2665 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2666 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2667 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2668 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2671 case EVAS_CALLBACK_MULTI_UP:
2672 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2673 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2674 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2675 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2678 case EVAS_CALLBACK_MULTI_MOVE:
2679 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2680 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2681 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2682 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2689 pe->event_type = event_type;
2696 * This function the core-function where input handling is done.
2697 * Here we get user input and stream it to gesture testing.
2698 * We notify user about any gestures with new state:
2700 * START - gesture started.
2701 * MOVE - gesture is ongoing.
2702 * END - gesture was completed.
2703 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
2705 * We also check if a gesture was detected, then reset event history
2706 * If no gestures were found we reset gesture test flag
2707 * after streaming event-history to widget.
2708 * (stream to the widget all events not consumed as a gesture)
2710 * @param data The gesture-layer object.
2711 * @param event_info Pointer to recent input event.
2712 * @param event_type Recent input event type.
2714 * @ingroup Elm_Gesture_Layer
2717 _event_process(void *data, Evas_Object *obj __UNUSED__,
2718 void *event_info, Evas_Callback_Type event_type)
2721 Pointer_Event *pe = NULL;
2722 Widget_Data *wd = elm_widget_data_get(data);
2725 /* Start testing candidate gesture from here */
2726 if (_make_pointer_event(data, event_info, event_type, &_pe))
2729 if (IS_TESTED(ELM_GESTURE_N_TAPS))
2730 _dbl_click_test(data, pe, event_info, event_type,
2731 ELM_GESTURE_N_TAPS, 1);
2733 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
2734 _dbl_click_test(data, pe, event_info, event_type,
2735 ELM_GESTURE_N_DOUBLE_TAPS, 2);
2737 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
2738 _dbl_click_test(data, pe, event_info, event_type,
2739 ELM_GESTURE_N_TRIPLE_TAPS, 3);
2741 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
2742 _momentum_test(data, pe, event_info, event_type,
2743 ELM_GESTURE_MOMENTUM);
2745 if (IS_TESTED(ELM_GESTURE_N_LINES))
2746 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
2748 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
2749 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
2751 if (IS_TESTED(ELM_GESTURE_ZOOM))
2752 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
2754 if (IS_TESTED(ELM_GESTURE_ZOOM))
2755 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
2757 if (IS_TESTED(ELM_GESTURE_ROTATE))
2758 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
2760 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
2761 _event_history_add(data, event_info, event_type);
2762 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2763 (event_type == EVAS_CALLBACK_MULTI_UP))
2765 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
2768 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
2769 _event_history_add(data, event_info, event_type);
2773 /* we maintain list of touched devices*/
2774 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2775 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2777 wd->touched = _add_touched_device(wd->touched, pe);
2779 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2780 (event_type == EVAS_CALLBACK_MULTI_UP))
2782 wd->touched = _remove_touched_device(wd->touched, pe);
2785 /* Report current states and clear history if needed */
2786 _clear_if_finished(data);
2791 * For all _mouse_* / multi_* functions wethen send this event to
2792 * _event_process function.
2794 * @param data The gesture-layer object.
2795 * @param event_info Pointer to recent input event.
2797 * @ingroup Elm_Gesture_Layer
2800 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2803 Widget_Data *wd = elm_widget_data_get(data);
2805 if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
2806 return; /* We only process left-click at the moment */
2808 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
2812 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2815 Widget_Data *wd = elm_widget_data_get(data);
2818 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
2822 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2825 Widget_Data *wd = elm_widget_data_get(data);
2828 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
2832 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2835 Widget_Data *wd = elm_widget_data_get(data);
2838 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
2842 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2845 Widget_Data *wd = elm_widget_data_get(data);
2848 if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
2849 return; /* We only process left-click at the moment */
2851 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
2855 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2858 Widget_Data *wd = elm_widget_data_get(data);
2861 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
2865 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2868 Widget_Data *wd = elm_widget_data_get(data);
2871 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
2875 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2878 Widget_Data *wd = elm_widget_data_get(data);
2881 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
2885 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2888 Widget_Data *wd = elm_widget_data_get(data);
2891 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
2895 elm_gesture_layer_hold_events_get(Evas_Object *obj)
2897 Widget_Data *wd = elm_widget_data_get(obj);
2898 if (!wd) return EINA_FALSE;
2900 return !wd->repeat_events;
2904 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
2906 Widget_Data *wd = elm_widget_data_get(obj);
2909 wd->repeat_events = !r;
2913 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
2915 Widget_Data *wd = elm_widget_data_get(obj);
2925 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
2927 Widget_Data *wd = elm_widget_data_get(obj);
2933 wd->rotate_step = s;
2937 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
2939 Widget_Data *wd = elm_widget_data_get(obj);
2940 if (!wd) return EINA_FALSE;
2945 /* if was attached before, unregister callbacks first */
2947 _unregister_callbacks(obj);
2951 _register_callbacks(obj);
2956 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
2957 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
2959 Widget_Data *wd = elm_widget_data_get(obj);
2962 if (!wd->gesture[idx])
2963 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
2965 Gesture_Info *p = wd->gesture[idx];
2968 p->fn[cb_type].cb = cb;
2969 p->fn[cb_type].user_data = data;
2970 p->state = ELM_GESTURE_STATE_UNDEFINED;
2975 _disable_hook(Evas_Object *obj)
2977 if (elm_widget_disabled_get(obj))
2978 _unregister_callbacks(obj);
2980 _register_callbacks(obj);
2984 elm_gesture_layer_add(Evas_Object *parent)
2990 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2992 wd = ELM_NEW(Widget_Data);
2993 e = evas_object_evas_get(parent);
2994 if (!e) return NULL;
2995 obj = elm_widget_add(e);
2996 ELM_SET_WIDTYPE(widtype, "gesture_layer");
2997 elm_widget_type_set(obj, "gesture_layer");
2998 elm_widget_sub_object_add(parent, obj);
2999 elm_widget_data_set(obj, wd);
3000 elm_widget_del_hook_set(obj, _del_hook);
3001 elm_widget_disable_hook_set(obj, _disable_hook);
3004 wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3005 wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3006 wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3007 wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3008 wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3009 wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3010 wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3011 wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3012 wd->repeat_events = EINA_TRUE;
3014 #if defined(DEBUG_GESTURE_LAYER)
3015 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3016 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", 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);
3018 memset(wd->gesture, 0, sizeof(wd->gesture));