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)
24 _glayer_bufdup(void *buf, size_t size)
31 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
34 #define SET_TEST_BIT(P) do { \
35 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; \
38 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
44 * Struct holds callback information.
46 * @ingroup Elm_Gesture_Layer
50 void *user_data; /**< Holds user data to CB (like sd) */
51 Elm_Gesture_Event_Cb cb;
58 * type for callback information
60 * @ingroup Elm_Gesture_Layer
62 typedef struct _Func_Data Func_Data;
67 * @struct _Gesture_Info
68 * Struct holds gesture info
70 * @ingroup Elm_Gesture_Layer
75 void *data; /**< Holds gesture intemidiate processing data */
76 Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
77 Elm_Gesture_Types g_type; /**< gesture type */
78 Elm_Gesture_State state; /**< gesture state */
79 void *info; /**< Data for the state callback */
80 Eina_Bool test; /**< if true this gesture should be tested on input */
86 * @typedef Gesture_Info
87 * Type for _Gesture_Info
89 * @ingroup Elm_Gesture_Layer
91 typedef struct _Gesture_Info Gesture_Info;
96 * @struct _Event_History
97 * Struct holds event history.
98 * These events are repeated if no gesture found.
100 * @ingroup Elm_Gesture_Layer
102 struct _Event_History
106 Evas_Callback_Type event_type;
112 * @typedef Event_History
113 * Type for _Event_History
115 * @ingroup Elm_Gesture_Layer
117 typedef struct _Event_History Event_History;
122 * @struct _Pointer_Event
123 * Struct holds pointer-event info
124 * This is a generic pointer event structure
126 * @ingroup Elm_Gesture_Layer
128 struct _Pointer_Event
131 unsigned int timestamp;
133 Evas_Callback_Type event_type;
139 * @typedef Pointer_Event
140 * Type for generic pointer event structure
142 * @ingroup Elm_Gesture_Layer
144 typedef struct _Pointer_Event Pointer_Event;
146 /* All *Type structs hold result for the user in 'info' field
147 * The rest is gesture processing intermediate data.
148 * NOTE: info field must be FIRST in the struct.
149 * This is used when reporting ABORT in event_history_clear() */
152 Elm_Gesture_Taps_Info info;
153 unsigned int count_ups;
159 typedef struct _Taps_Type Taps_Type;
161 struct _Momentum_Type
162 { /* Fields used by _line_test() */
163 Elm_Gesture_Momentum_Info info;
164 Evas_Coord_Point line_st;
165 Evas_Coord_Point line_end;
166 unsigned int t_st_x; /* Time start on X */
167 unsigned int t_st_y; /* Time start on Y */
168 unsigned int t_end; /* Time end */
171 typedef struct _Momentum_Type Momentum_Type;
175 Evas_Coord_Point line_st;
176 Evas_Coord_Point line_end;
177 Evas_Coord line_length;
178 unsigned int t_st; /* Time start */
179 unsigned int t_end; /* Time end */
181 double line_angle; /* Current angle of line */
183 typedef struct _Line_Data Line_Data;
186 { /* Fields used by _line_test() */
187 Elm_Gesture_Line_Info info;
188 Eina_List *list; /* List of Line_Data */
190 typedef struct _Line_Type Line_Type;
193 { /* Fields used by _zoom_test() */
194 Elm_Gesture_Zoom_Info info;
195 Pointer_Event zoom_st;
196 Pointer_Event zoom_mv;
197 Pointer_Event zoom_st1;
198 Pointer_Event zoom_mv1;
199 Evas_Event_Mouse_Wheel *zoom_wheel;
200 Evas_Coord zoom_base; /* Holds gap between fingers on zoom-start */
201 Evas_Coord zoom_tolerance;
204 typedef struct _Zoom_Type Zoom_Type;
207 { /* Fields used by _rotation_test() */
208 Elm_Gesture_Rotate_Info info;
209 Pointer_Event rotate_st;
210 Pointer_Event rotate_mv;
211 Pointer_Event rotate_st1;
212 Pointer_Event rotate_mv1;
213 double rotate_tolerance;
216 typedef struct _Rotate_Type Rotate_Type;
220 Evas_Object *target; /* Target Widget */
221 Event_History *event_history_list;
224 Evas_Coord zoom_tolerance;
225 Evas_Coord line_tolerance;
226 float zoom_wheel_factor; /* mouse wheel zoom steps */
227 float factor; /* used for zoom factor */
228 double rotate_tolerance;
233 Gesture_Info *gesture[ELM_GESTURE_LAST];
234 Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed */
235 Eina_List *pending; /* List of devices need to refeed *UP event */
236 int touched; /* Int containing number of touched devices */
238 Eina_Bool repeat_events : 1;
240 typedef struct _Widget_Data Widget_Data;
242 static const char *widtype = NULL;
243 static void _del_hook(Evas_Object *obj);
245 static void _event_history_clear(Evas_Object *obj);
246 static void _reset_states(Widget_Data *wd);
247 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
248 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
249 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
250 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
251 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
252 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
253 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
255 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
256 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
257 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
260 _dbl_click_test_reset(Gesture_Info *gesture)
265 Widget_Data *wd = elm_widget_data_get(gesture->obj);
266 if (wd->dbl_timeout) ecore_timer_del(wd->dbl_timeout);
267 wd->dbl_timeout = NULL;
274 EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
275 EINA_LIST_FREE(data, pe)
278 memset(gesture->data, 0, sizeof(Taps_Type));
285 * @param event_info pointer to event.
287 * @ingroup Elm_Gesture_Layer
289 static Evas_Event_Flags
290 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
294 case EVAS_CALLBACK_MOUSE_IN:
295 return ((Evas_Event_Mouse_In *) event_info)->event_flags;
296 case EVAS_CALLBACK_MOUSE_OUT:
297 return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
298 case EVAS_CALLBACK_MOUSE_DOWN:
299 return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
300 case EVAS_CALLBACK_MOUSE_MOVE:
301 return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
302 case EVAS_CALLBACK_MOUSE_UP:
303 return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
304 case EVAS_CALLBACK_MOUSE_WHEEL:
305 return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
306 case EVAS_CALLBACK_MULTI_DOWN:
307 return ((Evas_Event_Multi_Down *) event_info)->event_flags;
308 case EVAS_CALLBACK_MULTI_MOVE:
309 return ((Evas_Event_Multi_Move *) event_info)->event_flags;
310 case EVAS_CALLBACK_MULTI_UP:
311 return ((Evas_Event_Multi_Up *) event_info)->event_flags;
312 case EVAS_CALLBACK_KEY_DOWN:
313 return ((Evas_Event_Key_Down *) event_info)->event_flags;
314 case EVAS_CALLBACK_KEY_UP:
315 return ((Evas_Event_Key_Up *) event_info)->event_flags;
317 return EVAS_EVENT_FLAG_NONE;
324 * Sets event flag to value returned from user callback
325 * @param wd Widget Data
326 * @param event_info pointer to event.
327 * @param event_type what type was ev (mouse down, etc...)
328 * @param ev_flags event flags
330 * @ingroup Elm_Gesture_Layer
333 consume_event(Widget_Data *wd, void *event_info,
334 Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
335 { /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
336 /* ev_flags != EVAS_EVENT_FLAG_NONE means target used the event and g-layer */
337 /* should not refeed this event. */
338 if ((ev_flags) || (!wd->repeat_events))
342 case EVAS_CALLBACK_MOUSE_DOWN:
343 ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
345 case EVAS_CALLBACK_MOUSE_MOVE:
346 ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
348 case EVAS_CALLBACK_MOUSE_UP:
349 ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
351 case EVAS_CALLBACK_MOUSE_WHEEL:
352 ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
354 case EVAS_CALLBACK_MULTI_DOWN:
355 ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
357 case EVAS_CALLBACK_MULTI_MOVE:
358 ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
360 case EVAS_CALLBACK_MULTI_UP:
361 ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
363 case EVAS_CALLBACK_KEY_DOWN:
364 ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
366 case EVAS_CALLBACK_KEY_UP:
367 ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
378 * Report current state of a gesture by calling user callback.
379 * @param gesture what gesture state we report.
380 * @param info inforamtion for user callback
382 * @ingroup Elm_Gesture_Layer
384 static Evas_Event_Flags
385 _report_state(Gesture_Info *gesture, void *info)
386 { /* We report current state (START, MOVE, END, ABORT), once */
387 #if defined(DEBUG_GESTURE_LAYER)
388 printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, g_type,
391 if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
392 (gesture->fn[gesture->state].cb))
393 { /* Fill state-info struct and send ptr to user callback */
394 return gesture->fn[gesture->state].cb(
395 gesture->fn[gesture->state].user_data, info);
398 return EVAS_EVENT_FLAG_NONE;
404 * Update state for a given gesture.
405 * We may update gesture state to:
406 * UNDEFINED - current input did not start gesure yet.
407 * START - gesture started according to input.
408 * MOVE - gusture in progress.
409 * END - gesture completed according to input.
410 * ABORT - input does not matches gesure.
411 * note that we may move from UNDEFINED to ABORT
412 * because we may detect that gesture will not START
413 * with a given input.
415 * @param g given gesture to change state.
416 * @param s gesure new state.
417 * @param info buffer to be sent to user callback on report_state.
418 * @param force makes report_state to report the new-state even
419 * if its same as current state. Works for MOVE - gesture in progress.
421 * @ingroup Elm_Gesture_Layer
423 static Evas_Event_Flags
424 _set_state(Gesture_Info *g, Elm_Gesture_State s,
425 void *info, Eina_Bool force)
427 Elm_Gesture_State old_state;
428 if ((g->state == s) && (!force))
429 return EVAS_EVENT_FLAG_NONE;
431 old_state = g->state;
434 g->info = info; /* Information for user callback */
435 if ((g->state == ELM_GESTURE_STATE_ABORT) ||
436 (g->state == ELM_GESTURE_STATE_END))
437 g->test = EINA_FALSE;
439 if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
440 (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
441 (s == ELM_GESTURE_STATE_ABORT))))
442 return _report_state(g, g->info);
444 return EVAS_EVENT_FLAG_NONE;
450 * This resets all gesture states and sets test-bit.
451 * this is used for restarting gestures to listen to input.
452 * happens after we complete a gesture or no gesture was detected.
453 * @param wd Widget data of the gesture-layer object.
455 * @ingroup Elm_Gesture_Layer
458 _reset_states(Widget_Data *wd)
462 for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
467 _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
476 * if gesture was NOT detected AND we only have gestures in ABORT state
477 * we clear history immediately to be ready for input.
479 * @param obj The gesture-layer object.
481 * @ingroup Elm_Gesture_Layer
484 _clear_if_finished(Evas_Object *obj)
486 Widget_Data *wd = elm_widget_data_get(obj);
490 /* Clear history if all we have aborted gestures */
491 Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
492 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
493 { /* If no gesture started and all we have aborted gestures, reset all */
494 Gesture_Info *p = wd->gesture[i];
495 if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
497 if ((p->state == ELM_GESTURE_STATE_START) ||
498 (p->state == ELM_GESTURE_STATE_MOVE))
499 reset_s = EINA_FALSE;
501 all_undefined = EINA_FALSE;
505 // if ((!wd->touched) || (reset_s && !all_undefined))
506 /* (!wd->touched && reset_s) - don't stop zoom with mouse-wheel */
507 if ((!wd->touched && reset_s) || (reset_s && !all_undefined))
508 _event_history_clear(obj);
512 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
514 int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
533 * when this timer expires we ABORT double click gesture.
535 * @param data The gesture-layer object.
536 * @return cancles callback for this timer.
538 * @ingroup Elm_Gesture_Layer
541 _dbl_click_timeout(void *data)
543 Gesture_Info *gesture = data;
544 Widget_Data *wd = elm_widget_data_get(gesture->obj);
546 wd->dbl_timeout = NULL;
547 _set_state(gesture, ELM_GESTURE_STATE_ABORT,
548 gesture->info, EINA_FALSE);
550 _dbl_click_test_reset(gesture);
551 _clear_if_finished(gesture->obj);
552 return ECORE_CALLBACK_CANCEL;
555 /* All *test_reset() funcs are called to clear
556 * gesture intermediate data.
557 * This happens when we need to reset our tests.
558 * for example when gesture is detected or all ABORTed. */
560 _momentum_test_reset(Gesture_Info *gesture)
568 memset(gesture->data, 0, sizeof(Momentum_Type));
572 _line_data_reset(Line_Data *st)
577 memset(st, 0, sizeof(Line_Data));
578 st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
582 _line_test_reset(Gesture_Info *gesture)
590 Line_Type *st = gesture->data;
591 Eina_List *list = st->list;
594 EINA_LIST_FOREACH(list, l, t_line)
597 eina_list_free(list);
602 _zoom_test_reset(Gesture_Info *gesture)
610 Widget_Data *wd = elm_widget_data_get(gesture->obj);
611 Zoom_Type *st = gesture->data;
612 Pointer_Event pe, pe1;
614 pe.timestamp = pe1.timestamp = 0;
616 if(st->zoom_st.timestamp)
617 memcpy(&pe, &st->zoom_st, sizeof(Pointer_Event));
619 if(st->zoom_st1.timestamp)
620 memcpy(&pe1, &st->zoom_st1, sizeof(Pointer_Event));
622 memset(st, 0, sizeof(Zoom_Type));
624 /* If user released one finger only, restore down-info */
625 if(pe.timestamp && (!pe1.timestamp))
626 memcpy(&st->zoom_st, &pe, sizeof(Pointer_Event));
628 if(pe1.timestamp && (!pe.timestamp))
629 memcpy(&st->zoom_st1, &pe1, sizeof(Pointer_Event));
631 st->zoom_tolerance = wd->zoom_tolerance;
636 _rotate_test_reset(Gesture_Info *gesture)
644 Widget_Data *wd = elm_widget_data_get(gesture->obj);
645 Rotate_Type *st = gesture->data;
646 Pointer_Event pe, pe1;
648 pe.timestamp = pe1.timestamp = 0;
650 if(st->rotate_st.timestamp)
651 memcpy(&pe, &st->rotate_st, sizeof(Pointer_Event));
653 if(st->rotate_st1.timestamp)
654 memcpy(&pe1, &st->rotate_st1, sizeof(Pointer_Event));
656 memset(st, 0, sizeof(Rotate_Type));
658 /* If user released one finger only, restore down-info */
659 if(pe.timestamp && (!pe1.timestamp))
660 memcpy(&st->rotate_st, &pe, sizeof(Pointer_Event));
662 if(pe1.timestamp && (!pe.timestamp))
663 memcpy(&st->rotate_st1, &pe1, sizeof(Pointer_Event));
666 st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
667 st->rotate_tolerance = wd->rotate_tolerance;
674 * We register callbacks when gesture layer is attached to an object
675 * or when its enabled after disable.
677 * @param obj The gesture-layer object.
679 * @ingroup Elm_Gesture_Layer
682 _register_callbacks(Evas_Object *obj)
684 Widget_Data *wd = elm_widget_data_get(obj);
689 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
691 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
693 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
696 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
699 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
701 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
703 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
706 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, obj);
707 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb, obj);
714 * We unregister callbacks when gesture layer is disabled.
716 * @param obj The gesture-layer object.
718 * @ingroup Elm_Gesture_Layer
721 _unregister_callbacks(Evas_Object *obj)
723 Widget_Data *wd = elm_widget_data_get(obj);
728 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
730 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
732 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
735 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
738 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
741 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
744 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
747 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN, _key_down_cb);
748 evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP, _key_up_cb);
752 /* START - Event history list handling functions */
755 * This function is used to find if device number
756 * is found in a list of devices.
757 * The list contains devices for refeeding *UP event
759 * @ingroup Elm_Gesture_Layer
762 device_in_list(const void *data1, const void *data2)
763 { /* Compare the two device numbers */
764 return (((int) data1) - ((int) data2));
770 * This functions adds device to refeed-pending device list
771 * @ingroup Elm_Gesture_Layer
774 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
776 int device = ELM_MOUSE_DEVICE;
779 case EVAS_CALLBACK_MOUSE_DOWN:
781 case EVAS_CALLBACK_MULTI_DOWN:
782 device = ((Evas_Event_Multi_Down *) event)->device;
788 if (!eina_list_search_unsorted_list(list, device_in_list, (void *) device))
790 printf("%s ======> Added <%d>\n", __func__, device);
791 return eina_list_append(list, (void *) device);
800 * This functions returns pending-device node
801 * @ingroup Elm_Gesture_Layer
804 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
806 int device = ELM_MOUSE_DEVICE;
809 case EVAS_CALLBACK_MOUSE_UP:
811 case EVAS_CALLBACK_MULTI_UP:
812 device = ((Evas_Event_Multi_Up *) event)->device;
818 return eina_list_search_unsorted_list(list, device_in_list, (void *) device);
824 * This function reports ABORT to all none-detected gestures
825 * Then resets test bits for all desired gesures
826 * and clears input-events history.
827 * note: if no gesture was detected, events from history list
828 * are streamed to the widget because it's unused by layer.
829 * user may cancel refeed of events by setting repeat events.
831 * @param obj The gesture-layer object.
833 * @ingroup Elm_Gesture_Layer
836 _event_history_clear(Evas_Object *obj)
838 Widget_Data *wd = elm_widget_data_get(obj);
843 Evas *e = evas_object_evas_get(obj);
844 Eina_Bool gesture_found = EINA_FALSE;
845 for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
850 if (p->state == ELM_GESTURE_STATE_END)
851 gesture_found = EINA_TRUE;
853 { /* Report ABORT to all gestures that still not finished */
854 _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
860 _reset_states(wd); /* we are ready to start testing for gestures again */
862 /* Clear all gestures intermediate date */
863 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
864 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
865 _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
866 _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
867 _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
868 _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
869 _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
870 _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
872 /* Disable gesture layer so refeeded events won't be consumed by it */
873 _unregister_callbacks(obj);
874 while (wd->event_history_list)
877 t = wd->event_history_list;
878 Eina_List *pending = _device_is_pending(wd->pending, wd->event_history_list->event, wd->event_history_list->event_type);
880 /* Refeed events if no gesture matched input */
881 if (pending || ((!gesture_found) && (!wd->repeat_events)))
883 evas_event_refeed_event(e, wd->event_history_list->event, wd->event_history_list->event_type);
887 wd->pending = eina_list_remove_list(wd->pending, pending);
888 int device = ELM_MOUSE_DEVICE;
889 if(wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
890 device = ((Evas_Event_Multi_Up *) (wd->event_history_list->event))->device;
891 printf("%s ======> Removed <%d>\n", __func__, device);
894 wd->pending = _add_device_pending(wd->pending, wd->event_history_list->event, wd->event_history_list->event_type);
897 free(wd->event_history_list->event);
898 wd->event_history_list = (Event_History *) eina_inlist_remove(
899 EINA_INLIST_GET(wd->event_history_list),
900 EINA_INLIST_GET(wd->event_history_list));
903 _register_callbacks(obj);
909 * This function copies input events.
910 * We copy event info before adding it to history.
911 * The memory is freed when we clear history.
913 * @param event the event to copy
914 * @param event_type event type to copy
916 * @ingroup Elm_Gesture_Layer
919 _copy_event_info(void *event, Evas_Callback_Type event_type)
923 case EVAS_CALLBACK_MOUSE_DOWN:
924 return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
926 case EVAS_CALLBACK_MOUSE_MOVE:
927 return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
929 case EVAS_CALLBACK_MOUSE_UP:
930 return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
932 case EVAS_CALLBACK_MOUSE_WHEEL:
933 return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
935 case EVAS_CALLBACK_MULTI_DOWN:
936 return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
938 case EVAS_CALLBACK_MULTI_MOVE:
939 return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
941 case EVAS_CALLBACK_MULTI_UP:
942 return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
944 case EVAS_CALLBACK_KEY_DOWN:
945 return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
947 case EVAS_CALLBACK_KEY_UP:
948 return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
956 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
958 Widget_Data *wd = elm_widget_data_get(obj);
960 if (!wd) return EINA_FALSE;
962 ev = malloc(sizeof(Event_History));
963 ev->event = _copy_event_info(event, event_type); /* Freed on event_history_clear */
964 ev->event_type = event_type;
965 wd->event_history_list = (Event_History *) eina_inlist_append(
966 EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
970 /* END - Event history list handling functions */
973 _del_hook(Evas_Object *obj)
975 Widget_Data *wd = elm_widget_data_get(obj);
978 _event_history_clear(obj);
979 eina_list_free(wd->pending);
981 if (!elm_widget_disabled_get(obj))
982 _unregister_callbacks(obj);
984 /* Free all gestures internal data structures */
986 for (i = 0; i < ELM_GESTURE_LAST; i++)
989 if (wd->gesture[i]->data)
990 free(wd->gesture[i]->data);
992 free(wd->gesture[i]);
999 compare_match_fingers(const void *data1, const void *data2)
1000 { /* Compare coords of first item in list to cur coords */
1001 const Pointer_Event *pe1 = eina_list_data_get(data1);
1002 const Pointer_Event *pe2 = data2;
1004 if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1006 else if (pe1->x < pe2->x)
1010 if (pe1->x == pe2->x)
1011 return pe1->y - pe2->y;
1018 compare_pe_device(const void *data1, const void *data2)
1019 { /* Compare coords of first item in list to cur coords */
1020 const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1021 const Pointer_Event *pe2 = data2;
1023 /* Only match if last was a down event */
1024 if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1025 (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1029 if (pe1->device == pe2->device)
1031 else if (pe1->device < pe2->device)
1038 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe, Widget_Data *wd, void *event_info,
1039 Evas_Callback_Type event_type)
1040 { /* Keep copy of pe and record it in list */
1041 Pointer_Event *p = malloc(sizeof(Pointer_Event));
1042 memcpy(p, pe, sizeof(Pointer_Event));
1043 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1049 /* This will also update middle-point to report to user later */
1050 st->info.x = st->sum_x / st->n_taps;
1051 st->info.y = st->sum_y / st->n_taps;
1052 st->info.timestamp = pe->timestamp;
1056 pe_list = eina_list_append(pe_list, p);
1057 st->l = eina_list_append(st->l, pe_list);
1060 pe_list = eina_list_append(pe_list, p);
1068 * This function checks all click/tap and double/triple taps
1070 * @param obj The gesture-layer object.
1071 * @param pe The recent input event as stored in pe struct.
1072 * @param event_info Original input event pointer.
1073 * @param event_type Type of original input event.
1074 * @param g_type what Gesture we are testing.
1075 * @param taps How many click/taps we test for.
1077 * @ingroup Elm_Gesture_Layer
1080 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
1081 void *event_info, Evas_Callback_Type event_type,
1082 Elm_Gesture_Types g_type, int taps)
1083 { /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1084 Widget_Data *wd = elm_widget_data_get(obj);
1087 if (!pe) /* this happens when unhandled event arrived */
1088 return; /* see _make_pointer_event function */
1090 Gesture_Info *gesture = wd->gesture[g_type];
1091 if (!gesture ) return;
1093 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1095 return; /* user left a finger on device, do NOT start */
1097 Taps_Type *st = gesture->data;
1099 { /* Allocated once on first time */
1100 st = calloc(1, sizeof(Taps_Type));
1102 _dbl_click_test_reset(gesture);
1105 Eina_List *pe_list = NULL;
1106 Pointer_Event *pe_down = NULL;
1107 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1108 switch (pe->event_type)
1110 case EVAS_CALLBACK_MULTI_DOWN:
1111 case EVAS_CALLBACK_MOUSE_DOWN:
1112 pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1113 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1114 if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1115 { /* This is the first mouse down we got */
1116 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1117 &st->info, EINA_FALSE);
1118 consume_event(wd, event_info, event_type, ev_flag);
1120 /* To test dbl_click/dbl_tap */
1121 /* When this timer expires, gesture ABORTed if not completed */
1122 if (!wd->dbl_timeout && (taps > 1))
1123 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
1130 case EVAS_CALLBACK_MULTI_UP:
1131 case EVAS_CALLBACK_MOUSE_UP:
1132 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1134 return; /* Got only first mouse_down and mouse_up */
1136 pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1138 if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
1139 return; /* Got only first mouse_down and mouse_up */
1141 /* Get first event in first list, this has to be Mouse Down event */
1142 pe_down = eina_list_data_get(pe_list);
1144 if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1150 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1151 &st->info, EINA_FALSE);
1152 consume_event(wd, event_info, event_type, ev_flag);
1156 if (st->count_ups == eina_list_count(st->l))
1158 /* Abort if we found a single click */
1159 if ((taps == 1) && (st->count_ups == 1))
1161 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1162 &st->info, EINA_FALSE);
1163 consume_event(wd, event_info, event_type, ev_flag);
1166 st->info.n = st->count_ups;
1167 ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1168 &st->info, EINA_FALSE);
1169 consume_event(wd, event_info, event_type, ev_flag);
1176 case EVAS_CALLBACK_MULTI_MOVE:
1177 case EVAS_CALLBACK_MOUSE_MOVE:
1178 /* Get first event in first list, this has to be a Mouse Down event */
1179 /* and verify that user didn't move out of this area before next tap */
1180 pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1183 pe_down = eina_list_data_get(pe_list);
1184 if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1186 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1187 &st->info, EINA_FALSE);
1188 consume_event(wd, event_info, event_type, ev_flag);
1201 * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1202 * This momentum value will be sent to widget when gesture is completed.
1204 * @param momentum pointer to buffer where we record momentum value.
1205 * @param x1 x coord where user started gesture.
1206 * @param y1 y coord where user started gesture.
1207 * @param x2 x coord where user completed gesture.
1208 * @param y2 y coord where user completed gesture.
1209 * @param t1x timestamp for X, when user started gesture.
1210 * @param t1y timestamp for Y, when user started gesture.
1211 * @param t2 timestamp when user completed gesture.
1213 * @ingroup Elm_Gesture_Layer
1216 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1217 Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1220 Evas_Coord velx = 0, vely = 0, vel;
1221 Evas_Coord dx = x2 - x1;
1222 Evas_Coord dy = y2 - y1;
1226 velx = (dx * 1000) / dtx;
1229 vely = (dy * 1000) / dty;
1231 vel = sqrt((velx * velx) + (vely * vely));
1233 if ((_elm_config->thumbscroll_friction > 0.0) &&
1234 (vel > _elm_config->thumbscroll_momentum_threshold))
1235 { /* report momentum */
1236 momentum->mx = velx;
1237 momentum->my = vely;
1249 * This function is used for computing rotation angle (DEG).
1251 * @param x1 first finger x location.
1252 * @param y1 first finger y location.
1253 * @param x2 second finger x location.
1254 * @param y2 second finger y location.
1256 * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1258 * @ingroup Elm_Gesture_Layer
1261 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1267 if (((int) xx) && ((int) yy))
1274 return RAD_360DEG - a;
1285 return RAD_180DEG + a;
1289 return RAD_180DEG - a;
1295 { /* Horizontal line */
1320 * This function is used for computing the magnitude and direction
1321 * of vector between two points.
1323 * @param x1 first finger x location.
1324 * @param y1 first finger y location.
1325 * @param x2 second finger x location.
1326 * @param y2 second finger y location.
1327 * @param l length computed (output)
1328 * @param a angle computed (output)
1330 * @ingroup Elm_Gesture_Layer
1333 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1334 Evas_Coord *l, double *a)
1339 *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1340 *a = get_angle(x1, y1, x2, y2);
1344 _get_direction(Evas_Coord x1, Evas_Coord x2)
1357 * This function tests momentum gesture.
1358 * @param obj The gesture-layer object.
1359 * @param pe The recent input event as stored in pe struct.
1360 * @param event_info recent input event.
1361 * @param event_type recent event type.
1362 * @param g_type what Gesture we are testing.
1364 * @ingroup Elm_Gesture_Layer
1367 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1368 void *event_info, Evas_Callback_Type event_type,
1369 Elm_Gesture_Types g_type)
1371 Widget_Data *wd = elm_widget_data_get(obj);
1373 Gesture_Info *gesture = wd->gesture[g_type];
1374 if (!gesture ) return;
1376 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1378 return; /* user left a finger on device, do NOT start */
1380 Momentum_Type *st = gesture->data;
1382 { /* Allocated once on first time */
1383 st = calloc(1, sizeof(Momentum_Type));
1385 _momentum_test_reset(gesture);
1391 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1392 switch (pe->event_type)
1394 case EVAS_CALLBACK_MOUSE_DOWN:
1395 st->line_st.x = st->line_end.x = pe->x;
1396 st->line_st.y = st->line_end.y = pe->y;
1397 st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1398 st->xdir = st->ydir = 0;
1399 st->info.x2 = st->info.x1 = pe->x;
1400 st->info.y2 = st->info.y1 = pe->y;
1401 st->info.tx = st->info.ty = pe->timestamp;
1402 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1403 &st->info, EINA_FALSE);
1404 consume_event(wd, event_info, event_type, ev_flag);
1407 case EVAS_CALLBACK_MOUSE_UP:
1408 /* IGNORE if line info was cleared, like long press, move */
1412 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1414 /* Too long of a wait, reset all values */
1415 st->line_st.x = pe->x;
1416 st->line_st.y = pe->y;
1417 st->t_st_y = st->t_st_x = pe->timestamp;
1418 st->xdir = st->ydir = 0;
1421 st->info.x2 = pe->x;
1422 st->info.y2 = pe->y;
1423 st->line_end.x = pe->x;
1424 st->line_end.y = pe->y;
1425 st->t_end = pe->timestamp;
1427 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1428 st->t_st_x, st->t_st_y, pe->timestamp);
1430 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1432 consume_event(wd, event_info, event_type, ev_flag);
1436 case EVAS_CALLBACK_MOUSE_MOVE:
1437 /* IGNORE if line info was cleared, like long press, move */
1441 if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1443 /* Too long of a wait, reset all values */
1444 st->line_st.x = pe->x;
1445 st->line_st.y = pe->y;
1446 st->t_st_y = st->t_st_x = pe->timestamp;
1447 st->info.tx = st->t_st_x;
1448 st->info.ty = st->t_st_y;
1449 st->xdir = st->ydir = 0;
1454 xdir = _get_direction(st->line_end.x, pe->x);
1455 ydir = _get_direction(st->line_end.y, pe->y);
1456 if (!xdir || (xdir == (-st->xdir)))
1458 st->line_st.x = st->line_end.x;
1459 st->info.tx = st->t_st_x = st->t_end;
1463 if (!ydir || (ydir == (-st->ydir)))
1465 st->line_st.y = st->line_end.y;
1466 st->info.ty = st->t_st_y = st->t_end;
1471 st->info.x2 = st->line_end.x = pe->x;
1472 st->info.y2 = st->line_end.y = pe->y;
1473 st->t_end = pe->timestamp;
1474 _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1475 st->t_st_x, st->t_st_y, pe->timestamp);
1476 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE, &st->info,
1478 consume_event(wd, event_info, event_type, ev_flag);
1481 case EVAS_CALLBACK_MULTI_UP:
1482 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1484 consume_event(wd, event_info, event_type, ev_flag);
1493 compare_line_device(const void *data1, const void *data2)
1494 { /* Compare device component of line struct */
1495 const Line_Data *ln1 = data1;
1496 const int *device = data2;
1498 if (ln1->t_st) /* Compare only with lines that started */
1499 return (ln1->device - (*device));
1507 * This function construct line struct from input.
1508 * @param info pointer to store line momentum.
1509 * @param st line info to store input data.
1510 * @param pe The recent input event as stored in pe struct.
1512 * @ingroup Elm_Gesture_Layer
1515 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1517 { /* Record events and set momentum for line pointed by st */
1521 switch (pe->event_type)
1523 case EVAS_CALLBACK_MOUSE_DOWN:
1524 case EVAS_CALLBACK_MULTI_DOWN:
1525 st->line_st.x = pe->x;
1526 st->line_st.y = pe->y;
1527 st->t_st = pe->timestamp;
1528 st->device = pe->device;
1529 info->momentum.x1 = pe->x;
1530 info->momentum.y1 = pe->y;
1531 info->momentum.tx = pe->timestamp;
1532 info->momentum.ty = pe->timestamp;
1537 case EVAS_CALLBACK_MOUSE_UP:
1538 case EVAS_CALLBACK_MULTI_UP:
1539 /* IGNORE if line info was cleared, like long press, move */
1543 st->line_end.x = pe->x;
1544 st->line_end.y = pe->y;
1545 st->t_end = pe->timestamp;
1548 case EVAS_CALLBACK_MOUSE_MOVE:
1549 case EVAS_CALLBACK_MULTI_MOVE:
1550 /* IGNORE if line info was cleared, like long press, move */
1561 _line_data_reset(st);
1565 info->momentum.x2 = pe->x;
1566 info->momentum.y2 = pe->y;
1567 _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1568 st->t_st, st->t_st, pe->timestamp);
1576 * This function test for (n) line gesture.
1577 * @param obj The gesture-layer object.
1578 * @param pe The recent input event as stored in pe struct.
1579 * @param event_info Original input event pointer.
1580 * @param event_type Type of original input event.
1581 * @param g_type what Gesture we are testing.
1583 * @ingroup Elm_Gesture_Layer
1586 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1587 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1591 Widget_Data *wd = elm_widget_data_get(obj);
1593 Gesture_Info *gesture = wd->gesture[g_type];
1594 if (!gesture ) return;
1596 if((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1598 return; /* user left a finger on device, do NOT start */
1600 Line_Type *st = gesture->data;
1603 st = calloc(1, sizeof(Line_Type));
1607 Line_Data *line = NULL;
1608 Eina_List *list = st->list;
1609 unsigned int i, cnt = eina_list_count(list);
1612 { /* list is not empty, locate this device on list */
1613 line = (Line_Data *) eina_list_search_unsorted(st->list,
1614 compare_line_device, &pe->device);
1617 { /* Try to locate an empty-node */
1618 for (i = 0; i < cnt; i++)
1620 line = eina_list_nth(list, i);
1622 break; /* Found a free node */
1630 { /* List is empty or device not found, new line-struct on START only */
1631 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1632 (event_type == EVAS_CALLBACK_MULTI_DOWN))
1633 { /* Allocate new item on START */
1634 line = calloc(1, sizeof(Line_Data));
1635 _line_data_reset(line);
1636 list = eina_list_append(list, line);
1641 if (!line) /* This may happen on MOVE that comes before DOWN */
1642 return; /* No line-struct to work with, can't continue testing */
1645 if (_single_line_process(&st->info, line, pe)) /* update st with input */
1646 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1648 /* Get direction and magnitude of the line */
1650 get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1651 &line->line_length, &angle);
1653 /* These are used later to compare lines length */
1654 Evas_Coord shortest_line_len = line->line_length;
1655 Evas_Coord longest_line_len = line->line_length;
1656 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1658 /* Now update line-state */
1660 { /* Analyze line only if line started */
1661 if (line->line_angle >= 0.0)
1662 { /* if line direction was set, we test if broke tolerance */
1663 double a = fabs(angle - line->line_angle);
1665 double d = (tan(a)) * line->line_length; /* Distance from line */
1666 #if defined(DEBUG_GESTURE_LAYER)
1667 printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
1669 if((d > wd->line_tolerance) || (a > ELM_GESTURE_LINE_ANGLE_TOLERANCE))
1670 // if (a > ELM_GESTURE_LINE_ANGLE_TOLERANCE)
1671 { /* Broke tolerance: abort line and start a new one */
1672 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1673 &st->info, EINA_FALSE);
1674 consume_event(wd, event_info, event_type, ev_flag);
1679 { /* Record the line angle as it broke minimum length for line */
1680 if (line->line_length >= wd->line_min_length)
1681 st->info.angle = line->line_angle = angle;
1686 if (line->line_angle < 0.0)
1687 { /* it's not a line, too short more close to a tap */
1688 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1689 &st->info, EINA_FALSE);
1690 consume_event(wd, event_info, event_type, ev_flag);
1696 /* Count how many lines already started / ended */
1699 unsigned int tm_start = pe->timestamp;
1700 unsigned int tm_end = pe->timestamp;
1703 double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1704 Eina_Bool lines_parallel = EINA_TRUE;
1705 EINA_LIST_FOREACH(list, l, t_line)
1708 base_angle = t_line->line_angle;
1711 if (t_line->line_angle >= 0)
1712 { /* Compare angle only with lines with direction defined */
1713 if (fabs(base_angle - t_line->line_angle) >
1714 ELM_GESTURE_LINE_ANGLE_TOLERANCE)
1715 lines_parallel = EINA_FALSE;
1719 if (t_line->line_length)
1720 { /* update only if this line is used */
1721 if (shortest_line_len > t_line->line_length)
1722 shortest_line_len = t_line->line_length;
1724 if (longest_line_len < t_line->line_length)
1725 longest_line_len = t_line->line_length;
1731 if (t_line->t_st < tm_start)
1732 tm_start = t_line->t_st;
1738 if (t_line->t_end < tm_end)
1739 tm_end = t_line->t_end;
1743 st->info.n = started;
1747 ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1748 (event_type == EVAS_CALLBACK_MULTI_DOWN)))
1749 { /* user lift one finger then starts again without line-end - ABORT */
1750 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1752 consume_event(wd, event_info, event_type, ev_flag);
1756 if (!lines_parallel)
1757 { /* Lines are NOT at same direction, abort this gesture */
1758 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1760 consume_event(wd, event_info, event_type, ev_flag);
1765 /* We report ABORT if lines length are NOT matching when fingers are up */
1766 if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
1768 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1770 consume_event(wd, event_info, event_type, ev_flag);
1774 if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > FLICK_MAX_MS))
1775 { /* We consider FLICK as a fast line.ABORT if take too long to finish */
1776 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1778 consume_event(wd, event_info, event_type, ev_flag);
1784 case EVAS_CALLBACK_MOUSE_UP:
1785 case EVAS_CALLBACK_MULTI_UP:
1786 if ((started) && (started == ended))
1788 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
1789 &st->info, EINA_FALSE);
1790 consume_event(wd, event_info, event_type, ev_flag);
1795 case EVAS_CALLBACK_MOUSE_DOWN:
1796 case EVAS_CALLBACK_MULTI_DOWN:
1799 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1800 &st->info, EINA_TRUE);
1801 consume_event(wd, event_info, event_type, ev_flag);
1806 case EVAS_CALLBACK_MOUSE_MOVE:
1807 case EVAS_CALLBACK_MULTI_MOVE:
1810 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1811 &st->info, EINA_TRUE);
1812 consume_event(wd, event_info, event_type, ev_flag);
1818 return; /* Unhandeld event type */
1825 * This function is used to check if rotation gesture started.
1826 * @param st Contains current rotation values from user input.
1827 * @return TRUE/FALSE if we need to set rotation START.
1829 * @ingroup Elm_Gesture_Layer
1832 rotation_broke_tolerance(Rotate_Type *st)
1834 if (st->info.base_angle < 0)
1835 return EINA_FALSE; /* Angle has to be computed first */
1837 if (st->rotate_tolerance < 0)
1840 double low = st->info.base_angle - st->rotate_tolerance;
1841 double high = st->info.base_angle + st->rotate_tolerance;
1842 double t = st->info.angle;
1855 if (high > RAD_360DEG)
1866 #if defined(DEBUG_GESTURE_LAYER)
1867 printf("%s angle=<%d> low=<%d> high=<%d>\n", __func__, t, low, high);
1869 if ((t < low) || (t > high))
1870 { /* This marks that roation action has started */
1871 st->rotate_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
1872 st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
1882 * This function is used for computing the gap between fingers.
1883 * It returns the length and center point between fingers.
1885 * @param x1 first finger x location.
1886 * @param y1 first finger y location.
1887 * @param x2 second finger x location.
1888 * @param y2 second finger y location.
1889 * @param x Gets center point x cord (output)
1890 * @param y Gets center point y cord (output)
1892 * @return length of the line between (x1,y1), (x2,y2) in pixels.
1894 * @ingroup Elm_Gesture_Layer
1897 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
1898 Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
1900 double a, b, xx, yy, gap;
1903 gap = sqrt(xx*xx + yy*yy);
1905 /* START - Compute zoom center point */
1906 /* The triangle defined as follows:
1914 * http://en.wikipedia.org/wiki/Trigonometric_functions
1915 *************************************/
1916 if (((int) xx) && ((int) yy))
1918 double A = atan((yy / xx));
1919 #if defined(DEBUG_GESTURE_LAYER)
1920 printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
1922 a = (Evas_Coord) ((gap / 2) * sin(A));
1923 b = (Evas_Coord) ((gap / 2) * cos(A));
1924 *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
1925 *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
1930 { /* horiz line, take half width */
1931 #if defined(DEBUG_GESTURE_LAYER)
1932 printf("==== HORIZ ====\n");
1934 *x = (Evas_Coord) (xx / 2);
1935 *y = (Evas_Coord) (y1);
1939 { /* vert line, take half width */
1940 #if defined(DEBUG_GESTURE_LAYER)
1941 printf("==== VERT ====\n");
1943 *x = (Evas_Coord) (x1);
1944 *y = (Evas_Coord) (yy / 2);
1947 /* END - Compute zoom center point */
1949 return (Evas_Coord) gap;
1955 * This function is used for computing zoom value.
1957 * @param st Pointer to zoom data based on user input.
1958 * @param x1 first finger x location.
1959 * @param y1 first finger y location.
1960 * @param x2 second finger x location.
1961 * @param y2 second finger y location.
1962 * @param factor zoom-factor, used to determine how fast zoom works.
1964 * @return zoom value, when 1.0 means no zoom, 0.5 half size...
1966 * @ingroup Elm_Gesture_Layer
1968 /* FIXME change float to double */
1970 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
1971 Evas_Coord x2, Evas_Coord y2, unsigned int tm2, float factor)
1974 Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
1975 &st->info.x, &st->info.y);
1977 st->info.radius = diam / 2;
1981 st->zoom_base = diam;
1982 return st->info.zoom;
1985 if (st->zoom_tolerance)
1986 { /* zoom tolerance <> ZERO, means zoom action NOT started yet */
1987 if (diam < (st->zoom_base - st->zoom_tolerance))
1988 { /* avoid jump with zoom value when break tolerance */
1989 st->zoom_base -= st->zoom_tolerance;
1990 st->zoom_tolerance = 0;
1993 if (diam > (st->zoom_base + st->zoom_tolerance))
1994 { /* avoid jump with zoom value when break tolerance */
1995 st->zoom_base += st->zoom_tolerance;
1996 st->zoom_tolerance = 0;
2002 /* We use factor only on the difference between gap-base */
2003 /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2004 rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2005 (float) st->zoom_base) * factor));
2008 /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2009 st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2020 * This function handles zoom with mouse wheel.
2021 * thats a combination of wheel + CTRL key.
2022 * @param obj The gesture-layer object.
2023 * @param event_info Original input event pointer.
2024 * @param event_type Type of original input event.
2025 * @param g_type what Gesture we are testing.
2027 * @ingroup Elm_Gesture_Layer
2030 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2031 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2033 Widget_Data *wd = elm_widget_data_get(obj);
2035 if (!wd->gesture[g_type]) return;
2037 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2038 Zoom_Type *st = gesture_zoom->data;
2039 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2041 { /* Allocated once on first time, used for zoom intermediate data */
2042 st = calloc(1, sizeof(Zoom_Type));
2043 gesture_zoom->data = st;
2044 _zoom_test_reset(gesture_zoom);
2049 case EVAS_CALLBACK_KEY_UP:
2051 Evas_Event_Key_Up *p = event_info;
2052 if ((!strcmp(p->keyname, "Control_L")) ||
2053 (!strcmp(p->keyname, "Control_R")))
2054 { /* Test if we ended a zoom gesture when releasing CTRL */
2055 if ((st->zoom_wheel) &&
2056 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2057 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2058 { /* User released CTRL after zooming */
2059 ev_flag = _set_state(gesture_zoom,
2060 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2061 consume_event(wd, event_info, event_type, ev_flag);
2069 case EVAS_CALLBACK_MOUSE_WHEEL:
2072 Elm_Gesture_State s;
2073 if (!evas_key_modifier_is_set(
2074 ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2076 { /* if using wheel witout CTRL after starting zoom */
2077 if ((st->zoom_wheel) &&
2078 ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2079 (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2081 ev_flag = _set_state(gesture_zoom,
2082 ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2083 consume_event(wd, event_info, event_type, ev_flag);
2088 return; /* Ignore mouse-wheel without control */
2091 /* Using mouse wheel with CTRL for zoom */
2092 if (st->zoom_wheel || (st->zoom_tolerance == 0))
2093 { /* when (zoom_wheel == NULL) and (zoom_tolerance == 0)
2094 we continue a zoom gesture */
2096 s = ELM_GESTURE_STATE_MOVE;
2099 { /* On first wheel event, report START */
2101 s = ELM_GESTURE_STATE_START;
2104 st->zoom_tolerance = 0; /* Cancel tolerance */
2105 st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2106 st->info.x = st->zoom_wheel->canvas.x;
2107 st->info.y = st->zoom_wheel->canvas.y;
2109 if (st->zoom_wheel->z > 0) /* zoom in */
2110 st->info.zoom += (wd->factor * wd->zoom_wheel_factor);
2112 if (st->zoom_wheel->z < 0) /* zoom out */
2113 st->info.zoom -= (wd->factor * wd->zoom_wheel_factor);
2115 if (st->info.zoom < 0.0)
2116 st->info.zoom = 0.0;
2118 ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2119 consume_event(wd, event_info, event_type, ev_flag);
2131 * This function is used to test zoom gesture.
2132 * user may combine zoom, rotation together.
2133 * so its possible that both will be detected from input.
2134 * (both are two-finger movement-oriented gestures)
2136 * @param obj The gesture-layer object.
2137 * @param event_info Pointer to recent input event.
2138 * @param event_type Recent input event type.
2139 * @param g_type what Gesture we are testing.
2141 * @ingroup Elm_Gesture_Layer
2144 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info, Evas_Callback_Type event_type,
2145 Elm_Gesture_Types g_type)
2149 Widget_Data *wd = elm_widget_data_get(obj);
2151 if (!wd->gesture[g_type]) return;
2153 Gesture_Info *gesture_zoom = wd->gesture[g_type];
2154 Zoom_Type *st = gesture_zoom->data;
2157 { /* Allocated once on first time, used for zoom data */
2158 st = calloc(1, sizeof(Zoom_Type));
2159 gesture_zoom->data = st;
2160 _zoom_test_reset(gesture_zoom);
2163 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2166 case EVAS_CALLBACK_MOUSE_DOWN:
2167 consume_event(wd, event_info, event_type, ev_flag);
2168 memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2172 case EVAS_CALLBACK_MOUSE_MOVE:
2173 consume_event(wd, event_info, event_type, ev_flag);
2174 if (!st->zoom_st.timestamp)
2175 return; /* we got move event before down event.Ignore it */
2177 consume_event(wd, event_info, event_type, ev_flag);
2178 memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2180 /* We match this point to previous multi-move or multi-down event */
2181 if (st->zoom_mv1.timestamp)
2183 st->info.zoom = compute_zoom(st,
2184 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2185 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2190 if (st->zoom_st1.timestamp)
2192 st->info.zoom = compute_zoom(st,
2193 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2194 st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2201 case EVAS_CALLBACK_MULTI_MOVE:
2202 if (!st->zoom_st1.timestamp)
2203 return; /* We get move event before down event.Ignore it */
2205 consume_event(wd, event_info, event_type, ev_flag);
2206 if (st->zoom_mv1.timestamp)
2208 if (st->zoom_mv1.device !=
2209 ((Evas_Event_Multi_Move *) event_info)->device)
2210 { /* A third finger on screen, abort zoom */
2211 ev_flag = _set_state(gesture_zoom,
2212 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2213 consume_event(wd, event_info, event_type, ev_flag);
2219 memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2221 /* Match this point to previous mouse-move or mouse-down event */
2222 if (st->zoom_mv.timestamp)
2224 st->info.zoom = compute_zoom(st,
2225 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2226 st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2231 if (st->zoom_st.timestamp)
2233 st->info.zoom = compute_zoom(st,
2234 st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2235 st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2242 case EVAS_CALLBACK_MULTI_DOWN:
2243 consume_event(wd, event_info, event_type, ev_flag);
2244 memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2247 case EVAS_CALLBACK_MOUSE_UP:
2248 case EVAS_CALLBACK_MULTI_UP:
2249 /* Reset timestamp of finger-up.This is used later
2250 by _zoom_test_reset() to retain finger-down data */
2251 consume_event(wd, event_info, event_type, ev_flag);
2252 if(event_type == EVAS_CALLBACK_MOUSE_UP)
2253 st->zoom_st.timestamp = 0;
2255 if((event_type == EVAS_CALLBACK_MULTI_UP) &&
2256 (st->zoom_st1.device ==
2257 ((Evas_Event_Multi_Up *) event_info)->device))
2258 st->zoom_st1.timestamp = 0;
2260 if (((st->zoom_wheel) || (st->zoom_base)) &&
2261 (st->zoom_tolerance == 0))
2263 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2264 &st->info, EINA_FALSE);
2265 consume_event(wd, event_info, event_type, ev_flag);
2270 /* if we got here not a ZOOM */
2271 if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2272 { /* Must be != undefined, if gesture started */
2273 ev_flag = _set_state(gesture_zoom,
2274 ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2275 consume_event(wd, event_info, event_type, ev_flag);
2278 _zoom_test_reset(gesture_zoom);
2287 if (!st->zoom_tolerance)
2288 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2289 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2291 { /* Zoom broke tolerance, report move */
2292 double d = st->info.zoom - st->next_step;
2296 if(d >= wd->zoom_step)
2297 { /* Report move in steps */
2298 st->next_step = st->info.zoom;
2300 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2301 &st->info, EINA_TRUE);
2302 consume_event(wd, event_info, event_type, ev_flag);
2309 if((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2310 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2311 { /* report zoom start finger location is zoom-center temporarly */
2312 /* Zoom may have started with mouse-wheel, don't report START */
2313 if((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2314 { /* Set zoom-base after BOTH down events were recorded */
2315 /* Compute length of line between fingers on zoom start */
2316 st->info.zoom = 1.0;
2317 st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2318 st->zoom_st1.y, st->zoom_st.x, st->zoom_st.y,
2319 &st->info.x, &st->info.y);
2321 st->info.radius = st->zoom_base / 2;
2323 if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2324 (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2325 { /* Report START only when two fingers touching */
2326 ev_flag = _set_state(gesture_zoom,
2327 ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2328 consume_event(wd, event_info, event_type, ev_flag);
2337 _get_rotate_properties(Rotate_Type *st,
2338 Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2339 Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2342 st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2343 &st->info.x, &st->info.y) / 2;
2345 *angle = get_angle(x1, y1, x2, y2);
2346 #if 0 /* (NOT YET SUPPORTED) */
2347 if(angle == &st->info.angle)
2348 { /* Compute momentum: TODO: bug when breaking 0, 360 values */
2349 st->info.momentum = (((*angle) - st->info.base_angle) /
2350 (fabs(tm2 - tm1))) * 1000;
2353 st->info.momentum = 0;
2363 * This function is used to test rotation gesture.
2364 * user may combine zoom, rotation together.
2365 * so its possible that both will be detected from input.
2366 * (both are two-finger movement-oriented gestures)
2368 * @param obj The gesture-layer object.
2369 * @param event_info Pointer to recent input event.
2370 * @param event_type Recent input event type.
2371 * @param g_type what Gesture we are testing.
2373 * @ingroup Elm_Gesture_Layer
2376 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2377 Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2382 Widget_Data *wd = elm_widget_data_get(obj);
2384 if (!wd->gesture[g_type]) return;
2386 Gesture_Info *gesture = wd->gesture[g_type];
2387 Rotate_Type *st = gesture->data;
2392 { /* Allocated once on first time */
2393 st = calloc(1, sizeof(Rotate_Type));
2395 _rotate_test_reset(gesture);
2399 Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2403 case EVAS_CALLBACK_MOUSE_DOWN:
2404 consume_event(wd, event_info, event_type, ev_flag);
2405 memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2409 case EVAS_CALLBACK_MOUSE_MOVE:
2410 if (!st->rotate_st.timestamp)
2411 break; /* We got move event before down event.Ignore it */
2413 consume_event(wd, event_info, event_type, ev_flag);
2414 memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2416 /* Match this point to previous multi-move or multi-down event */
2417 if (st->rotate_mv1.timestamp)
2418 { /* Compute rotation angle and report to user */
2419 _get_rotate_properties(st,
2420 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2421 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2426 if (st->rotate_st1.timestamp)
2427 { /* Compute rotation angle and report to user */
2428 _get_rotate_properties(st,
2429 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2430 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2437 case EVAS_CALLBACK_MULTI_MOVE:
2438 if (!st->rotate_st1.timestamp)
2439 break; /* We got move event before down event.Ignore it */
2441 consume_event(wd, event_info, event_type, ev_flag);
2442 if (st->rotate_mv1.timestamp)
2444 if (st->rotate_mv1.device !=
2445 ((Evas_Event_Multi_Move *) event_info)->device)
2446 { /* A third finger on screen, abort rotate */
2447 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2448 &st->info, EINA_FALSE);
2449 consume_event(wd, event_info, event_type, ev_flag);
2455 memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2457 /* Match this point to previous mouse-move or mouse-down event */
2458 if (st->rotate_mv.timestamp)
2459 { /* Compute rotation angle and report to user */
2460 _get_rotate_properties(st,
2461 st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2462 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2467 if (st->rotate_st.timestamp)
2468 { /* Compute rotation angle and report to user */
2469 _get_rotate_properties(st,
2470 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2471 st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2478 case EVAS_CALLBACK_MULTI_DOWN:
2479 consume_event(wd, event_info, event_type, ev_flag);
2480 memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2481 _get_rotate_properties(st,
2482 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2483 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2487 case EVAS_CALLBACK_MOUSE_UP:
2488 case EVAS_CALLBACK_MULTI_UP:
2489 consume_event(wd, event_info, event_type, ev_flag);
2490 /* Reset timestamp of finger-up.This is used later
2491 by rotate_test_reset() to retain finger-down data */
2492 if(event_type == EVAS_CALLBACK_MOUSE_UP)
2493 st->rotate_st.timestamp = 0;
2495 if((event_type == EVAS_CALLBACK_MULTI_UP) &&
2496 (st->rotate_st1.device ==
2497 ((Evas_Event_Multi_Up *) event_info)->device))
2498 st->rotate_st1.timestamp = 0;
2500 if (st->rotate_tolerance < 0)
2502 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2503 &st->info, EINA_FALSE);
2504 consume_event(wd, event_info, event_type, ev_flag);
2509 if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2510 { /* Must be != undefined, if gesture started */
2511 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2512 &st->info, EINA_FALSE);
2513 consume_event(wd, event_info, event_type, ev_flag);
2516 _rotate_test_reset(gesture);
2523 if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2524 (event_type == EVAS_CALLBACK_MULTI_MOVE))
2525 { /* Report MOVE or ABORT for *MOVE event */
2526 if (rotation_broke_tolerance(st))
2527 { /* Rotation broke tolerance, report move */
2528 double d = st->info.angle - st->next_step;
2532 if(d >= wd->rotate_step)
2533 { /* Report move in steps */
2534 st->next_step = st->info.angle;
2536 ev_flag = _set_state(gesture,
2537 ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2538 consume_event(wd, event_info, event_type, ev_flag);
2545 if((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2546 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2548 if((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2549 { /* two-fingers on touch screen - report rotate start */
2550 /* Set base angle, then report start. */
2551 _get_rotate_properties(st,
2552 st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2553 st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2554 &st->info.base_angle);
2556 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2557 &st->info, EINA_FALSE);
2558 consume_event(wd, event_info, event_type, ev_flag);
2568 * This function is used to save input events in an abstract struct
2569 * to be used later by getsure-testing functions.
2571 * @param data The gesture-layer object.
2572 * @param event_info Pointer to recent input event.
2573 * @param event_type Recent input event type.
2574 * @param pe The abstract data-struct (output).
2576 * @ingroup Elm_Gesture_Layer
2579 _make_pointer_event(void *data, void *event_info,
2580 Evas_Callback_Type event_type, Pointer_Event *pe)
2582 Widget_Data *wd = elm_widget_data_get(data);
2583 if (!wd) return EINA_FALSE;
2587 case EVAS_CALLBACK_MOUSE_DOWN:
2588 pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2589 pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2590 pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2591 pe->device = ELM_MOUSE_DEVICE;
2594 case EVAS_CALLBACK_MOUSE_UP:
2595 pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2596 pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2597 pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2598 pe->device = ELM_MOUSE_DEVICE;
2601 case EVAS_CALLBACK_MOUSE_MOVE:
2602 pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2603 pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2604 pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2605 pe->device = ELM_MOUSE_DEVICE;
2608 case EVAS_CALLBACK_MULTI_DOWN:
2609 pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2610 pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2611 pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2612 pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2615 case EVAS_CALLBACK_MULTI_UP:
2616 pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2617 pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2618 pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2619 pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2622 case EVAS_CALLBACK_MULTI_MOVE:
2623 pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2624 pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2625 pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2626 pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2633 pe->event_type = event_type;
2640 * This function the core-function where input handling is done.
2641 * Here we get user input and stream it to gesture testing.
2642 * We notify user about any gestures with new state:
2644 * START - gesture started.
2645 * MOVE - gesture is ongoing.
2646 * END - gesture was completed.
2647 * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
2649 * We also check if a gesture was detected, then reset event history
2650 * If no gestures were found we reset gesture test flag
2651 * after streaming event-history to widget.
2652 * (stream to the widget all events not consumed as a gesture)
2654 * @param data The gesture-layer object.
2655 * @param event_info Pointer to recent input event.
2656 * @param event_type Recent input event type.
2658 * @ingroup Elm_Gesture_Layer
2661 _event_process(void *data, Evas_Object *obj __UNUSED__,
2662 void *event_info, Evas_Callback_Type event_type)
2665 Pointer_Event *pe = NULL;
2666 Widget_Data *wd = elm_widget_data_get(data);
2669 /* Start testing candidate gesture from here */
2670 if (_make_pointer_event(data, event_info, event_type, &_pe))
2673 if (IS_TESTED(ELM_GESTURE_N_TAPS))
2674 _dbl_click_test(data, pe, event_info, event_type,
2675 ELM_GESTURE_N_TAPS, 1);
2677 if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
2678 _dbl_click_test(data, pe, event_info, event_type,
2679 ELM_GESTURE_N_DOUBLE_TAPS, 2);
2681 if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
2682 _dbl_click_test(data, pe, event_info, event_type,
2683 ELM_GESTURE_N_TRIPLE_TAPS, 3);
2685 if (IS_TESTED(ELM_GESTURE_MOMENTUM))
2686 _momentum_test(data, pe, event_info, event_type,
2687 ELM_GESTURE_MOMENTUM);
2689 if (IS_TESTED(ELM_GESTURE_N_LINES))
2690 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
2692 if (IS_TESTED(ELM_GESTURE_N_FLICKS))
2693 _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
2695 if (IS_TESTED(ELM_GESTURE_ZOOM))
2696 _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
2698 if (IS_TESTED(ELM_GESTURE_ZOOM))
2699 _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
2701 if (IS_TESTED(ELM_GESTURE_ROTATE))
2702 _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
2704 if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
2705 _event_history_add(data, event_info, event_type);
2706 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2707 (event_type == EVAS_CALLBACK_MULTI_UP))
2709 Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
2712 consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
2713 _event_history_add(data, event_info, event_type);
2717 /* we maintain list of touched devices*/
2718 if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2719 (event_type == EVAS_CALLBACK_MULTI_DOWN))
2722 printf("%s touched=<%d>\n", __func__, wd->touched);
2724 else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2725 (event_type == EVAS_CALLBACK_MULTI_UP))
2728 printf("%s touched=<%d>\n", __func__, wd->touched);
2731 /* Report current states and clear history if needed */
2732 _clear_if_finished(data);
2737 * For all _mouse_* / multi_* functions wethen send this event to
2738 * _event_process function.
2740 * @param data The gesture-layer object.
2741 * @param event_info Pointer to recent input event.
2743 * @ingroup Elm_Gesture_Layer
2746 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2749 Widget_Data *wd = elm_widget_data_get(data);
2751 printf("---- %s ----\n", __func__);
2752 if (((Evas_Event_Mouse_Down *) event_info)->button != 1) /* We only process left-click at the moment */
2755 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
2759 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2762 Widget_Data *wd = elm_widget_data_get(data);
2765 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
2769 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2772 Widget_Data *wd = elm_widget_data_get(data);
2775 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
2779 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2782 Widget_Data *wd = elm_widget_data_get(data);
2785 _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
2789 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2792 Widget_Data *wd = elm_widget_data_get(data);
2795 printf("---- %s ----\n", __func__);
2796 if (((Evas_Event_Mouse_Up *) event_info)->button != 1) /* We only process left-click at the moment */
2799 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
2803 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2806 Widget_Data *wd = elm_widget_data_get(data);
2809 _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
2813 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2816 Widget_Data *wd = elm_widget_data_get(data);
2818 printf("---- %s ----\n", __func__);
2820 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
2824 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2827 Widget_Data *wd = elm_widget_data_get(data);
2830 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
2834 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2837 Widget_Data *wd = elm_widget_data_get(data);
2839 printf("---- %s ----\n", __func__);
2841 _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
2845 elm_gesture_layer_hold_events_get(Evas_Object *obj)
2847 Widget_Data *wd = elm_widget_data_get(obj);
2848 if (!wd) return EINA_FALSE;
2850 return !wd->repeat_events;
2854 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
2856 Widget_Data *wd = elm_widget_data_get(obj);
2859 wd->repeat_events = !r;
2863 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
2865 Widget_Data *wd = elm_widget_data_get(obj);
2875 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
2877 Widget_Data *wd = elm_widget_data_get(obj);
2883 wd->rotate_step = s;
2887 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
2889 Widget_Data *wd = elm_widget_data_get(obj);
2890 if (!wd) return EINA_FALSE;
2895 /* if was attached before, unregister callbacks first */
2897 _unregister_callbacks(obj);
2901 _register_callbacks(obj);
2906 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
2907 Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
2909 Widget_Data *wd = elm_widget_data_get(obj);
2912 if (!wd->gesture[idx])
2913 wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
2915 Gesture_Info *p = wd->gesture[idx];
2918 p->fn[cb_type].cb = cb;
2919 p->fn[cb_type].user_data = data;
2920 p->state = ELM_GESTURE_STATE_UNDEFINED;
2925 _disable_hook(Evas_Object *obj)
2927 if (elm_widget_disabled_get(obj))
2928 _unregister_callbacks(obj);
2930 _register_callbacks(obj);
2934 elm_gesture_layer_add(Evas_Object *parent)
2940 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2942 wd = ELM_NEW(Widget_Data);
2943 e = evas_object_evas_get(parent);
2944 if (!e) return NULL;
2945 obj = elm_widget_add(e);
2946 ELM_SET_WIDTYPE(widtype, "gesture_layer");
2947 elm_widget_type_set(obj, "gesture_layer");
2948 elm_widget_sub_object_add(parent, obj);
2949 elm_widget_data_set(obj, wd);
2950 elm_widget_del_hook_set(obj, _del_hook);
2951 elm_widget_disable_hook_set(obj, _disable_hook);
2954 wd->line_min_length = wd->zoom_tolerance = elm_finger_size_get();
2955 wd->line_tolerance = elm_finger_size_get() * 3;
2956 wd->factor = ELM_GESTURE_ZOOM_FACTOR;
2957 wd->zoom_wheel_factor = ELM_GESTURE_ZOOM_WHEEL_FACTOR ; /* mouse wheel zoom steps */
2958 wd->rotate_tolerance = ELM_GESTURE_ROTATION_TOLERANCE;
2959 wd->repeat_events = EINA_TRUE;
2961 #if defined(DEBUG_GESTURE_LAYER)
2962 printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
2964 memset(wd->gesture, 0, sizeof(wd->gesture));