1 #include <Elementary.h>
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
6 #define ELM_MOUSE_DEVICE 0
7 #define ELM_GESTURE_ZOOM_FACTOR 1.0
8 #define ELM_GESTURE_ZOOM_WHEEL_FACTOR 0.05
9 #define ELM_GESTURE_ROTATION_TOLERANCE 0.034906585 /* Represents 2 DEG */
10 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
11 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
12 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
13 #define ELM_GESTURE_LINE_ANGLE_TOLERANCE 0.34906585 /* Represents 20 DEG */
14 #define FLICK_MAX_MS 60
15 #define DBL_CLICK_TIME 400
17 /* Some Trigo values */
18 #define RAD_90DEG M_PI_2
19 #define RAD_180DEG M_PI
20 #define RAD_270DEG (M_PI_2 * 3)
21 #define RAD_360DEG (M_PI * 2)
23 #define COPY_EVENT_INFO(P, EV) do { \
24 P = malloc(sizeof(*EV)); \
25 memcpy(P, 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_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_tolerance;
211 typedef struct _Rotate_Type Rotate_Type;
215 Evas_Object *target; /* Target Widget */
216 Event_History *event_history_list;
219 Evas_Coord zoom_tolerance;
220 Evas_Coord line_tolerance;
221 float zoom_wheel_factor; /* mouse wheel zoom steps */
222 float factor; /* used for zoom factor */
223 double rotate_tolerance;
228 Gesture_Info *gesture[ELM_GESTURE_LAST];
229 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
230 Eina_List *touched; /* List of devices with currently touched */
232 Eina_Bool repeat_events : 1;
234 typedef struct _Widget_Data Widget_Data;
236 static const char *widtype = NULL;
237 static void _del_hook(Evas_Object *obj);
239 static void _event_history_clear(Evas_Object *obj);
240 static void _reset_states(Widget_Data *wd);
241 static void _mouse_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
242 static void _mouse_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
243 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
244 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
245 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
246 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
247 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
248 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
250 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
251 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
252 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
255 _dbl_click_test_reset(Gesture_Info *gesture)
260 Widget_Data *wd = elm_widget_data_get(gesture->obj);
261 if (wd->dbl_timeout) ecore_timer_del(wd->dbl_timeout);
262 wd->dbl_timeout = NULL;
269 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
270 EINA_LIST_FREE(data, pe)
273 memset(gesture->data, 0, sizeof(Taps_Type));
279 * Sets event flag to value returned from user callback
280 * @param wd Widget Data
281 * @param event_info pointer to event.
282 * @param event_type what type was ev (mouse down, etc...)
283 * @param ev_flags event flags
285 * @ingroup Elm_Gesture_Layer
288 consume_event(Widget_Data *wd, void *event_info,
289 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
290 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
291 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used the event and g-layer */
292 /* should not refeed this event. */
293 if ((ev_flags) || (!wd->repeat_events))
297 case EVAS_CALLBACK_MOUSE_IN:
298 ((Evas_Event_Mouse_In *) event_info)->event_flags |= ev_flags;
300 case EVAS_CALLBACK_MOUSE_OUT:
301 ((Evas_Event_Mouse_Out *) event_info)->event_flags |= ev_flags;
303 case EVAS_CALLBACK_MOUSE_DOWN:
304 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
306 case EVAS_CALLBACK_MOUSE_MOVE:
307 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
309 case EVAS_CALLBACK_MOUSE_UP:
310 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
312 case EVAS_CALLBACK_MOUSE_WHEEL:
313 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
315 case EVAS_CALLBACK_MULTI_DOWN:
316 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
318 case EVAS_CALLBACK_MULTI_MOVE:
319 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
321 case EVAS_CALLBACK_MULTI_UP:
322 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
324 case EVAS_CALLBACK_KEY_UP:
325 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
336 * Report current state of a gesture by calling user callback.
337 * @param gesture what gesture state we report.
338 * @param info inforamtion for user callback
340 * @ingroup Elm_Gesture_Layer
342 static Evas_Event_Flags
343 _report_state(Gesture_Info *gesture, void *info)
344 { /* We report current state (START, MOVE, END, ABORT), once */
345 #if defined(DEBUG_GESTURE_LAYER)
346 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, g_type,
349 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
350 (gesture->fn[gesture->state].cb))
351 { /* Fill state-info struct and send ptr to user callback */
352 return gesture->fn[gesture->state].cb(
353 gesture->fn[gesture->state].user_data, info);
356 return EVAS_EVENT_FLAG_NONE;
362 * Update state for a given gesture.
363 * We may update gesture state to:
364 * UNDEFINED - current input did not start gesure yet.
365 * START - gesture started according to input.
366 * MOVE - gusture in progress.
367 * END - gesture completed according to input.
368 * ABORT - input does not matches gesure.
369 * note that we may move from UNDEFINED to ABORT
370 * because we may detect that gesture will not START
371 * with a given input.
373 * @param g given gesture to change state.
374 * @param s gesure new state.
375 * @param info buffer to be sent to user callback on report_state.
376 * @param force makes report_state to report the new-state even
377 * if its same as current state. Works for MOVE - gesture in progress.
379 * @ingroup Elm_Gesture_Layer
381 static Evas_Event_Flags
382 _set_state(Gesture_Info *g, Elm_Gesture_State s,
383 void *info, Eina_Bool force)
385 Elm_Gesture_State old_state;
386 if ((g->state == s) && (!force))
387 return EVAS_EVENT_FLAG_NONE;
389 old_state = g->state;
392 g->info = info; /* Information for user callback */
393 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
394 (g->state == ELM_GESTURE_STATE_END))
395 g->test = EINA_FALSE;
397 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
398 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
399 (s == ELM_GESTURE_STATE_ABORT))))
400 return _report_state(g, g->info);
402 return EVAS_EVENT_FLAG_NONE;
408 * This resets all gesture states and sets test-bit.
409 * this is used for restarting gestures to listen to input.
410 * happens after we complete a gesture or no gesture was detected.
411 * @param wd Widget data of the gesture-layer object.
413 * @ingroup Elm_Gesture_Layer
416 _reset_states(Widget_Data *wd)
420 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
425 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
434 * if gesture was NOT detected AND we only have gestures in ABORT state
435 * we clear history immediately to be ready for input.
437 * @param obj The gesture-layer object.
439 * @ingroup Elm_Gesture_Layer
442 _clear_if_finished(Evas_Object *obj)
444 Widget_Data *wd = elm_widget_data_get(obj);
448 /* Clear history if all we have aborted gestures */
449 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
450 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
451 { /* If no gesture started and all we have aborted gestures, reset all */
452 Gesture_Info *p = wd->gesture[i];
453 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
455 if ((p->state == ELM_GESTURE_STATE_START) ||
456 (p->state == ELM_GESTURE_STATE_MOVE))
457 reset_s = EINA_FALSE;
459 all_undefined = EINA_FALSE;
463 if (reset_s && !all_undefined)
464 _event_history_clear(obj);
468 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
470 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
489 * when this timer expires we ABORT double click gesture.
491 * @param data The gesture-layer object.
492 * @return cancles callback for this timer.
494 * @ingroup Elm_Gesture_Layer
497 _dbl_click_timeout(void *data)
499 Gesture_Info *gesture = data;
500 Widget_Data *wd = elm_widget_data_get(gesture->obj);
502 wd->dbl_timeout = NULL;
503 _set_state(gesture, ELM_GESTURE_STATE_ABORT,
504 gesture->info, EINA_FALSE);
506 _dbl_click_test_reset(gesture);
507 _clear_if_finished(gesture->obj);
508 return ECORE_CALLBACK_CANCEL;
511 /* All *test_reset() funcs are called to clear
512 * gesture intermediate data.
513 * This happens when we need to reset our tests.
514 * for example when gesture is detected or all ABORTed. */
516 _momentum_test_reset(Gesture_Info *gesture)
524 memset(gesture->data, 0, sizeof(Momentum_Type));
528 _line_data_reset(Line_Data *st)
533 memset(st, 0, sizeof(Line_Data));
534 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
538 _line_test_reset(Gesture_Info *gesture)
546 Line_Type *st = gesture->data;
547 Eina_List *list = st->list;
550 EINA_LIST_FOREACH(list, l, t_line)
553 eina_list_free(list);
558 _zoom_test_reset(Gesture_Info *gesture)
566 Widget_Data *wd = elm_widget_data_get(gesture->obj);
567 Zoom_Type *st = gesture->data;
568 Pointer_Event pe, pe1;
570 pe.timestamp = pe1.timestamp = 0;
572 if(st->zoom_st.timestamp)
573 memcpy(&pe, &st->zoom_st, sizeof(Pointer_Event));
575 if(st->zoom_st1.timestamp)
576 memcpy(&pe1, &st->zoom_st1, sizeof(Pointer_Event));
578 memset(st, 0, sizeof(Zoom_Type));
580 /* If user released one finger only, restore down-info */
581 if(pe.timestamp && (!pe1.timestamp))
582 memcpy(&st->zoom_st, &pe, sizeof(Pointer_Event));
584 if(pe1.timestamp && (!pe.timestamp))
585 memcpy(&st->zoom_st1, &pe1, sizeof(Pointer_Event));
586 st->zoom_tolerance = wd->zoom_tolerance;
591 _rotate_test_reset(Gesture_Info *gesture)
599 Widget_Data *wd = elm_widget_data_get(gesture->obj);
600 Rotate_Type *st = gesture->data;
601 Pointer_Event pe, pe1;
603 pe.timestamp = pe1.timestamp = 0;
605 if(st->rotate_st.timestamp)
606 memcpy(&pe, &st->rotate_st, sizeof(Pointer_Event));
608 if(st->rotate_st1.timestamp)
609 memcpy(&pe1, &st->rotate_st1, sizeof(Pointer_Event));
611 memset(st, 0, sizeof(Rotate_Type));
613 /* If user released one finger only, restore down-info */
614 if(pe.timestamp && (!pe1.timestamp))
615 memcpy(&st->rotate_st, &pe, sizeof(Pointer_Event));
617 if(pe1.timestamp && (!pe.timestamp))
618 memcpy(&st->rotate_st1, &pe1, sizeof(Pointer_Event));
621 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
622 st->rotate_tolerance = wd->rotate_tolerance;
629 * We register callbacks when gesture layer is attached to an object
630 * or when its enabled after disable.
632 * @param obj The gesture-layer object.
634 * @ingroup Elm_Gesture_Layer
637 _register_callbacks(Evas_Object *obj)
639 Widget_Data *wd = elm_widget_data_get(obj);
644 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_IN,
646 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_OUT,
649 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
651 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
653 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
656 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
659 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
661 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
663 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
666 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
673 * We unregister callbacks when gesture layer is disabled.
675 * @param obj The gesture-layer object.
677 * @ingroup Elm_Gesture_Layer
680 _unregister_callbacks(Evas_Object *obj)
682 Widget_Data *wd = elm_widget_data_get(obj);
687 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_IN,
689 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_OUT,
692 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
694 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
696 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
699 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
702 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
705 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
708 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
711 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb);
715 /* START - Event history list handling functions */
719 * This function reports ABORT to all none-detected gestures
720 * Then resets test bits for all desired gesures
721 * and clears input-events history.
722 * note: if no gesture was detected, events from history list
723 * are streamed to the widget because it's unused by layer.
724 * user may cancel refeed of events by setting repeat events.
726 * @param obj The gesture-layer object.
728 * @ingroup Elm_Gesture_Layer
731 _event_history_clear(Evas_Object *obj)
733 Widget_Data *wd = elm_widget_data_get(obj);
738 Evas *e = evas_object_evas_get(obj);
739 Eina_Bool gesture_found = EINA_FALSE;
740 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
745 if (p->state == ELM_GESTURE_STATE_END)
746 gesture_found = EINA_TRUE;
748 { /* Report ABORT to all gestures that still not finished */
749 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
755 _reset_states(wd); /* we are ready to start testing for gestures again */
757 /* Clear all gestures intermediate date */
758 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
759 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
760 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
761 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
762 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
763 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
764 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
765 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
767 /* Disable gesture layer so refeeded events won't be consumed by it */
768 _unregister_callbacks(obj);
769 while (wd->event_history_list)
772 t = wd->event_history_list;
774 /* Refeed events if no gesture matched input */
775 if ((!gesture_found) && (!wd->repeat_events))
776 evas_event_refeed_event(e, wd->event_history_list->event,
777 wd->event_history_list->event_type);
779 free(wd->event_history_list->event);
780 wd->event_history_list = (Event_History *) eina_inlist_remove(
781 EINA_INLIST_GET(wd->event_history_list),
782 EINA_INLIST_GET(wd->event_history_list));
785 _register_callbacks(obj);
789 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
791 Widget_Data *wd = elm_widget_data_get(obj);
793 if (!wd) return EINA_FALSE;
795 ev = malloc(sizeof(Event_History));
797 ev->event_type = event_type;
798 wd->event_history_list = (Event_History *) eina_inlist_append(
799 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
803 /* END - Event history list handling functions */
806 _del_hook(Evas_Object *obj)
808 Widget_Data *wd = elm_widget_data_get(obj);
811 eina_list_free(wd->touched);
812 _event_history_clear(obj);
814 if (!elm_widget_disabled_get(obj))
815 _unregister_callbacks(obj);
817 /* Free all gestures internal data structures */
819 for (i = 0; i < ELM_GESTURE_LAST; i++)
822 if (wd->gesture[i]->data)
823 free(wd->gesture[i]->data);
825 free(wd->gesture[i]);
832 compare_match_fingers(const void *data1, const void *data2)
833 { /* Compare coords of first item in list to cur coords */
834 const Pointer_Event *pe1 = eina_list_data_get(data1);
835 const Pointer_Event *pe2 = data2;
837 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
839 else if (pe1->x < pe2->x)
843 if (pe1->x == pe2->x)
844 return pe1->y - pe2->y;
851 compare_pe_device(const void *data1, const void *data2)
852 { /* Compare coords of first item in list to cur coords */
853 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
854 const Pointer_Event *pe2 = data2;
856 /* Only match if last was a down event */
857 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
858 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
862 if (pe1->device == pe2->device)
864 else if (pe1->device < pe2->device)
871 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe, Widget_Data *wd, void *event_info,
872 Evas_Callback_Type event_type)
873 { /* Keep copy of pe and record it in list */
874 Pointer_Event *p = malloc(sizeof(Pointer_Event));
875 memcpy(p, pe, sizeof(Pointer_Event));
876 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
882 /* This will also update middle-point to report to user later */
883 st->info.x = st->sum_x / st->n_taps;
884 st->info.y = st->sum_y / st->n_taps;
885 st->info.timestamp = pe->timestamp;
889 pe_list = eina_list_append(pe_list, p);
890 st->l = eina_list_append(st->l, pe_list);
893 pe_list = eina_list_append(pe_list, p);
901 * This function checks all click/tap and double/triple taps
903 * @param obj The gesture-layer object.
904 * @param pe The recent input event as stored in pe struct.
905 * @param event_info Original input event pointer.
906 * @param event_type Type of original input event.
907 * @param g_type what Gesture we are testing.
908 * @param taps How many click/taps we test for.
910 * @ingroup Elm_Gesture_Layer
913 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
914 void *event_info, Evas_Callback_Type event_type,
915 Elm_Gesture_Types g_type, int taps)
916 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
917 Widget_Data *wd = elm_widget_data_get(obj);
920 if (!pe) /* this happens when unhandled event arrived */
921 return; /* see _make_pointer_event function */
923 Gesture_Info *gesture = wd->gesture[g_type];
924 if (!gesture ) return;
926 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
927 eina_list_count(wd->touched))
928 return; /* user left a finger on device, do NOT start */
930 Taps_Type *st = gesture->data;
932 { /* Allocated once on first time */
933 st = calloc(1, sizeof(Taps_Type));
935 _dbl_click_test_reset(gesture);
938 Eina_List *pe_list = NULL;
939 Pointer_Event *pe_down = NULL;
940 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
941 switch (pe->event_type)
943 case EVAS_CALLBACK_MULTI_DOWN:
944 case EVAS_CALLBACK_MOUSE_DOWN:
945 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
946 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
947 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
948 { /* This is the first mouse down we got */
949 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
950 &st->info, EINA_FALSE);
951 consume_event(wd, event_info, event_type, ev_flag);
953 /* To test dbl_click/dbl_tap */
954 /* When this timer expires, gesture ABORTed if not completed */
955 if (!wd->dbl_timeout && (taps > 1))
956 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
963 case EVAS_CALLBACK_MULTI_UP:
964 case EVAS_CALLBACK_MOUSE_UP:
965 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
967 return; /* Got only first mouse_down and mouse_up */
969 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
971 if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
972 return; /* Got only first mouse_down and mouse_up */
974 /* Get first event in first list, this has to be Mouse Down event */
975 pe_down = eina_list_data_get(pe_list);
977 if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
983 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
984 &st->info, EINA_FALSE);
985 consume_event(wd, event_info, event_type, ev_flag);
989 if (st->count_ups == eina_list_count(st->l))
991 /* Abort if we found a single click */
992 if ((taps == 1) && (st->count_ups == 1))
994 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
995 &st->info, EINA_FALSE);
996 consume_event(wd, event_info, event_type, ev_flag);
999 st->info.n = st->count_ups;
1000 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1001 &st->info, EINA_FALSE);
1002 consume_event(wd, event_info, event_type, ev_flag);
1009 case EVAS_CALLBACK_MULTI_MOVE:
1010 case EVAS_CALLBACK_MOUSE_MOVE:
1011 /* Get first event in first list, this has to be a Mouse Down event */
1012 /* and verify that user didn't move out of this area before next tap */
1013 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1016 pe_down = eina_list_data_get(pe_list);
1017 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1019 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1020 &st->info, EINA_FALSE);
1021 consume_event(wd, event_info, event_type, ev_flag);
1034 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1035 * This momentum value will be sent to widget when gesture is completed.
1037 * @param momentum pointer to buffer where we record momentum value.
1038 * @param x1 x coord where user started gesture.
1039 * @param y1 y coord where user started gesture.
1040 * @param x2 x coord where user completed gesture.
1041 * @param y2 y coord where user completed gesture.
1042 * @param t1x timestamp for X, when user started gesture.
1043 * @param t1y timestamp for Y, when user started gesture.
1044 * @param t2 timestamp when user completed gesture.
1046 * @ingroup Elm_Gesture_Layer
1049 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1050 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1053 Evas_Coord velx = 0, vely = 0, vel;
1054 Evas_Coord dx = x2 - x1;
1055 Evas_Coord dy = y2 - y1;
1059 velx = (dx * 1000) / dtx;
1062 vely = (dy * 1000) / dty;
1064 vel = sqrt((velx * velx) + (vely * vely));
1066 if ((_elm_config->thumbscroll_friction > 0.0) &&
1067 (vel > _elm_config->thumbscroll_momentum_threshold))
1068 { /* report momentum */
1069 momentum->mx = velx;
1070 momentum->my = vely;
1082 * This function is used for computing rotation angle (DEG).
1084 * @param x1 first finger x location.
1085 * @param y1 first finger y location.
1086 * @param x2 second finger x location.
1087 * @param y2 second finger y location.
1089 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1091 * @ingroup Elm_Gesture_Layer
1094 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1100 if (((int) xx) && ((int) yy))
1107 return RAD_360DEG - a;
1118 return RAD_180DEG + a;
1122 return RAD_180DEG - a;
1128 { /* Horizontal line */
1153 * This function is used for computing the magnitude and direction
1154 * of vector between two points.
1156 * @param x1 first finger x location.
1157 * @param y1 first finger y location.
1158 * @param x2 second finger x location.
1159 * @param y2 second finger y location.
1160 * @param l length computed (output)
1161 * @param a angle computed (output)
1163 * @ingroup Elm_Gesture_Layer
1166 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1167 Evas_Coord *l, double *a)
1172 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1173 *a = get_angle(x1, y1, x2, y2);
1177 _get_direction(Evas_Coord x1, Evas_Coord x2)
1190 * This function tests momentum gesture.
1191 * @param obj The gesture-layer object.
1192 * @param pe The recent input event as stored in pe struct.
1193 * @param event_info recent input event.
1194 * @param event_type recent event type.
1195 * @param g_type what Gesture we are testing.
1197 * @ingroup Elm_Gesture_Layer
1200 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1201 void *event_info, Evas_Callback_Type event_type,
1202 Elm_Gesture_Types g_type)
1204 Widget_Data *wd = elm_widget_data_get(obj);
1206 Gesture_Info *gesture = wd->gesture[g_type];
1207 if (!gesture ) return;
1209 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1210 eina_list_count(wd->touched))
1211 return; /* user left a finger on device, do NOT start */
1213 Momentum_Type *st = gesture->data;
1215 { /* Allocated once on first time */
1216 st = calloc(1, sizeof(Momentum_Type));
1218 _momentum_test_reset(gesture);
1224 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1225 switch (pe->event_type)
1227 case EVAS_CALLBACK_MOUSE_DOWN:
1228 st->line_st.x = st->line_end.x = pe->x;
1229 st->line_st.y = st->line_end.y = pe->y;
1230 st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1231 st->xdir = st->ydir = 0;
1232 st->info.x2 = st->info.x1 = pe->x;
1233 st->info.y2 = st->info.y1 = pe->y;
1234 st->info.tx = st->info.ty = pe->timestamp;
1235 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1236 &st->info, EINA_FALSE);
1237 consume_event(wd, event_info, event_type, ev_flag);
1240 case EVAS_CALLBACK_MOUSE_UP:
1241 /* IGNORE if line info was cleared, like long press, move */
1245 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1247 /* Too long of a wait, reset all values */
1248 st->line_st.x = pe->x;
1249 st->line_st.y = pe->y;
1250 st->t_st_y = st->t_st_x = pe->timestamp;
1251 st->xdir = st->ydir = 0;
1254 st->info.x2 = pe->x;
1255 st->info.y2 = pe->y;
1256 st->line_end.x = pe->x;
1257 st->line_end.y = pe->y;
1258 st->t_end = pe->timestamp;
1260 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1261 st->t_st_x, st->t_st_y, pe->timestamp);
1263 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1265 consume_event(wd, event_info, event_type, ev_flag);
1269 case EVAS_CALLBACK_MOUSE_MOVE:
1270 /* IGNORE if line info was cleared, like long press, move */
1274 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1276 /* Too long of a wait, reset all values */
1277 st->line_st.x = pe->x;
1278 st->line_st.y = pe->y;
1279 st->t_st_y = st->t_st_x = pe->timestamp;
1280 st->info.tx = st->t_st_x;
1281 st->info.ty = st->t_st_y;
1282 st->xdir = st->ydir = 0;
1287 xdir = _get_direction(st->line_end.x, pe->x);
1288 ydir = _get_direction(st->line_end.y, pe->y);
1289 if (!xdir || (xdir == (-st->xdir)))
1291 st->line_st.x = st->line_end.x;
1292 st->info.tx = st->t_st_x = st->t_end;
1296 if (!ydir || (ydir == (-st->ydir)))
1298 st->line_st.y = st->line_end.y;
1299 st->info.ty = st->t_st_y = st->t_end;
1304 st->info.x2 = st->line_end.x = pe->x;
1305 st->info.y2 = st->line_end.y = pe->y;
1306 st->t_end = pe->timestamp;
1307 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1308 st->t_st_x, st->t_st_y, pe->timestamp);
1309 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE, &st->info,
1311 consume_event(wd, event_info, event_type, ev_flag);
1314 case EVAS_CALLBACK_MULTI_UP:
1315 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1317 consume_event(wd, event_info, event_type, ev_flag);
1326 compare_line_device(const void *data1, const void *data2)
1327 { /* Compare device component of line struct */
1328 const Line_Data *ln1 = data1;
1329 const int *device = data2;
1331 if (ln1->t_st) /* Compare only with lines that started */
1332 return (ln1->device - (*device));
1340 * This function construct line struct from input.
1341 * @param info pointer to store line momentum.
1342 * @param st line info to store input data.
1343 * @param pe The recent input event as stored in pe struct.
1345 * @ingroup Elm_Gesture_Layer
1348 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1350 { /* Record events and set momentum for line pointed by st */
1354 switch (pe->event_type)
1356 case EVAS_CALLBACK_MOUSE_DOWN:
1357 case EVAS_CALLBACK_MULTI_DOWN:
1358 st->line_st.x = pe->x;
1359 st->line_st.y = pe->y;
1360 st->t_st = pe->timestamp;
1361 st->device = pe->device;
1362 info->momentum.x1 = pe->x;
1363 info->momentum.y1 = pe->y;
1364 info->momentum.tx = pe->timestamp;
1365 info->momentum.ty = pe->timestamp;
1370 case EVAS_CALLBACK_MOUSE_UP:
1371 case EVAS_CALLBACK_MULTI_UP:
1372 /* IGNORE if line info was cleared, like long press, move */
1376 st->line_end.x = pe->x;
1377 st->line_end.y = pe->y;
1378 st->t_end = pe->timestamp;
1381 case EVAS_CALLBACK_MOUSE_MOVE:
1382 case EVAS_CALLBACK_MULTI_MOVE:
1383 /* IGNORE if line info was cleared, like long press, move */
1394 _line_data_reset(st);
1398 info->momentum.x2 = pe->x;
1399 info->momentum.y2 = pe->y;
1400 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1401 st->t_st, st->t_st, pe->timestamp);
1409 * This function test for (n) line gesture.
1410 * @param obj The gesture-layer object.
1411 * @param pe The recent input event as stored in pe struct.
1412 * @param event_info Original input event pointer.
1413 * @param event_type Type of original input event.
1414 * @param g_type what Gesture we are testing.
1416 * @ingroup Elm_Gesture_Layer
1419 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1420 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1424 Widget_Data *wd = elm_widget_data_get(obj);
1426 Gesture_Info *gesture = wd->gesture[g_type];
1427 if (!gesture ) return;
1429 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1430 eina_list_count(wd->touched))
1431 return; /* user left a finger on device, do NOT start */
1433 Line_Type *st = gesture->data;
1436 st = calloc(1, sizeof(Line_Type));
1440 Line_Data *line = NULL;
1441 Eina_List *list = st->list;
1442 unsigned int i, cnt = eina_list_count(list);
1445 { /* list is not empty, locate this device on list */
1446 line = (Line_Data *) eina_list_search_unsorted(st->list,
1447 compare_line_device, &pe->device);
1450 { /* Try to locate an empty-node */
1451 for (i = 0; i < cnt; i++)
1453 line = eina_list_nth(list, i);
1455 break; /* Found a free node */
1463 { /* List is empty or device not found, new line-struct on START only */
1464 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1465 (event_type == EVAS_CALLBACK_MULTI_DOWN))
1466 { /* Allocate new item on START */
1467 line = calloc(1, sizeof(Line_Data));
1468 _line_data_reset(line);
1469 list = eina_list_append(list, line);
1474 if (!line) /* This may happen on MOVE that comes before DOWN */
1475 return; /* No line-struct to work with, can't continue testing */
1478 if (_single_line_process(&st->info, line, pe)) /* update st with input */
1479 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1481 /* Get direction and magnitude of the line */
1483 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1484 &line->line_length, &angle);
1486 /* These are used later to compare lines length */
1487 Evas_Coord shortest_line_len = line->line_length;
1488 Evas_Coord longest_line_len = line->line_length;
1489 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1491 /* Now update line-state */
1493 { /* Analyze line only if line started */
1494 if (line->line_angle >= 0.0)
1495 { /* if line direction was set, we test if broke tolerance */
1496 double a = fabs(angle - line->line_angle);
1498 double d = (tan(a)) * line->line_length; /* Distance from line */
1499 #if defined(DEBUG_GESTURE_LAYER)
1500 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
1502 if((d > wd->line_tolerance) || (a > ELM_GESTURE_LINE_ANGLE_TOLERANCE))
1503 // if (a > ELM_GESTURE_LINE_ANGLE_TOLERANCE)
1504 { /* Broke tolerance: abort line and start a new one */
1505 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1506 &st->info, EINA_FALSE);
1507 consume_event(wd, event_info, event_type, ev_flag);
1512 { /* Record the line angle as it broke minimum length for line */
1513 if (line->line_length >= wd->line_min_length)
1514 st->info.angle = line->line_angle = angle;
1519 if (line->line_angle < 0.0)
1520 { /* it's not a line, too short more close to a tap */
1521 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1522 &st->info, EINA_FALSE);
1523 consume_event(wd, event_info, event_type, ev_flag);
1529 /* Count how many lines already started / ended */
1532 unsigned int tm_start = pe->timestamp;
1533 unsigned int tm_end = pe->timestamp;
1536 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1537 Eina_Bool lines_parallel = EINA_TRUE;
1538 EINA_LIST_FOREACH(list, l, t_line)
1541 base_angle = t_line->line_angle;
1544 if (t_line->line_angle >= 0)
1545 { /* Compare angle only with lines with direction defined */
1546 if (fabs(base_angle - t_line->line_angle) >
1547 ELM_GESTURE_LINE_ANGLE_TOLERANCE)
1548 lines_parallel = EINA_FALSE;
1552 if (t_line->line_length)
1553 { /* update only if this line is used */
1554 if (shortest_line_len > t_line->line_length)
1555 shortest_line_len = t_line->line_length;
1557 if (longest_line_len < t_line->line_length)
1558 longest_line_len = t_line->line_length;
1564 if (t_line->t_st < tm_start)
1565 tm_start = t_line->t_st;
1571 if (t_line->t_end < tm_end)
1572 tm_end = t_line->t_end;
1576 st->info.n = started;
1580 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1581 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
1582 { /* user lift one finger then starts again without line-end - ABORT */
1583 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1585 consume_event(wd, event_info, event_type, ev_flag);
1589 if (!lines_parallel)
1590 { /* Lines are NOT at same direction, abort this gesture */
1591 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1593 consume_event(wd, event_info, event_type, ev_flag);
1598 /* We report ABORT if lines length are NOT matching when fingers are up */
1599 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
1601 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1603 consume_event(wd, event_info, event_type, ev_flag);
1607 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > FLICK_MAX_MS))
1608 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
1609 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1611 consume_event(wd, event_info, event_type, ev_flag);
1617 case EVAS_CALLBACK_MOUSE_UP:
1618 case EVAS_CALLBACK_MULTI_UP:
1619 if ((started) && (started == ended))
1621 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
1622 &st->info, EINA_FALSE);
1623 consume_event(wd, event_info, event_type, ev_flag);
1628 case EVAS_CALLBACK_MOUSE_DOWN:
1629 case EVAS_CALLBACK_MULTI_DOWN:
1632 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1633 &st->info, EINA_TRUE);
1634 consume_event(wd, event_info, event_type, ev_flag);
1639 case EVAS_CALLBACK_MOUSE_MOVE:
1640 case EVAS_CALLBACK_MULTI_MOVE:
1643 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1644 &st->info, EINA_TRUE);
1645 consume_event(wd, event_info, event_type, ev_flag);
1651 return; /* Unhandeld event type */
1658 * This function is used to check if rotation gesture started.
1659 * @param st Contains current rotation values from user input.
1660 * @return TRUE/FALSE if we need to set rotation START.
1662 * @ingroup Elm_Gesture_Layer
1665 rotation_broke_tolerance(Rotate_Type *st)
1667 if (st->info.base_angle < 0)
1668 return EINA_FALSE; /* Angle has to be computed first */
1670 if (st->rotate_tolerance < 0)
1673 double low = st->info.base_angle - st->rotate_tolerance;
1674 double high = st->info.base_angle + st->rotate_tolerance;
1675 double t = st->info.angle;
1688 if (high > RAD_360DEG)
1699 #if defined(DEBUG_GESTURE_LAYER)
1700 printf("%s angle=<%d> low=<%d> high=<%d>\n", __func__, t, low, high);
1702 if ((t < low) || (t > high))
1703 { /* This marks that roation action has started */
1704 st->rotate_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
1705 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
1715 * This function is used for computing the gap between fingers.
1716 * It returns the length and center point between fingers.
1718 * @param x1 first finger x location.
1719 * @param y1 first finger y location.
1720 * @param x2 second finger x location.
1721 * @param y2 second finger y location.
1722 * @param x Gets center point x cord (output)
1723 * @param y Gets center point y cord (output)
1725 * @return length of the line between (x1,y1), (x2,y2) in pixels.
1727 * @ingroup Elm_Gesture_Layer
1730 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
1731 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
1733 double a, b, xx, yy, gap;
1736 gap = sqrt(xx*xx + yy*yy);
1738 /* START - Compute zoom center point */
1739 /* The triangle defined as follows:
1747 * http://en.wikipedia.org/wiki/Trigonometric_functions
1748 *************************************/
1749 if (((int) xx) && ((int) yy))
1751 double A = atan((yy / xx));
1752 #if defined(DEBUG_GESTURE_LAYER)
1753 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
1755 a = (Evas_Coord) ((gap / 2) * sin(A));
1756 b = (Evas_Coord) ((gap / 2) * cos(A));
1757 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
1758 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
1763 { /* horiz line, take half width */
1764 #if defined(DEBUG_GESTURE_LAYER)
1765 printf("==== HORIZ ====\n");
1767 *x = (Evas_Coord) (xx / 2);
1768 *y = (Evas_Coord) (y1);
1772 { /* vert line, take half width */
1773 #if defined(DEBUG_GESTURE_LAYER)
1774 printf("==== VERT ====\n");
1776 *x = (Evas_Coord) (x1);
1777 *y = (Evas_Coord) (yy / 2);
1780 /* END - Compute zoom center point */
1782 return (Evas_Coord) gap;
1788 * This function is used for computing zoom value.
1790 * @param st Pointer to zoom data based on user input.
1791 * @param x1 first finger x location.
1792 * @param y1 first finger y location.
1793 * @param x2 second finger x location.
1794 * @param y2 second finger y location.
1795 * @param factor zoom-factor, used to determine how fast zoom works.
1797 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
1799 * @ingroup Elm_Gesture_Layer
1801 /* FIXME change float to double */
1803 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
1804 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, float factor)
1807 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
1808 &st->info.x, &st->info.y);
1810 st->info.radius = diam / 2;
1814 st->zoom_base = diam;
1815 return st->info.zoom;
1818 if (st->zoom_tolerance)
1819 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
1820 if (diam < (st->zoom_base - st->zoom_tolerance))
1821 { /* avoid jump with zoom value when break tolerance */
1822 st->zoom_base -= st->zoom_tolerance;
1823 st->zoom_tolerance = 0;
1826 if (diam > (st->zoom_base + st->zoom_tolerance))
1827 { /* avoid jump with zoom value when break tolerance */
1828 st->zoom_base += st->zoom_tolerance;
1829 st->zoom_tolerance = 0;
1835 /* We use factor only on the difference between gap-base */
1836 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
1837 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
1838 (float) st->zoom_base) * factor));
1841 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
1842 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
1853 * This function handles zoom with mouse wheel.
1854 * thats a combination of wheel + CTRL key.
1855 * @param obj The gesture-layer object.
1856 * @param event_info Original input event pointer.
1857 * @param event_type Type of original input event.
1858 * @param g_type what Gesture we are testing.
1860 * @ingroup Elm_Gesture_Layer
1863 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
1864 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1866 Widget_Data *wd = elm_widget_data_get(obj);
1868 if (!wd->gesture[g_type]) return;
1870 Gesture_Info *gesture_zoom = wd->gesture[g_type];
1871 Zoom_Type *st = gesture_zoom->data;
1872 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1874 { /* Allocated once on first time, used for zoom intermediate data */
1875 st = calloc(1, sizeof(Zoom_Type));
1876 gesture_zoom->data = st;
1877 _zoom_test_reset(gesture_zoom);
1882 case EVAS_CALLBACK_KEY_UP:
1884 Evas_Event_Key_Up *p = event_info;
1885 if ((!strcmp(p->keyname, "Control_L")) ||
1886 (!strcmp(p->keyname, "Control_R")))
1887 { /* Test if we ended a zoom gesture when releasing CTRL */
1888 if ((st->zoom_wheel) &&
1889 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
1890 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
1891 { /* User released CTRL after zooming */
1892 ev_flag = _set_state(gesture_zoom,
1893 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
1894 consume_event(wd, event_info, event_type, ev_flag);
1902 case EVAS_CALLBACK_MOUSE_WHEEL:
1905 Elm_Gesture_State s;
1906 if (!evas_key_modifier_is_set(
1907 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
1909 { /* if using wheel witout CTRL after starting zoom */
1910 if ((st->zoom_wheel) &&
1911 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
1912 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
1914 ev_flag = _set_state(gesture_zoom,
1915 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
1916 consume_event(wd, event_info, event_type, ev_flag);
1921 return; /* Ignore mouse-wheel without control */
1924 /* Using mouse wheel with CTRL for zoom */
1925 if (st->zoom_wheel || (st->zoom_tolerance == 0))
1926 { /* when (zoom_wheel == NULL) and (zoom_tolerance == 0)
1927 we continue a zoom gesture */
1929 s = ELM_GESTURE_STATE_MOVE;
1932 { /* On first wheel event, report START */
1934 s = ELM_GESTURE_STATE_START;
1937 st->zoom_tolerance = 0; /* Cancel tolerance */
1938 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
1939 st->info.x = st->zoom_wheel->canvas.x;
1940 st->info.y = st->zoom_wheel->canvas.y;
1942 if (st->zoom_wheel->z > 0) /* zoom in */
1943 st->info.zoom += (wd->factor * wd->zoom_wheel_factor);
1945 if (st->zoom_wheel->z < 0) /* zoom out */
1946 st->info.zoom -= (wd->factor * wd->zoom_wheel_factor);
1948 if (st->info.zoom < 0.0)
1949 st->info.zoom = 0.0;
1951 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
1952 consume_event(wd, event_info, event_type, ev_flag);
1964 * This function is used to test zoom gesture.
1965 * user may combine zoom, rotation together.
1966 * so its possible that both will be detected from input.
1967 * (both are two-finger movement-oriented gestures)
1969 * @param obj The gesture-layer object.
1970 * @param event_info Pointer to recent input event.
1971 * @param event_type Recent input event type.
1972 * @param g_type what Gesture we are testing.
1974 * @ingroup Elm_Gesture_Layer
1977 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info, Evas_Callback_Type event_type,
1978 Elm_Gesture_Types g_type)
1982 Widget_Data *wd = elm_widget_data_get(obj);
1984 if (!wd->gesture[g_type]) return;
1986 Gesture_Info *gesture_zoom = wd->gesture[g_type];
1987 Zoom_Type *st = gesture_zoom->data;
1990 { /* Allocated once on first time, used for zoom data */
1991 st = calloc(1, sizeof(Zoom_Type));
1992 gesture_zoom->data = st;
1993 _zoom_test_reset(gesture_zoom);
1996 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1999 case EVAS_CALLBACK_MOUSE_DOWN:
2000 consume_event(wd, event_info, event_type, ev_flag);
2001 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2005 case EVAS_CALLBACK_MOUSE_MOVE:
2006 consume_event(wd, event_info, event_type, ev_flag);
2007 if (!st->zoom_st.timestamp)
2008 return; /* we got move event before down event.Ignore it */
2010 consume_event(wd, event_info, event_type, ev_flag);
2011 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2013 /* We match this point to previous multi-move or multi-down event */
2014 if (st->zoom_mv1.timestamp)
2016 st->info.zoom = compute_zoom(st,
2017 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2018 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2023 if (st->zoom_st1.timestamp)
2025 st->info.zoom = compute_zoom(st,
2026 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2027 st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2034 case EVAS_CALLBACK_MULTI_MOVE:
2035 if (!st->zoom_st1.timestamp)
2036 return; /* We get move event before down event.Ignore it */
2038 consume_event(wd, event_info, event_type, ev_flag);
2039 if (st->zoom_mv1.timestamp)
2041 if (st->zoom_mv1.device !=
2042 ((Evas_Event_Multi_Move *) event_info)->device)
2043 { /* A third finger on screen, abort zoom */
2044 ev_flag = _set_state(gesture_zoom,
2045 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2046 consume_event(wd, event_info, event_type, ev_flag);
2052 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2054 /* Match this point to previous mouse-move or mouse-down event */
2055 if (st->zoom_mv.timestamp)
2057 st->info.zoom = compute_zoom(st,
2058 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2059 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2064 if (st->zoom_st.timestamp)
2066 st->info.zoom = compute_zoom(st,
2067 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2068 st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2075 case EVAS_CALLBACK_MULTI_DOWN:
2076 consume_event(wd, event_info, event_type, ev_flag);
2077 memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2080 case EVAS_CALLBACK_MOUSE_UP:
2081 case EVAS_CALLBACK_MULTI_UP:
2082 /* Reset timestamp of finger-up.This is used later
2083 by _zoom_test_reset() to retain finger-down data */
2084 consume_event(wd, event_info, event_type, ev_flag);
2085 if(event_type == EVAS_CALLBACK_MOUSE_UP)
2086 st->zoom_st.timestamp = 0;
2088 if((event_type == EVAS_CALLBACK_MULTI_UP) &&
2089 (st->zoom_st1.device ==
2090 ((Evas_Event_Multi_Up *) event_info)->device))
2091 st->zoom_st1.timestamp = 0;
2093 if (((st->zoom_wheel) || (st->zoom_base)) &&
2094 (st->zoom_tolerance == 0))
2096 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2097 &st->info, EINA_FALSE);
2098 consume_event(wd, event_info, event_type, ev_flag);
2103 /* if we got here not a ZOOM */
2104 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2105 { /* Must be != undefined, if gesture started */
2106 ev_flag = _set_state(gesture_zoom,
2107 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2108 consume_event(wd, event_info, event_type, ev_flag);
2111 _zoom_test_reset(gesture_zoom);
2120 if (!st->zoom_tolerance)
2121 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2122 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2124 { /* Zoom broke tolerance, report move */
2125 double d = st->info.zoom - st->next_step;
2129 if(d >= wd->zoom_step)
2130 { /* Report move in steps */
2131 st->next_step = st->info.zoom;
2133 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2134 &st->info, EINA_TRUE);
2135 consume_event(wd, event_info, event_type, ev_flag);
2142 if((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2143 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2144 { /* report zoom start finger location is zoom-center temporarly */
2145 /* Zoom may have started with mouse-wheel, don't report START */
2146 if((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2147 { /* Set zoom-base after BOTH down events were recorded */
2148 /* Compute length of line between fingers on zoom start */
2149 st->info.zoom = 1.0;
2150 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2151 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2152 &st->info.x, &st->info.y);
2154 st->info.radius = st->zoom_base / 2;
2156 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2157 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2158 { /* Report START only when two fingers touching */
2159 ev_flag = _set_state(gesture_zoom,
2160 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2161 consume_event(wd, event_info, event_type, ev_flag);
2170 _get_rotate_properties(Rotate_Type *st,
2171 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2172 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2175 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2176 &st->info.x, &st->info.y) / 2;
2178 *angle = get_angle(x1, y1, x2, y2);
2179 #if 0 /* (NOT YET SUPPORTED) */
2180 if(angle == &st->info.angle)
2181 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2182 st->info.momentum = (((*angle) - st->info.base_angle) /
2183 (fabs(tm2 - tm1))) * 1000;
2186 st->info.momentum = 0;
2196 * This function is used to test rotation gesture.
2197 * user may combine zoom, rotation together.
2198 * so its possible that both will be detected from input.
2199 * (both are two-finger movement-oriented gestures)
2201 * @param obj The gesture-layer object.
2202 * @param event_info Pointer to recent input event.
2203 * @param event_type Recent input event type.
2204 * @param g_type what Gesture we are testing.
2206 * @ingroup Elm_Gesture_Layer
2209 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2210 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2215 Widget_Data *wd = elm_widget_data_get(obj);
2217 if (!wd->gesture[g_type]) return;
2219 Gesture_Info *gesture = wd->gesture[g_type];
2220 Rotate_Type *st = gesture->data;
2225 { /* Allocated once on first time */
2226 st = calloc(1, sizeof(Rotate_Type));
2228 _rotate_test_reset(gesture);
2232 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2236 case EVAS_CALLBACK_MOUSE_DOWN:
2237 consume_event(wd, event_info, event_type, ev_flag);
2238 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2242 case EVAS_CALLBACK_MOUSE_MOVE:
2243 if (!st->rotate_st.timestamp)
2244 break; /* We got move event before down event.Ignore it */
2246 consume_event(wd, event_info, event_type, ev_flag);
2247 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2249 /* Match this point to previous multi-move or multi-down event */
2250 if (st->rotate_mv1.timestamp)
2251 { /* Compute rotation angle and report to user */
2252 _get_rotate_properties(st,
2253 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2254 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2259 if (st->rotate_st1.timestamp)
2260 { /* Compute rotation angle and report to user */
2261 _get_rotate_properties(st,
2262 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2263 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2270 case EVAS_CALLBACK_MULTI_MOVE:
2271 if (!st->rotate_st1.timestamp)
2272 break; /* We got move event before down event.Ignore it */
2274 consume_event(wd, event_info, event_type, ev_flag);
2275 if (st->rotate_mv1.timestamp)
2277 if (st->rotate_mv1.device !=
2278 ((Evas_Event_Multi_Move *) event_info)->device)
2279 { /* A third finger on screen, abort rotate */
2280 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2281 &st->info, EINA_FALSE);
2282 consume_event(wd, event_info, event_type, ev_flag);
2288 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2290 /* Match this point to previous mouse-move or mouse-down event */
2291 if (st->rotate_mv.timestamp)
2292 { /* Compute rotation angle and report to user */
2293 _get_rotate_properties(st,
2294 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2295 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2300 if (st->rotate_st.timestamp)
2301 { /* Compute rotation angle and report to user */
2302 _get_rotate_properties(st,
2303 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2304 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2311 case EVAS_CALLBACK_MULTI_DOWN:
2312 consume_event(wd, event_info, event_type, ev_flag);
2313 memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2314 _get_rotate_properties(st,
2315 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2316 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2320 case EVAS_CALLBACK_MOUSE_UP:
2321 case EVAS_CALLBACK_MULTI_UP:
2322 consume_event(wd, event_info, event_type, ev_flag);
2323 /* Reset timestamp of finger-up.This is used later
2324 by rotate_test_reset() to retain finger-down data */
2325 if(event_type == EVAS_CALLBACK_MOUSE_UP)
2326 st->rotate_st.timestamp = 0;
2328 if((event_type == EVAS_CALLBACK_MULTI_UP) &&
2329 (st->rotate_st1.device ==
2330 ((Evas_Event_Multi_Up *) event_info)->device))
2331 st->rotate_st1.timestamp = 0;
2333 if (st->rotate_tolerance < 0)
2335 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2336 &st->info, EINA_FALSE);
2337 consume_event(wd, event_info, event_type, ev_flag);
2342 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2343 { /* Must be != undefined, if gesture started */
2344 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2345 &st->info, EINA_FALSE);
2346 consume_event(wd, event_info, event_type, ev_flag);
2349 _rotate_test_reset(gesture);
2356 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2357 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2358 { /* Report MOVE or ABORT for *MOVE event */
2359 if (rotation_broke_tolerance(st))
2360 { /* Rotation broke tolerance, report move */
2361 double d = st->info.angle - st->next_step;
2365 if(d >= wd->rotate_step)
2366 { /* Report move in steps */
2367 st->next_step = st->info.angle;
2369 ev_flag = _set_state(gesture,
2370 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2371 consume_event(wd, event_info, event_type, ev_flag);
2378 if((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2379 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2381 if((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2382 { /* two-fingers on touch screen - report rotate start */
2383 /* Set base angle, then report start. */
2384 _get_rotate_properties(st,
2385 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2386 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2387 &st->info.base_angle);
2389 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2390 &st->info, EINA_FALSE);
2391 consume_event(wd, event_info, event_type, ev_flag);
2401 * This function manges a list of devices that are currently touched
2402 * when a *DOWN event for a device comes, we add it to the list
2403 * When a *UP event for a device comes, we remove it from list
2405 * @param list Pointer to device list.
2406 * @param device What device to add or remove from list
2407 * @param add When TRUE means - add to list, otherwise remove
2409 * @return The new pointer to list head
2410 * @ingroup Elm_Gesture_Layer
2413 _manage_device_list(Eina_List *list, int device, Eina_Bool add)
2419 return eina_list_append(list, (void *) device);
2421 EINA_LIST_FOREACH(list, l, data)
2422 { /* Remove device from list if found */
2423 if(device == (int) data)
2424 return eina_list_remove_list(list, l);
2433 * This function is used to save input events in an abstract struct
2434 * to be used later by getsure-testing functions.
2436 * @param data The gesture-layer object.
2437 * @param event_info Pointer to recent input event.
2438 * @param event_type Recent input event type.
2439 * @param pe The abstract data-struct (output).
2441 * @ingroup Elm_Gesture_Layer
2444 _make_pointer_event(void *data, void *event_info,
2445 Evas_Callback_Type event_type, Pointer_Event *pe)
2447 Widget_Data *wd = elm_widget_data_get(data);
2448 if (!wd) return EINA_FALSE;
2452 case EVAS_CALLBACK_MOUSE_DOWN:
2453 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2454 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2455 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2456 pe->device = ELM_MOUSE_DEVICE;
2459 case EVAS_CALLBACK_MOUSE_UP:
2460 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2461 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2462 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2463 pe->device = ELM_MOUSE_DEVICE;
2466 case EVAS_CALLBACK_MOUSE_MOVE:
2467 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2468 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2469 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2470 pe->device = ELM_MOUSE_DEVICE;
2473 case EVAS_CALLBACK_MULTI_DOWN:
2474 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2475 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2476 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2477 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2480 case EVAS_CALLBACK_MULTI_UP:
2481 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2482 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2483 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2484 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2487 case EVAS_CALLBACK_MULTI_MOVE:
2488 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2489 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2490 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2491 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2498 pe->event_type = event_type;
2505 * This function the core-function where input handling is done.
2506 * Here we get user input and stream it to gesture testing.
2507 * We notify user about any gestures with new state:
2509 * START - gesture started.
2510 * MOVE - gesture is ongoing.
2511 * END - gesture was completed.
2512 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
2514 * We also check if a gesture was detected, then reset event history
2515 * If no gestures were found we reset gesture test flag
2516 * after streaming event-history to widget.
2517 * (stream to the widget all events not consumed as a gesture)
2519 * @param data The gesture-layer object.
2520 * @param event_info Pointer to recent input event.
2521 * @param event_type Recent input event type.
2523 * @ingroup Elm_Gesture_Layer
2526 _event_process(void *data, Evas_Object *obj __UNUSED__,
2527 void *event_info, Evas_Callback_Type event_type)
2530 Pointer_Event *pe = NULL;
2531 Widget_Data *wd = elm_widget_data_get(data);
2534 _event_history_add(data, event_info, event_type);
2535 /* Start testing candidate gesture from here */
2536 if (_make_pointer_event(data, event_info, event_type, &_pe))
2539 if (IS_TESTED(ELM_GESTURE_N_TAPS))
2540 _dbl_click_test(data, pe, event_info, event_type,
2541 ELM_GESTURE_N_TAPS, 1);
2543 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
2544 _dbl_click_test(data, pe, event_info, event_type,
2545 ELM_GESTURE_N_DOUBLE_TAPS, 2);
2547 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
2548 _dbl_click_test(data, pe, event_info, event_type,
2549 ELM_GESTURE_N_TRIPLE_TAPS, 3);
2551 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
2552 _momentum_test(data, pe, event_info, event_type,
2553 ELM_GESTURE_MOMENTUM);
2555 if (IS_TESTED(ELM_GESTURE_N_LINES))
2556 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
2558 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
2559 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
2561 if (IS_TESTED(ELM_GESTURE_ZOOM))
2562 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
2564 if (IS_TESTED(ELM_GESTURE_ZOOM))
2565 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
2567 if (IS_TESTED(ELM_GESTURE_ROTATE))
2568 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
2570 /* Report current states and clear history if needed */
2571 _clear_if_finished(data);
2573 /* we maintain list of touched devices*/
2574 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2575 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2576 wd->touched = _manage_device_list(wd->touched, pe->device, EINA_TRUE);
2578 if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2579 (event_type == EVAS_CALLBACK_MULTI_UP))
2580 wd->touched = _manage_device_list(wd->touched, pe->device, EINA_FALSE);
2584 * For all _mouse_* / multi_* functions we copy event information
2585 * to newly allocated memory space with COPY_EVENT_INFO macro.
2586 * then send this event to _event_process function where
2587 * it is saved in events-history list and processes.
2588 * The allocated memeory is cleared in event_history_clear()
2590 * @param data The gesture-layer object.
2591 * @param event_info Pointer to recent input event.
2593 * @ingroup Elm_Gesture_Layer
2596 _mouse_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2599 Widget_Data *wd = elm_widget_data_get(data);
2602 Evas_Event_Mouse_In *p, *ev = event_info;
2603 COPY_EVENT_INFO(p, ev);
2604 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_IN);
2606 #if defined(DEBUG_GESTURE_LAYER)
2607 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2612 _mouse_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2615 Widget_Data *wd = elm_widget_data_get(data);
2618 Evas_Event_Mouse_Out *p, *ev = event_info;
2619 COPY_EVENT_INFO(p, ev);
2620 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_OUT);
2621 #if defined(DEBUG_GESTURE_LAYER)
2622 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2627 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2630 Widget_Data *wd = elm_widget_data_get(data);
2633 Evas_Event_Mouse_Down *p, *ev = event_info;
2634 if (ev->button != 1) /* We only process left-click at the moment */
2637 COPY_EVENT_INFO(p, ev);
2638 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_DOWN);
2639 #if defined(DEBUG_GESTURE_LAYER)
2640 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2645 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2648 Widget_Data *wd = elm_widget_data_get(data);
2651 Evas_Event_Mouse_Move *p, *ev = event_info;
2653 COPY_EVENT_INFO(p, ev);
2654 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_MOVE);
2655 #if defined(DEBUG_GESTURE_LAYER)
2656 printf("%s %d %d\n", __func__, p->cur.canvas.x, p->cur.canvas.y);
2661 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2664 Widget_Data *wd = elm_widget_data_get(data);
2667 Evas_Event_Key_Up *p, *ev = event_info;
2669 COPY_EVENT_INFO(p, ev);
2670 _event_process(data, obj, (void *) p, EVAS_CALLBACK_KEY_UP);
2672 #if defined(DEBUG_GESTURE_LAYER)
2673 printf("%s %s\n", __func__, p->keyname);
2678 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2681 Widget_Data *wd = elm_widget_data_get(data);
2684 Evas_Event_Mouse_Up *p, *ev = event_info;
2685 if (ev->button != 1) /* We only process left-click at the moment */
2688 COPY_EVENT_INFO(p, ev);
2689 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_UP);
2690 #if defined(DEBUG_GESTURE_LAYER)
2691 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2696 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2699 Widget_Data *wd = elm_widget_data_get(data);
2702 Evas_Event_Mouse_Wheel *p, *ev = event_info;
2703 COPY_EVENT_INFO(p, ev);
2704 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_WHEEL);
2705 #if defined(DEBUG_GESTURE_LAYER)
2706 printf("%s %d %d %d\n", __func__, p->canvas.x, p->canvas.y, p->z);
2711 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2714 Widget_Data *wd = elm_widget_data_get(data);
2717 Evas_Event_Multi_Down *p, *ev = event_info;
2718 COPY_EVENT_INFO(p, ev);
2719 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MULTI_DOWN);
2720 #if defined(DEBUG_GESTURE_LAYER)
2721 printf("%s %d\n", __func__, __LINE__);
2722 printf("radius=<%3.2f> radius_x=<%3.2f> radius_y=<%3.2f> device: <%d>\n",
2723 p->radius, p->radius_x, p->radius_y, p->device);
2724 printf("pressure<%3.2f> angle<%3.2f>\n", p->pressure, p->angle);
2725 printf("output.x=<%d> output.y=<%d>\n", p->output.x, p->output.y);
2726 printf("canvas.x=<%d> canvas.y=<%d> canvas.xsub=<%3.2f> canvas.ysub=<%3.2f>\n\n\n", p->canvas.x, p->canvas.y, p->canvas.xsub, p->canvas.ysub);
2731 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2734 Widget_Data *wd = elm_widget_data_get(data);
2737 Evas_Event_Multi_Move *p, *ev = event_info;
2738 COPY_EVENT_INFO(p, ev);
2739 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MULTI_MOVE);
2740 #if defined(DEBUG_GESTURE_LAYER)
2741 printf("%s %d\n", __func__, __LINE__);
2742 printf("radius=<%3.2f> radius_x=<%3.2f> radius_y=<%3.2f> device: <%d>\n", p->radius, p->radius_x, p->radius_y, p->device);
2743 printf("pressure<%3.2f> angle<%3.2f>\n", p->pressure, p->angle);
2744 printf("output.x=<%d> output.y=<%d>\n", p->cur.output.x, p->cur.output.y);
2745 printf("canvas.x=<%d> canvas.y=<%d> canvas.xsub=<%3.2f> canvas.ysub=<%3.2f>\n\n\n", p->cur.canvas.x, p->cur.canvas.y, p->cur.canvas.xsub, p->cur.canvas.ysub);
2750 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2753 Widget_Data *wd = elm_widget_data_get(data);
2756 Evas_Event_Multi_Up *p, *ev = event_info;
2757 COPY_EVENT_INFO(p, ev);
2758 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MULTI_UP);
2759 #if defined(DEBUG_GESTURE_LAYER)
2760 printf("%s %d\n", __func__, __LINE__);
2761 printf("radius=<%3.2f> radius_x=<%3.2f> radius_y=<%3.2f> device: <%d>\n", p->radius, p->radius_x, p->radius_y, p->device);
2762 printf("pressure<%3.2f> angle<%3.2f>\n", p->pressure, p->angle);
2763 printf("output.x=<%d> output.y=<%d>\n", p->output.x, p->output.y);
2764 printf("canvas.x=<%d> canvas.y=<%d> canvas.xsub=<%3.2f> canvas.ysub=<%3.2f>\n\n\n", p->canvas.x, p->canvas.y, p->canvas.xsub, p->canvas.ysub);
2769 elm_gesture_layer_hold_events_get(Evas_Object *obj)
2771 Widget_Data *wd = elm_widget_data_get(obj);
2772 if (!wd) return EINA_FALSE;
2774 return !wd->repeat_events;
2778 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
2780 Widget_Data *wd = elm_widget_data_get(obj);
2783 wd->repeat_events = !r;
2787 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
2789 Widget_Data *wd = elm_widget_data_get(obj);
2799 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
2801 Widget_Data *wd = elm_widget_data_get(obj);
2807 wd->rotate_step = s;
2811 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
2813 Widget_Data *wd = elm_widget_data_get(obj);
2814 if (!wd) return EINA_FALSE;
2819 /* if was attached before, unregister callbacks first */
2821 _unregister_callbacks(obj);
2825 _register_callbacks(obj);
2830 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
2831 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
2833 Widget_Data *wd = elm_widget_data_get(obj);
2836 if (!wd->gesture[idx])
2837 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
2839 Gesture_Info *p = wd->gesture[idx];
2842 p->fn[cb_type].cb = cb;
2843 p->fn[cb_type].user_data = data;
2844 p->state = ELM_GESTURE_STATE_UNDEFINED;
2849 _disable_hook(Evas_Object *obj)
2851 if (elm_widget_disabled_get(obj))
2852 _unregister_callbacks(obj);
2854 _register_callbacks(obj);
2858 elm_gesture_layer_add(Evas_Object *parent)
2864 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2866 wd = ELM_NEW(Widget_Data);
2867 e = evas_object_evas_get(parent);
2868 if (!e) return NULL;
2869 obj = elm_widget_add(e);
2870 ELM_SET_WIDTYPE(widtype, "gesture_layer");
2871 elm_widget_type_set(obj, "gesture_layer");
2872 elm_widget_sub_object_add(parent, obj);
2873 elm_widget_data_set(obj, wd);
2874 elm_widget_del_hook_set(obj, _del_hook);
2875 elm_widget_disable_hook_set(obj, _disable_hook);
2878 wd->line_min_length = wd->zoom_tolerance = elm_finger_size_get();
2879 wd->line_tolerance = elm_finger_size_get() * 3;
2880 wd->factor = ELM_GESTURE_ZOOM_FACTOR;
2881 wd->zoom_wheel_factor = ELM_GESTURE_ZOOM_WHEEL_FACTOR ; /* mouse wheel zoom steps */
2882 wd->rotate_tolerance = ELM_GESTURE_ROTATION_TOLERANCE;
2883 wd->repeat_events = EINA_TRUE;
2885 #if defined(DEBUG_GESTURE_LAYER)
2886 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
2888 memset(wd->gesture, 0, sizeof(wd->gesture));