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 /* SPANK SPANK, EINA_FALSE?! FIXME */
877 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
883 /* This will also update middle-point to report to user later */
884 st->info.x = st->sum_x / st->n_taps;
885 st->info.y = st->sum_y / st->n_taps;
886 st->info.timestamp = pe->timestamp;
890 pe_list = eina_list_append(pe_list, p);
891 st->l = eina_list_append(st->l, pe_list);
894 pe_list = eina_list_append(pe_list, p);
902 * This function checks all click/tap and double/triple taps
904 * @param obj The gesture-layer object.
905 * @param pe The recent input event as stored in pe struct.
906 * @param event_info Original input event pointer.
907 * @param event_type Type of original input event.
908 * @param g_type what Gesture we are testing.
909 * @param taps How many click/taps we test for.
911 * @ingroup Elm_Gesture_Layer
914 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
915 void *event_info, Evas_Callback_Type event_type,
916 Elm_Gesture_Types g_type, int taps)
917 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
918 Widget_Data *wd = elm_widget_data_get(obj);
921 if (!pe) /* this happens when unhandled event arrived */
922 return; /* see _make_pointer_event function */
924 Gesture_Info *gesture = wd->gesture[g_type];
925 if (!gesture ) return;
927 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
928 eina_list_count(wd->touched))
929 return; /* user left a finger on device, do NOT start */
931 Taps_Type *st = gesture->data;
933 { /* Allocated once on first time */
934 st = calloc(1, sizeof(Taps_Type));
936 _dbl_click_test_reset(gesture);
939 Eina_List *pe_list = NULL;
940 Pointer_Event *pe_down = NULL;
941 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
942 switch (pe->event_type)
944 case EVAS_CALLBACK_MULTI_DOWN:
945 case EVAS_CALLBACK_MOUSE_DOWN:
946 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
947 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
948 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
949 { /* This is the first mouse down we got */
950 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
951 &st->info, EINA_FALSE);
952 consume_event(wd, event_info, event_type, ev_flag);
954 /* To test dbl_click/dbl_tap */
955 /* When this timer expires, gesture ABORTed if not completed */
956 if (!wd->dbl_timeout && (taps > 1))
957 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
964 case EVAS_CALLBACK_MULTI_UP:
965 case EVAS_CALLBACK_MOUSE_UP:
966 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
968 return; /* Got only first mouse_down and mouse_up */
970 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
972 if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
973 return; /* Got only first mouse_down and mouse_up */
975 /* Get first event in first list, this has to be Mouse Down event */
976 pe_down = eina_list_data_get(pe_list);
978 if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
984 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
985 &st->info, EINA_FALSE);
986 consume_event(wd, event_info, event_type, ev_flag);
990 if (st->count_ups == eina_list_count(st->l))
992 /* Abort if we found a single click */
993 if ((taps == 1) && (st->count_ups == 1))
995 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
996 &st->info, EINA_FALSE);
997 consume_event(wd, event_info, event_type, ev_flag);
1000 st->info.n = st->count_ups;
1001 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1002 &st->info, EINA_FALSE);
1003 consume_event(wd, event_info, event_type, ev_flag);
1010 case EVAS_CALLBACK_MULTI_MOVE:
1011 case EVAS_CALLBACK_MOUSE_MOVE:
1012 /* Get first event in first list, this has to be a Mouse Down event */
1013 /* and verify that user didn't move out of this area before next tap */
1014 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1017 pe_down = eina_list_data_get(pe_list);
1018 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1020 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1021 &st->info, EINA_FALSE);
1022 consume_event(wd, event_info, event_type, ev_flag);
1035 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1036 * This momentum value will be sent to widget when gesture is completed.
1038 * @param momentum pointer to buffer where we record momentum value.
1039 * @param x1 x coord where user started gesture.
1040 * @param y1 y coord where user started gesture.
1041 * @param x2 x coord where user completed gesture.
1042 * @param y2 y coord where user completed gesture.
1043 * @param t1x timestamp for X, when user started gesture.
1044 * @param t1y timestamp for Y, when user started gesture.
1045 * @param t2 timestamp when user completed gesture.
1047 * @ingroup Elm_Gesture_Layer
1050 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1,Evas_Coord y1,
1051 Evas_Coord x2,Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1054 Evas_Coord velx = 0, vely = 0, vel;
1055 Evas_Coord dx = x2 - x1;
1056 Evas_Coord dy = y2 - y1;
1060 velx = (dx * 1000) / dtx;
1063 vely = (dy * 1000) / dty;
1065 vel = sqrt((velx * velx) + (vely * vely));
1067 if ((_elm_config->thumbscroll_friction > 0.0) &&
1068 (vel > _elm_config->thumbscroll_momentum_threshold))
1069 { /* report momentum */
1070 momentum->mx = velx;
1071 momentum->my = vely;
1083 * This function is used for computing rotation angle (DEG).
1085 * @param x1 first finger x location.
1086 * @param y1 first finger y location.
1087 * @param x2 second finger x location.
1088 * @param y2 second finger y location.
1090 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1092 * @ingroup Elm_Gesture_Layer
1095 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1101 if (((int) xx) && ((int) yy))
1108 return RAD_360DEG - a;
1119 return RAD_180DEG + a;
1123 return RAD_180DEG - a;
1129 { /* Horizontal line */
1154 * This function is used for computing the magnitude and direction
1155 * of vector between two points.
1157 * @param x1 first finger x location.
1158 * @param y1 first finger y location.
1159 * @param x2 second finger x location.
1160 * @param y2 second finger y location.
1161 * @param l length computed (output)
1162 * @param a angle computed (output)
1164 * @ingroup Elm_Gesture_Layer
1167 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1168 Evas_Coord *l, double *a)
1173 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1174 *a = get_angle(x1, y1, x2, y2);
1178 _get_direction(Evas_Coord x1, Evas_Coord x2)
1191 * This function tests momentum gesture.
1192 * @param obj The gesture-layer object.
1193 * @param pe The recent input event as stored in pe struct.
1194 * @param event_info recent input event.
1195 * @param event_type recent event type.
1196 * @param g_type what Gesture we are testing.
1198 * @ingroup Elm_Gesture_Layer
1201 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1202 void *event_info, Evas_Callback_Type event_type,
1203 Elm_Gesture_Types g_type)
1205 Widget_Data *wd = elm_widget_data_get(obj);
1207 Gesture_Info *gesture = wd->gesture[g_type];
1208 if (!gesture ) return;
1210 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1211 eina_list_count(wd->touched))
1212 return; /* user left a finger on device, do NOT start */
1214 Momentum_Type *st = gesture->data;
1216 { /* Allocated once on first time */
1217 st = calloc(1, sizeof(Momentum_Type));
1219 _momentum_test_reset(gesture);
1225 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1226 switch (pe->event_type)
1228 case EVAS_CALLBACK_MOUSE_DOWN:
1229 st->line_st.x = st->line_end.x = pe->x;
1230 st->line_st.y = st->line_end.y = pe->y;
1231 st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1232 st->xdir = st->ydir = 0;
1233 st->info.x2 = st->info.x1 = pe->x;
1234 st->info.y2 = st->info.y1 = pe->y;
1235 st->info.tx = st->info.ty = pe->timestamp;
1236 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1237 &st->info, EINA_FALSE);
1238 consume_event(wd, event_info, event_type, ev_flag);
1241 case EVAS_CALLBACK_MOUSE_UP:
1242 /* IGNORE if line info was cleared, like long press, move */
1246 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1248 /* Too long of a wait, reset all values */
1249 st->line_st.x = pe->x;
1250 st->line_st.y = pe->y;
1251 st->t_st_y = st->t_st_x = pe->timestamp;
1252 st->xdir = st->ydir = 0;
1255 st->info.x2 = pe->x;
1256 st->info.y2 = pe->y;
1257 st->line_end.x = pe->x;
1258 st->line_end.y = pe->y;
1259 st->t_end = pe->timestamp;
1261 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1262 st->t_st_x, st->t_st_y, pe->timestamp);
1264 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1266 consume_event(wd, event_info, event_type, ev_flag);
1270 case EVAS_CALLBACK_MOUSE_MOVE:
1271 /* IGNORE if line info was cleared, like long press, move */
1275 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1277 /* Too long of a wait, reset all values */
1278 st->line_st.x = pe->x;
1279 st->line_st.y = pe->y;
1280 st->t_st_y = st->t_st_x = pe->timestamp;
1281 st->info.tx = st->t_st_x;
1282 st->info.ty = st->t_st_y;
1283 st->xdir = st->ydir = 0;
1288 xdir = _get_direction(st->line_end.x, pe->x);
1289 ydir = _get_direction(st->line_end.y, pe->y);
1290 if (!xdir || (xdir == (-st->xdir)))
1292 st->line_st.x = st->line_end.x;
1293 st->info.tx = st->t_st_x = st->t_end;
1297 if (!ydir || (ydir == (-st->ydir)))
1299 st->line_st.y = st->line_end.y;
1300 st->info.ty = st->t_st_y = st->t_end;
1305 st->info.x2 = st->line_end.x = pe->x;
1306 st->info.y2 = st->line_end.y = pe->y;
1307 st->t_end = pe->timestamp;
1308 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1309 st->t_st_x, st->t_st_y, pe->timestamp);
1310 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE, &st->info,
1312 consume_event(wd, event_info, event_type, ev_flag);
1315 case EVAS_CALLBACK_MULTI_UP:
1316 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1318 consume_event(wd, event_info, event_type, ev_flag);
1327 compare_line_device(const void *data1, const void *data2)
1328 { /* Compare device component of line struct */
1329 const Line_Data *ln1 = data1;
1330 const int *device = data2;
1332 if (ln1->t_st) /* Compare only with lines that started */
1333 return (ln1->device - (*device));
1341 * This function construct line struct from input.
1342 * @param info pointer to store line momentum.
1343 * @param st line info to store input data.
1344 * @param pe The recent input event as stored in pe struct.
1346 * @ingroup Elm_Gesture_Layer
1349 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1351 { /* Record events and set momentum for line pointed by st */
1355 switch (pe->event_type)
1357 case EVAS_CALLBACK_MOUSE_DOWN:
1358 case EVAS_CALLBACK_MULTI_DOWN:
1359 st->line_st.x = pe->x;
1360 st->line_st.y = pe->y;
1361 st->t_st = pe->timestamp;
1362 st->device = pe->device;
1363 info->momentum.x1 = pe->x;
1364 info->momentum.y1 = pe->y;
1365 info->momentum.tx = pe->timestamp;
1366 info->momentum.ty = pe->timestamp;
1371 case EVAS_CALLBACK_MOUSE_UP:
1372 case EVAS_CALLBACK_MULTI_UP:
1373 /* IGNORE if line info was cleared, like long press, move */
1377 st->line_end.x = pe->x;
1378 st->line_end.y = pe->y;
1379 st->t_end = pe->timestamp;
1382 case EVAS_CALLBACK_MOUSE_MOVE:
1383 case EVAS_CALLBACK_MULTI_MOVE:
1384 /* IGNORE if line info was cleared, like long press, move */
1395 _line_data_reset(st);
1399 info->momentum.x2 = pe->x;
1400 info->momentum.y2 = pe->y;
1401 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1402 st->t_st, st->t_st, pe->timestamp);
1410 * This function test for (n) line gesture.
1411 * @param obj The gesture-layer object.
1412 * @param pe The recent input event as stored in pe struct.
1413 * @param event_info Original input event pointer.
1414 * @param event_type Type of original input event.
1415 * @param g_type what Gesture we are testing.
1417 * @ingroup Elm_Gesture_Layer
1420 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1421 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1425 Widget_Data *wd = elm_widget_data_get(obj);
1427 Gesture_Info *gesture = wd->gesture[g_type];
1428 if (!gesture ) return;
1430 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1431 eina_list_count(wd->touched))
1432 return; /* user left a finger on device, do NOT start */
1434 Line_Type *st = gesture->data;
1437 st = calloc(1, sizeof(Line_Type));
1441 Line_Data *line = NULL;
1442 Eina_List *list = st->list;
1443 unsigned int i, cnt = eina_list_count(list);
1446 { /* list is not empty, locate this device on list */
1447 line = (Line_Data *) eina_list_search_unsorted(st->list,
1448 compare_line_device, &pe->device);
1451 { /* Try to locate an empty-node */
1452 for (i = 0; i < cnt; i++)
1454 line = eina_list_nth(list, i);
1456 break; /* Found a free node */
1464 { /* List is empty or device not found, new line-struct on START only */
1465 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1466 (event_type == EVAS_CALLBACK_MULTI_DOWN))
1467 { /* Allocate new item on START */
1468 line = calloc(1, sizeof(Line_Data));
1469 _line_data_reset(line);
1470 list = eina_list_append(list, line);
1475 if (!line) /* This may happen on MOVE that comes before DOWN */
1476 return; /* No line-struct to work with, can't continue testing */
1479 if (_single_line_process(&st->info, line, pe)) /* update st with input */
1480 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1482 /* Get direction and magnitude of the line */
1484 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1485 &line->line_length, &angle);
1487 /* These are used later to compare lines length */
1488 Evas_Coord shortest_line_len = line->line_length;
1489 Evas_Coord longest_line_len = line->line_length;
1490 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1492 /* Now update line-state */
1494 { /* Analyze line only if line started */
1495 if (line->line_angle >= 0.0)
1496 { /* if line direction was set, we test if broke tolerance */
1497 double a = fabs(angle - line->line_angle);
1499 double d = (tan(a)) * line->line_length; /* Distance from line */
1500 #if defined(DEBUG_GESTURE_LAYER)
1501 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
1503 if((d > wd->line_tolerance) || (a > ELM_GESTURE_LINE_ANGLE_TOLERANCE))
1504 // if (a > ELM_GESTURE_LINE_ANGLE_TOLERANCE)
1505 { /* Broke tolerance: abort line and start a new one */
1506 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1507 &st->info, EINA_FALSE);
1508 consume_event(wd, event_info, event_type, ev_flag);
1513 { /* Record the line angle as it broke minimum length for line */
1514 if (line->line_length >= wd->line_min_length)
1515 st->info.angle = line->line_angle = angle;
1520 if (line->line_angle < 0.0)
1521 { /* it's not a line, too short more close to a tap */
1522 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1523 &st->info, EINA_FALSE);
1524 consume_event(wd, event_info, event_type, ev_flag);
1530 /* Count how many lines already started / ended */
1533 unsigned int tm_start = pe->timestamp;
1534 unsigned int tm_end = pe->timestamp;
1537 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1538 Eina_Bool lines_parallel = EINA_TRUE;
1539 EINA_LIST_FOREACH(list, l, t_line)
1542 base_angle = t_line->line_angle;
1545 if (t_line->line_angle >= 0)
1546 { /* Compare angle only with lines with direction defined */
1547 if (fabs(base_angle - t_line->line_angle) >
1548 ELM_GESTURE_LINE_ANGLE_TOLERANCE)
1549 lines_parallel = EINA_FALSE;
1553 if (t_line->line_length)
1554 { /* update only if this line is used */
1555 if (shortest_line_len > t_line->line_length)
1556 shortest_line_len = t_line->line_length;
1558 if (longest_line_len < t_line->line_length)
1559 longest_line_len = t_line->line_length;
1565 if (t_line->t_st < tm_start)
1566 tm_start = t_line->t_st;
1572 if (t_line->t_end < tm_end)
1573 tm_end = t_line->t_end;
1577 st->info.n = started;
1581 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1582 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
1583 { /* user lift one finger then starts again without line-end - ABORT */
1584 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1586 consume_event(wd, event_info, event_type, ev_flag);
1590 if (!lines_parallel)
1591 { /* Lines are NOT at same direction, abort this gesture */
1592 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1594 consume_event(wd, event_info, event_type, ev_flag);
1599 /* We report ABORT if lines length are NOT matching when fingers are up */
1600 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
1602 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1604 consume_event(wd, event_info, event_type, ev_flag);
1608 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > FLICK_MAX_MS))
1609 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
1610 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1612 consume_event(wd, event_info, event_type, ev_flag);
1618 case EVAS_CALLBACK_MOUSE_UP:
1619 case EVAS_CALLBACK_MULTI_UP:
1620 if ((started) && (started == ended))
1622 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
1623 &st->info, EINA_FALSE);
1624 consume_event(wd, event_info, event_type, ev_flag);
1629 case EVAS_CALLBACK_MOUSE_DOWN:
1630 case EVAS_CALLBACK_MULTI_DOWN:
1633 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1634 &st->info, EINA_TRUE);
1635 consume_event(wd, event_info, event_type, ev_flag);
1640 case EVAS_CALLBACK_MOUSE_MOVE:
1641 case EVAS_CALLBACK_MULTI_MOVE:
1644 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1645 &st->info, EINA_TRUE);
1646 consume_event(wd, event_info, event_type, ev_flag);
1652 return; /* Unhandeld event type */
1659 * This function is used to check if rotation gesture started.
1660 * @param st Contains current rotation values from user input.
1661 * @return TRUE/FALSE if we need to set rotation START.
1663 * @ingroup Elm_Gesture_Layer
1666 rotation_broke_tolerance(Rotate_Type *st)
1668 if (st->info.base_angle < 0)
1669 return EINA_FALSE; /* Angle has to be computed first */
1671 if (st->rotate_tolerance < 0)
1674 double low = st->info.base_angle - st->rotate_tolerance;
1675 double high = st->info.base_angle + st->rotate_tolerance;
1676 double t = st->info.angle;
1689 if (high > RAD_360DEG)
1700 #if defined(DEBUG_GESTURE_LAYER)
1701 printf("%s angle=<%d> low=<%d> high=<%d>\n", __func__, t, low, high);
1703 if ((t < low) || (t > high))
1704 { /* This marks that roation action has started */
1705 st->rotate_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
1706 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
1716 * This function is used for computing the gap between fingers.
1717 * It returns the length and center point between fingers.
1719 * @param x1 first finger x location.
1720 * @param y1 first finger y location.
1721 * @param x2 second finger x location.
1722 * @param y2 second finger y location.
1723 * @param x Gets center point x cord (output)
1724 * @param y Gets center point y cord (output)
1726 * @return length of the line between (x1,y1), (x2,y2) in pixels.
1728 * @ingroup Elm_Gesture_Layer
1731 get_finger_gap_length(Evas_Coord x1,Evas_Coord y1,Evas_Coord x2,
1732 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
1734 double a, b, xx, yy, gap;
1737 gap = sqrt(xx*xx + yy*yy);
1739 /* START - Compute zoom center point */
1740 /* The triangle defined as follows:
1748 * http://en.wikipedia.org/wiki/Trigonometric_functions
1749 *************************************/
1750 if (((int) xx) && ((int) yy))
1752 double A = atan((yy / xx));
1753 #if defined(DEBUG_GESTURE_LAYER)
1754 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
1756 a = (Evas_Coord) ((gap / 2) * sin(A));
1757 b = (Evas_Coord) ((gap / 2) * cos(A));
1758 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
1759 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
1764 { /* horiz line, take half width */
1765 #if defined(DEBUG_GESTURE_LAYER)
1766 printf("==== HORIZ ====\n");
1768 *x = (Evas_Coord) (xx / 2);
1769 *y = (Evas_Coord) (y1);
1773 { /* vert line, take half width */
1774 #if defined(DEBUG_GESTURE_LAYER)
1775 printf("==== VERT ====\n");
1777 *x = (Evas_Coord) (x1);
1778 *y = (Evas_Coord) (yy / 2);
1781 /* END - Compute zoom center point */
1783 return (Evas_Coord) gap;
1789 * This function is used for computing zoom value.
1791 * @param st Pointer to zoom data based on user input.
1792 * @param x1 first finger x location.
1793 * @param y1 first finger y location.
1794 * @param x2 second finger x location.
1795 * @param y2 second finger y location.
1796 * @param factor zoom-factor, used to determine how fast zoom works.
1798 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
1800 * @ingroup Elm_Gesture_Layer
1802 /* FIXME change float to double */
1804 compute_zoom(Zoom_Type *st, Evas_Coord x1 ,Evas_Coord y1, unsigned int tm1,
1805 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, float factor)
1808 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
1809 &st->info.x, &st->info.y);
1811 st->info.radius = diam / 2;
1815 st->zoom_base = diam;
1816 return st->info.zoom;
1819 if (st->zoom_tolerance)
1820 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
1821 if (diam < (st->zoom_base - st->zoom_tolerance))
1822 { /* avoid jump with zoom value when break tolerance */
1823 st->zoom_base -= st->zoom_tolerance;
1824 st->zoom_tolerance = 0;
1827 if (diam > (st->zoom_base + st->zoom_tolerance))
1828 { /* avoid jump with zoom value when break tolerance */
1829 st->zoom_base += st->zoom_tolerance;
1830 st->zoom_tolerance = 0;
1836 /* We use factor only on the difference between gap-base */
1837 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
1838 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
1839 (float) st->zoom_base) * factor));
1842 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
1843 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
1854 * This function handles zoom with mouse wheel.
1855 * thats a combination of wheel + CTRL key.
1856 * @param obj The gesture-layer object.
1857 * @param event_info Original input event pointer.
1858 * @param event_type Type of original input event.
1859 * @param g_type what Gesture we are testing.
1861 * @ingroup Elm_Gesture_Layer
1864 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
1865 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1867 Widget_Data *wd = elm_widget_data_get(obj);
1869 if (!wd->gesture[g_type]) return;
1871 Gesture_Info *gesture_zoom = wd->gesture[g_type];
1872 Zoom_Type *st = gesture_zoom->data;
1873 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1875 { /* Allocated once on first time, used for zoom intermediate data */
1876 st = calloc(1, sizeof(Zoom_Type));
1877 gesture_zoom->data = st;
1878 _zoom_test_reset(gesture_zoom);
1883 case EVAS_CALLBACK_KEY_UP:
1885 Evas_Event_Key_Up *p = event_info;
1886 if ((!strcmp(p->keyname, "Control_L")) ||
1887 (!strcmp(p->keyname, "Control_R")))
1888 { /* Test if we ended a zoom gesture when releasing CTRL */
1889 if ((st->zoom_wheel) &&
1890 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
1891 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
1892 { /* User released CTRL after zooming */
1893 ev_flag = _set_state(gesture_zoom,
1894 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
1895 consume_event(wd, event_info, event_type, ev_flag);
1903 case EVAS_CALLBACK_MOUSE_WHEEL:
1906 Elm_Gesture_State s;
1907 if (!evas_key_modifier_is_set(
1908 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
1910 { /* if using wheel witout CTRL after starting zoom */
1911 if ((st->zoom_wheel) &&
1912 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
1913 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
1915 ev_flag = _set_state(gesture_zoom,
1916 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
1917 consume_event(wd, event_info, event_type, ev_flag);
1922 return; /* Ignore mouse-wheel without control */
1925 /* Using mouse wheel with CTRL for zoom */
1926 if (st->zoom_wheel || (st->zoom_tolerance == 0))
1927 { /* when (zoom_wheel == NULL) and (zoom_tolerance == 0)
1928 we continue a zoom gesture */
1930 s = ELM_GESTURE_STATE_MOVE;
1933 { /* On first wheel event, report START */
1935 s = ELM_GESTURE_STATE_START;
1938 st->zoom_tolerance = 0; /* Cancel tolerance */
1939 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
1940 st->info.x = st->zoom_wheel->canvas.x;
1941 st->info.y = st->zoom_wheel->canvas.y;
1943 if (st->zoom_wheel->z > 0) /* zoom in */
1944 st->info.zoom += (wd->factor * wd->zoom_wheel_factor);
1946 if (st->zoom_wheel->z < 0) /* zoom out */
1947 st->info.zoom -= (wd->factor * wd->zoom_wheel_factor);
1949 if (st->info.zoom < 0.0)
1950 st->info.zoom = 0.0;
1952 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
1953 consume_event(wd, event_info, event_type, ev_flag);
1965 * This function is used to test zoom gesture.
1966 * user may combine zoom, rotation together.
1967 * so its possible that both will be detected from input.
1968 * (both are two-finger movement-oriented gestures)
1970 * @param obj The gesture-layer object.
1971 * @param event_info Pointer to recent input event.
1972 * @param event_type Recent input event type.
1973 * @param g_type what Gesture we are testing.
1975 * @ingroup Elm_Gesture_Layer
1978 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info, Evas_Callback_Type event_type,
1979 Elm_Gesture_Types g_type)
1983 Widget_Data *wd = elm_widget_data_get(obj);
1985 if (!wd->gesture[g_type]) return;
1987 Gesture_Info *gesture_zoom = wd->gesture[g_type];
1988 Zoom_Type *st = gesture_zoom->data;
1991 { /* Allocated once on first time, used for zoom data */
1992 st = calloc(1, sizeof(Zoom_Type));
1993 gesture_zoom->data = st;
1994 _zoom_test_reset(gesture_zoom);
1997 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2000 case EVAS_CALLBACK_MOUSE_DOWN:
2001 consume_event(wd, event_info, event_type, ev_flag);
2002 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2006 case EVAS_CALLBACK_MOUSE_MOVE:
2007 consume_event(wd, event_info, event_type, ev_flag);
2008 if (!st->zoom_st.timestamp)
2009 return; /* we got move event before down event.Ignore it */
2011 consume_event(wd, event_info, event_type, ev_flag);
2012 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2014 /* We match this point to previous multi-move or multi-down event */
2015 if (st->zoom_mv1.timestamp)
2017 st->info.zoom = compute_zoom(st,
2018 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2019 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2024 if (st->zoom_st1.timestamp)
2026 st->info.zoom = compute_zoom(st,
2027 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2028 st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2035 case EVAS_CALLBACK_MULTI_MOVE:
2036 if (!st->zoom_st1.timestamp)
2037 return; /* We get move event before down event.Ignore it */
2039 consume_event(wd, event_info, event_type, ev_flag);
2040 if (st->zoom_mv1.timestamp)
2042 if (st->zoom_mv1.device !=
2043 ((Evas_Event_Multi_Move *) event_info)->device)
2044 { /* A third finger on screen, abort zoom */
2045 ev_flag = _set_state(gesture_zoom,
2046 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2047 consume_event(wd, event_info, event_type, ev_flag);
2053 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2055 /* Match this point to previous mouse-move or mouse-down event */
2056 if (st->zoom_mv.timestamp)
2058 st->info.zoom = compute_zoom(st,
2059 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2060 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2065 if (st->zoom_st.timestamp)
2067 st->info.zoom = compute_zoom(st,
2068 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2069 st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2076 case EVAS_CALLBACK_MULTI_DOWN:
2077 consume_event(wd, event_info, event_type, ev_flag);
2078 memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2081 case EVAS_CALLBACK_MOUSE_UP:
2082 case EVAS_CALLBACK_MULTI_UP:
2083 /* Reset timestamp of finger-up.This is used later
2084 by _zoom_test_reset() to retain finger-down data */
2085 consume_event(wd, event_info, event_type, ev_flag);
2086 if(event_type == EVAS_CALLBACK_MOUSE_UP)
2087 st->zoom_st.timestamp = 0;
2089 if((event_type == EVAS_CALLBACK_MULTI_UP) &&
2090 (st->zoom_st1.device ==
2091 ((Evas_Event_Multi_Up *) event_info)->device))
2092 st->zoom_st1.timestamp = 0;
2094 if (((st->zoom_wheel) || (st->zoom_base)) &&
2095 (st->zoom_tolerance == 0))
2097 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2098 &st->info, EINA_FALSE);
2099 consume_event(wd, event_info, event_type, ev_flag);
2104 /* if we got here not a ZOOM */
2105 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2106 { /* Must be != undefined, if gesture started */
2107 ev_flag = _set_state(gesture_zoom,
2108 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2109 consume_event(wd, event_info, event_type, ev_flag);
2112 _zoom_test_reset(gesture_zoom);
2121 if (!st->zoom_tolerance)
2122 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2123 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2125 { /* Zoom broke tolerance, report move */
2126 double d = st->info.zoom - st->next_step;
2130 if(d >= wd->zoom_step)
2131 { /* Report move in steps */
2132 st->next_step = st->info.zoom;
2134 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2135 &st->info, EINA_TRUE);
2136 consume_event(wd, event_info, event_type, ev_flag);
2143 if((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2144 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2145 { /* report zoom start finger location is zoom-center temporarly */
2146 /* Zoom may have started with mouse-wheel, don't report START */
2147 if((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2148 { /* Set zoom-base after BOTH down events were recorded */
2149 /* Compute length of line between fingers on zoom start */
2150 st->info.zoom = 1.0;
2151 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2152 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2153 &st->info.x, &st->info.y);
2155 st->info.radius = st->zoom_base / 2;
2157 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2158 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2159 { /* Report START only when two fingers touching */
2160 ev_flag = _set_state(gesture_zoom,
2161 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2162 consume_event(wd, event_info, event_type, ev_flag);
2171 _get_rotate_properties(Rotate_Type *st,
2172 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2173 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2176 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2177 &st->info.x, &st->info.y) / 2;
2179 *angle = get_angle(x1, y1, x2, y2);
2180 #if 0 /* (NOT YET SUPPORTED) */
2181 if(angle == &st->info.angle)
2182 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2183 st->info.momentum = (((*angle) - st->info.base_angle) /
2184 (fabs(tm2 - tm1))) * 1000;
2187 st->info.momentum = 0;
2197 * This function is used to test rotation gesture.
2198 * user may combine zoom, rotation together.
2199 * so its possible that both will be detected from input.
2200 * (both are two-finger movement-oriented gestures)
2202 * @param obj The gesture-layer object.
2203 * @param event_info Pointer to recent input event.
2204 * @param event_type Recent input event type.
2205 * @param g_type what Gesture we are testing.
2207 * @ingroup Elm_Gesture_Layer
2210 _rotate_test(Evas_Object *obj, Pointer_Event *pe,void *event_info,
2211 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2216 Widget_Data *wd = elm_widget_data_get(obj);
2218 if (!wd->gesture[g_type]) return;
2220 Gesture_Info *gesture = wd->gesture[g_type];
2221 Rotate_Type *st = gesture->data;
2226 { /* Allocated once on first time */
2227 st = calloc(1, sizeof(Rotate_Type));
2229 _rotate_test_reset(gesture);
2233 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2237 case EVAS_CALLBACK_MOUSE_DOWN:
2238 consume_event(wd, event_info, event_type, ev_flag);
2239 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2243 case EVAS_CALLBACK_MOUSE_MOVE:
2244 if (!st->rotate_st.timestamp)
2245 break; /* We got move event before down event.Ignore it */
2247 consume_event(wd, event_info, event_type, ev_flag);
2248 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2250 /* Match this point to previous multi-move or multi-down event */
2251 if (st->rotate_mv1.timestamp)
2252 { /* Compute rotation angle and report to user */
2253 _get_rotate_properties(st,
2254 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2255 st->rotate_mv1.x,st->rotate_mv1.y, st->rotate_mv1.timestamp,
2260 if (st->rotate_st1.timestamp)
2261 { /* Compute rotation angle and report to user */
2262 _get_rotate_properties(st,
2263 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2264 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2271 case EVAS_CALLBACK_MULTI_MOVE:
2272 if (!st->rotate_st1.timestamp)
2273 break; /* We got move event before down event.Ignore it */
2275 consume_event(wd, event_info, event_type, ev_flag);
2276 if (st->rotate_mv1.timestamp)
2278 if (st->rotate_mv1.device !=
2279 ((Evas_Event_Multi_Move *) event_info)->device)
2280 { /* A third finger on screen, abort rotate */
2281 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2282 &st->info, EINA_FALSE);
2283 consume_event(wd, event_info, event_type, ev_flag);
2289 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2291 /* Match this point to previous mouse-move or mouse-down event */
2292 if (st->rotate_mv.timestamp)
2293 { /* Compute rotation angle and report to user */
2294 _get_rotate_properties(st,
2295 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2296 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2301 if (st->rotate_st.timestamp)
2302 { /* Compute rotation angle and report to user */
2303 _get_rotate_properties(st,
2304 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2305 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2312 case EVAS_CALLBACK_MULTI_DOWN:
2313 consume_event(wd, event_info, event_type, ev_flag);
2314 memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2315 _get_rotate_properties(st,
2316 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2317 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2321 case EVAS_CALLBACK_MOUSE_UP:
2322 case EVAS_CALLBACK_MULTI_UP:
2323 consume_event(wd, event_info, event_type, ev_flag);
2324 /* Reset timestamp of finger-up.This is used later
2325 by rotate_test_reset() to retain finger-down data */
2326 if(event_type == EVAS_CALLBACK_MOUSE_UP)
2327 st->rotate_st.timestamp = 0;
2329 if((event_type == EVAS_CALLBACK_MULTI_UP) &&
2330 (st->rotate_st1.device ==
2331 ((Evas_Event_Multi_Up *) event_info)->device))
2332 st->rotate_st1.timestamp = 0;
2334 if (st->rotate_tolerance < 0)
2336 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2337 &st->info, EINA_FALSE);
2338 consume_event(wd, event_info, event_type, ev_flag);
2343 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2344 { /* Must be != undefined, if gesture started */
2345 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2346 &st->info, EINA_FALSE);
2347 consume_event(wd, event_info, event_type, ev_flag);
2350 _rotate_test_reset(gesture);
2357 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2358 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2359 { /* Report MOVE or ABORT for *MOVE event */
2360 if (rotation_broke_tolerance(st))
2361 { /* Rotation broke tolerance, report move */
2362 double d = st->info.angle - st->next_step;
2366 if(d >= wd->rotate_step)
2367 { /* Report move in steps */
2368 st->next_step = st->info.angle;
2370 ev_flag = _set_state(gesture,
2371 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2372 consume_event(wd, event_info, event_type, ev_flag);
2379 if((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2380 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2382 if((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2383 { /* two-fingers on touch screen - report rotate start */
2384 /* Set base angle, then report start. */
2385 _get_rotate_properties(st,
2386 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2387 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2388 &st->info.base_angle);
2390 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2391 &st->info, EINA_FALSE);
2392 consume_event(wd, event_info, event_type, ev_flag);
2402 * This function manges a list of devices that are currently touched
2403 * when a *DOWN event for a device comes, we add it to the list
2404 * When a *UP event for a device comes, we remove it from list
2406 * @param list Pointer to device list.
2407 * @param device What device to add or remove from list
2408 * @param add When TRUE means - add to list, otherwise remove
2410 * @return The new pointer to list head
2411 * @ingroup Elm_Gesture_Layer
2414 _manage_device_list(Eina_List *list, int device, Eina_Bool add)
2420 return eina_list_append(list, (void *) device);
2422 EINA_LIST_FOREACH(list, l, data)
2423 { /* Remove device from list if found */
2424 if(device == (int) data)
2425 return eina_list_remove_list(list, l);
2434 * This function is used to save input events in an abstract struct
2435 * to be used later by getsure-testing functions.
2437 * @param data The gesture-layer object.
2438 * @param event_info Pointer to recent input event.
2439 * @param event_type Recent input event type.
2440 * @param pe The abstract data-struct (output).
2442 * @ingroup Elm_Gesture_Layer
2445 _make_pointer_event(void *data, void *event_info,
2446 Evas_Callback_Type event_type, Pointer_Event *pe)
2448 Widget_Data *wd = elm_widget_data_get(data);
2449 if (!wd) return EINA_FALSE;
2453 case EVAS_CALLBACK_MOUSE_DOWN:
2454 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2455 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2456 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2457 pe->device = ELM_MOUSE_DEVICE;
2460 case EVAS_CALLBACK_MOUSE_UP:
2461 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2462 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2463 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2464 pe->device = ELM_MOUSE_DEVICE;
2467 case EVAS_CALLBACK_MOUSE_MOVE:
2468 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2469 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2470 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2471 pe->device = ELM_MOUSE_DEVICE;
2474 case EVAS_CALLBACK_MULTI_DOWN:
2475 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2476 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2477 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2478 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2481 case EVAS_CALLBACK_MULTI_UP:
2482 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2483 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2484 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2485 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2488 case EVAS_CALLBACK_MULTI_MOVE:
2489 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2490 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2491 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2492 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2499 pe->event_type = event_type;
2506 * This function the core-function where input handling is done.
2507 * Here we get user input and stream it to gesture testing.
2508 * We notify user about any gestures with new state:
2510 * START - gesture started.
2511 * MOVE - gesture is ongoing.
2512 * END - gesture was completed.
2513 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
2515 * We also check if a gesture was detected, then reset event history
2516 * If no gestures were found we reset gesture test flag
2517 * after streaming event-history to widget.
2518 * (stream to the widget all events not consumed as a gesture)
2520 * @param data The gesture-layer object.
2521 * @param event_info Pointer to recent input event.
2522 * @param event_type Recent input event type.
2524 * @ingroup Elm_Gesture_Layer
2527 _event_process(void *data, Evas_Object *obj __UNUSED__,
2528 void *event_info, Evas_Callback_Type event_type)
2531 Pointer_Event *pe = NULL;
2532 Widget_Data *wd = elm_widget_data_get(data);
2535 _event_history_add(data, event_info, event_type);
2536 /* Start testing candidate gesture from here */
2537 if (_make_pointer_event(data, event_info, event_type, &_pe))
2540 if (IS_TESTED(ELM_GESTURE_N_TAPS))
2541 _dbl_click_test(data, pe, event_info, event_type,
2542 ELM_GESTURE_N_TAPS, 1);
2544 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
2545 _dbl_click_test(data, pe, event_info, event_type,
2546 ELM_GESTURE_N_DOUBLE_TAPS, 2);
2548 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
2549 _dbl_click_test(data, pe, event_info, event_type,
2550 ELM_GESTURE_N_TRIPLE_TAPS, 3);
2552 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
2553 _momentum_test(data, pe, event_info, event_type,
2554 ELM_GESTURE_MOMENTUM);
2556 if (IS_TESTED(ELM_GESTURE_N_LINES))
2557 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
2559 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
2560 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
2562 if (IS_TESTED(ELM_GESTURE_ZOOM))
2563 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
2565 if (IS_TESTED(ELM_GESTURE_ZOOM))
2566 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
2568 if (IS_TESTED(ELM_GESTURE_ROTATE))
2569 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
2571 /* Report current states and clear history if needed */
2572 _clear_if_finished(data);
2574 /* we maintain list of touched devices*/
2575 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2576 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2577 wd->touched = _manage_device_list(wd->touched, pe->device, EINA_TRUE);
2579 if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2580 (event_type == EVAS_CALLBACK_MULTI_UP))
2581 wd->touched = _manage_device_list(wd->touched, pe->device, EINA_FALSE);
2585 * For all _mouse_* / multi_* functions we copy event information
2586 * to newly allocated memory space with COPY_EVENT_INFO macro.
2587 * then send this event to _event_process function where
2588 * it is saved in events-history list and processes.
2589 * The allocated memeory is cleared in event_history_clear()
2591 * @param data The gesture-layer object.
2592 * @param event_info Pointer to recent input event.
2594 * @ingroup Elm_Gesture_Layer
2597 _mouse_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2600 Widget_Data *wd = elm_widget_data_get(data);
2603 Evas_Event_Mouse_In *p, *ev = event_info;
2604 COPY_EVENT_INFO(p, ev);
2605 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_IN);
2607 #if defined(DEBUG_GESTURE_LAYER)
2608 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2613 _mouse_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2616 Widget_Data *wd = elm_widget_data_get(data);
2619 Evas_Event_Mouse_Out *p, *ev = event_info;
2620 COPY_EVENT_INFO(p, ev);
2621 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_OUT);
2622 #if defined(DEBUG_GESTURE_LAYER)
2623 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2628 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2631 Widget_Data *wd = elm_widget_data_get(data);
2634 Evas_Event_Mouse_Down *p, *ev = event_info;
2635 if (ev->button != 1) /* We only process left-click at the moment */
2638 COPY_EVENT_INFO(p, ev);
2639 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_DOWN);
2640 #if defined(DEBUG_GESTURE_LAYER)
2641 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2646 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2649 Widget_Data *wd = elm_widget_data_get(data);
2652 Evas_Event_Mouse_Move *p, *ev = event_info;
2654 COPY_EVENT_INFO(p, ev);
2655 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_MOVE);
2656 #if defined(DEBUG_GESTURE_LAYER)
2657 printf("%s %d %d\n", __func__, p->cur.canvas.x, p->cur.canvas.y);
2662 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2665 Widget_Data *wd = elm_widget_data_get(data);
2668 Evas_Event_Key_Up *p, *ev = event_info;
2670 COPY_EVENT_INFO(p, ev);
2671 _event_process(data, obj, (void *) p, EVAS_CALLBACK_KEY_UP);
2673 #if defined(DEBUG_GESTURE_LAYER)
2674 printf("%s %s\n", __func__, p->keyname);
2679 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2682 Widget_Data *wd = elm_widget_data_get(data);
2685 Evas_Event_Mouse_Up *p, *ev = event_info;
2686 if (ev->button != 1) /* We only process left-click at the moment */
2689 COPY_EVENT_INFO(p, ev);
2690 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_UP);
2691 #if defined(DEBUG_GESTURE_LAYER)
2692 printf("%s %d %d\n", __func__, p->canvas.x, p->canvas.y);
2697 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2700 Widget_Data *wd = elm_widget_data_get(data);
2703 Evas_Event_Mouse_Wheel *p, *ev = event_info;
2704 COPY_EVENT_INFO(p, ev);
2705 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MOUSE_WHEEL);
2706 #if defined(DEBUG_GESTURE_LAYER)
2707 printf("%s %d %d %d\n", __func__, p->canvas.x, p->canvas.y, p->z);
2712 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2715 Widget_Data *wd = elm_widget_data_get(data);
2718 Evas_Event_Multi_Down *p, *ev = event_info;
2719 COPY_EVENT_INFO(p, ev);
2720 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MULTI_DOWN);
2721 #if defined(DEBUG_GESTURE_LAYER)
2722 printf("%s %d\n", __func__, __LINE__);
2723 printf("radius=<%3.2f> radius_x=<%3.2f> radius_y=<%3.2f> device: <%d>\n",
2724 p->radius, p->radius_x, p->radius_y, p->device);
2725 printf("pressure<%3.2f> angle<%3.2f>\n", p->pressure, p->angle);
2726 printf("output.x=<%d> output.y=<%d>\n", p->output.x, p->output.y);
2727 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);
2732 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2735 Widget_Data *wd = elm_widget_data_get(data);
2738 Evas_Event_Multi_Move *p, *ev = event_info;
2739 COPY_EVENT_INFO(p, ev);
2740 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MULTI_MOVE);
2741 #if defined(DEBUG_GESTURE_LAYER)
2742 printf("%s %d\n", __func__, __LINE__);
2743 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);
2744 printf("pressure<%3.2f> angle<%3.2f>\n", p->pressure, p->angle);
2745 printf("output.x=<%d> output.y=<%d>\n", p->cur.output.x, p->cur.output.y);
2746 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);
2751 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2754 Widget_Data *wd = elm_widget_data_get(data);
2757 Evas_Event_Multi_Up *p, *ev = event_info;
2758 COPY_EVENT_INFO(p, ev);
2759 _event_process(data, obj, (void *) p, EVAS_CALLBACK_MULTI_UP);
2760 #if defined(DEBUG_GESTURE_LAYER)
2761 printf("%s %d\n", __func__, __LINE__);
2762 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);
2763 printf("pressure<%3.2f> angle<%3.2f>\n", p->pressure, p->angle);
2764 printf("output.x=<%d> output.y=<%d>\n", p->output.x, p->output.y);
2765 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);
2770 elm_gesture_layer_hold_events_get(Evas_Object *obj)
2772 Widget_Data *wd = elm_widget_data_get(obj);
2773 if (!wd) return EINA_FALSE;
2775 return !wd->repeat_events;
2779 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
2781 Widget_Data *wd = elm_widget_data_get(obj);
2784 wd->repeat_events = !r;
2788 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
2790 Widget_Data *wd = elm_widget_data_get(obj);
2800 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
2802 Widget_Data *wd = elm_widget_data_get(obj);
2808 wd->rotate_step = s;
2812 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
2814 Widget_Data *wd = elm_widget_data_get(obj);
2815 if (!wd) return EINA_FALSE;
2820 /* if was attached before, unregister callbacks first */
2822 _unregister_callbacks(obj);
2826 _register_callbacks(obj);
2831 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
2832 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
2834 Widget_Data *wd = elm_widget_data_get(obj);
2837 if (!wd->gesture[idx])
2838 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
2840 Gesture_Info *p = wd->gesture[idx];
2843 p->fn[cb_type].cb = cb;
2844 p->fn[cb_type].user_data = data;
2845 p->state = ELM_GESTURE_STATE_UNDEFINED;
2850 _disable_hook(Evas_Object *obj)
2852 if (elm_widget_disabled_get(obj))
2853 _unregister_callbacks(obj);
2855 _register_callbacks(obj);
2859 elm_gesture_layer_add(Evas_Object *parent)
2865 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2867 wd = ELM_NEW(Widget_Data);
2868 e = evas_object_evas_get(parent);
2869 if (!e) return NULL;
2870 obj = elm_widget_add(e);
2871 ELM_SET_WIDTYPE(widtype, "gesture_layer");
2872 elm_widget_type_set(obj, "gesture_layer");
2873 elm_widget_sub_object_add(parent, obj);
2874 elm_widget_data_set(obj, wd);
2875 elm_widget_del_hook_set(obj, _del_hook);
2876 elm_widget_disable_hook_set(obj, _disable_hook);
2879 wd->line_min_length = wd->zoom_tolerance = elm_finger_size_get();
2880 wd->line_tolerance = elm_finger_size_get() * 3;
2881 wd->factor = ELM_GESTURE_ZOOM_FACTOR;
2882 wd->zoom_wheel_factor = ELM_GESTURE_ZOOM_WHEEL_FACTOR ; /* mouse wheel zoom steps */
2883 wd->rotate_tolerance = ELM_GESTURE_ROTATION_TOLERANCE;
2884 wd->repeat_events = EINA_TRUE;
2886 #if defined(DEBUG_GESTURE_LAYER)
2887 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
2889 memset(wd->gesture, 0, sizeof(wd->gesture));