Elm glayer: Added key grab for CTRL to finish zoom
[framework/uifw/elementary.git] / src / lib / elm_gesture_layer.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 /** @defgroup Elm_Gesture_Layer Gesture Layer */
4
5 /* Some defaults */
6 #define ELM_MOUSE_DEVICE 0
7 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
8 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
9 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
10 #define DBL_CLICK_TIME 400
11
12 /* Some Trigo values */
13 #define RAD_90DEG  M_PI_2
14 #define RAD_180DEG M_PI
15 #define RAD_270DEG (M_PI_2 * 3)
16 #define RAD_360DEG (M_PI * 2)
17
18 static void *
19 _glayer_bufdup(void *buf, size_t size)
20 {
21    void *p;
22    p = malloc(size);
23    memcpy(p, buf, size);
24    return p;
25 }
26 #define COPY_EVENT_INFO(EV) _glayer_bufdup(EV, sizeof(*EV))
27
28
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; \
31 } while (0)
32
33 #define IS_TESTED(T) ((wd->gesture[T]) ? wd->gesture[T]->test : EINA_FALSE)
34
35 /**
36  * @internal
37  *
38  * @struct _Func_Data
39  * Struct holds callback information.
40  *
41  * @ingroup Elm_Gesture_Layer
42  */
43 struct _Func_Data
44 {
45    void *user_data; /**< Holds user data to CB (like sd) */
46    Elm_Gesture_Event_Cb cb;
47 };
48
49 /**
50  * @internal
51  *
52  * @typedef Func_Data
53  * type for callback information
54  *
55  * @ingroup Elm_Gesture_Layer
56  */
57 typedef struct _Func_Data Func_Data;
58
59 /**
60  * @internal
61  *
62  * @struct _Gesture_Info
63  * Struct holds gesture info
64  *
65  * @ingroup Elm_Gesture_Layer
66  */
67 struct _Gesture_Info
68 {
69   Evas_Object *obj;
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 */
76 };
77
78 /**
79  * @internal
80  *
81  * @typedef Gesture_Info
82  * Type for _Gesture_Info
83  *
84  * @ingroup Elm_Gesture_Layer
85  */
86 typedef struct _Gesture_Info Gesture_Info;
87
88 /**
89  * @internal
90  *
91  * @struct _Event_History
92  * Struct holds event history.
93  * These events are repeated if no gesture found.
94  *
95  * @ingroup Elm_Gesture_Layer
96  */
97 struct _Event_History
98 {
99    EINA_INLIST;
100    void *event;
101    Evas_Callback_Type event_type;
102 };
103
104 /**
105  * @internal
106  *
107  * @typedef Event_History
108  * Type for _Event_History
109  *
110  * @ingroup Elm_Gesture_Layer
111  */
112 typedef struct _Event_History Event_History;
113
114 /**
115  * @internal
116  *
117  * @struct _Pointer_Event
118  * Struct holds pointer-event info
119  * This is a generic pointer event structure
120  *
121  * @ingroup Elm_Gesture_Layer
122  */
123 struct _Pointer_Event
124 {
125    Evas_Coord x, y;
126    unsigned int timestamp;
127    int device;
128    Evas_Callback_Type event_type;
129 };
130
131 /**
132  * @internal
133  *
134  * @typedef Pointer_Event
135  * Type for generic pointer event structure
136  *
137  * @ingroup Elm_Gesture_Layer
138  */
139 typedef struct _Pointer_Event Pointer_Event;
140
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() */
145 struct _Taps_Type
146 {
147    Elm_Gesture_Taps_Info info;
148    unsigned int count_ups;
149    unsigned int sum_x;
150    unsigned int sum_y;
151    unsigned int n_taps;
152    Eina_List *l;
153 };
154 typedef struct _Taps_Type Taps_Type;
155
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   */
164    int xdir, ydir;
165 };
166 typedef struct _Momentum_Type Momentum_Type;
167
168 struct _Line_Data
169 {
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   */
175    int device;
176    double line_angle;  /* Current angle of line */
177 };
178 typedef struct _Line_Data Line_Data;
179
180 struct _Line_Type
181 {  /* Fields used by _line_test() */
182    Elm_Gesture_Line_Info info;
183    Eina_List *list; /* List of Line_Data */
184 };
185 typedef struct _Line_Type Line_Type;
186
187 struct _Zoom_Type
188 {  /* Fields used by _zoom_test() */
189    Elm_Gesture_Zoom_Info info;
190    Pointer_Event zoom_st;
191    Pointer_Event zoom_mv;
192    Pointer_Event zoom_st1;
193    Pointer_Event zoom_mv1;
194    Evas_Event_Mouse_Wheel *zoom_wheel;
195    Evas_Coord zoom_base;  /* Holds gap between fingers on zoom-start  */
196    Evas_Coord zoom_distance_tolerance;
197    double next_step;
198 };
199 typedef struct _Zoom_Type Zoom_Type;
200
201 struct _Rotate_Type
202 {  /* Fields used by _rotation_test() */
203    Elm_Gesture_Rotate_Info info;
204    Pointer_Event rotate_st;
205    Pointer_Event rotate_mv;
206    Pointer_Event rotate_st1;
207    Pointer_Event rotate_mv1;
208    double rotate_angular_tolerance;
209    double next_step;
210 };
211 typedef struct _Rotate_Type Rotate_Type;
212
213 struct _Widget_Data
214 {
215    Evas_Object *target;  /* Target Widget */
216    Event_History *event_history_list;
217
218    int line_min_length;
219    Evas_Coord zoom_distance_tolerance;
220    Evas_Coord line_distance_tolerance;
221    double line_angular_tolerance;
222    double zoom_wheel_factor; /* mouse wheel zoom steps */
223    double zoom_finger_factor; /* used for zoom factor */
224    double rotate_angular_tolerance;
225    unsigned int flick_time_limit_ms;
226
227    double zoom_step;
228    double rotate_step;
229
230    Gesture_Info *gesture[ELM_GESTURE_LAST];
231    Ecore_Timer *dbl_timeout; /* When this expires, dbl click/taps ABORTed  */
232    Eina_List *pending; /* List of devices need to refeed *UP event */
233    Eina_List *touched;  /* Information  of touched devices   */
234
235    Eina_Bool repeat_events : 1;
236 };
237 typedef struct _Widget_Data Widget_Data;
238
239 static const char *widtype = NULL;
240 static void _del_hook(Evas_Object *obj);
241
242 static void _event_history_clear(Evas_Object *obj);
243 static void _reset_states(Widget_Data *wd);
244 static void _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
245 static void _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
246 static void _zoom_with_wheel_test(Evas_Object *obj, void *event_info, Evas_Callback_Type event_type, Elm_Gesture_Types g_type);
247 static void _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
248 static void _mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
249 static void _mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
250 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
251
252 static void _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
253 static void _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
254 static void _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info);
255
256 /* START - Functions to manage touched-device list */
257 /**
258  * @internal
259  * This function is used to find if device is touched
260  *
261  * @ingroup Elm_Gesture_Layer
262  */
263 static int
264 device_is_touched(const void *data1, const void *data2)
265 {  /* Compare the two device numbers */
266    return (((Pointer_Event *) data1)->device -((Pointer_Event *) data2)->device);
267 }
268
269 /**
270  * @internal
271  *
272  * Recoed Pointer Event in touched device list
273  * Note: This fuction allocates memory for PE event
274  * This memory is released in _remove_touched_device()
275  * @param list Pointer to touched device list.
276  * @param Pointer_Event Pointer to PE.
277  *
278  * @ingroup Elm_Gesture_Layer
279  */
280 static Eina_List *
281 _add_touched_device(Eina_List *list, Pointer_Event *pe)
282 {
283    if (eina_list_search_unsorted_list(list, device_is_touched, pe))
284      return list;
285
286    Pointer_Event *p = malloc(sizeof(Pointer_Event ));
287    memcpy(p, pe, sizeof(Pointer_Event)); /* Freed in _remove_touched_device() */
288    return eina_list_append(list, p);
289 }
290
291 /**
292  * @internal
293  *
294  * Remove Pointer Event from touched device list
295  * @param list Pointer to touched device list.
296  * @param Pointer_Event Pointer to PE.
297  *
298  * @ingroup Elm_Gesture_Layer
299  */
300 static Eina_List *
301 _remove_touched_device(Eina_List *list, Pointer_Event *pe)
302 {
303    Pointer_Event *p = eina_list_search_unsorted(list, device_is_touched, pe);
304    if (p)
305      {
306         free(p);
307         return eina_list_remove(list, p);
308      }
309
310    return list;
311 }
312 /* END   - Functions to manage touched-device list */
313
314 /**
315  * @internal
316  *
317  * Get event flag
318  * @param event_info pointer to event.
319  *
320  * @ingroup Elm_Gesture_Layer
321  */
322 static Evas_Event_Flags
323 _get_event_flag(void *event_info, Evas_Callback_Type event_type)
324 {
325    switch(event_type)
326      {
327       case EVAS_CALLBACK_MOUSE_IN:
328          return ((Evas_Event_Mouse_In *) event_info)->event_flags;
329       case EVAS_CALLBACK_MOUSE_OUT:
330          return ((Evas_Event_Mouse_Out *) event_info)->event_flags;
331       case EVAS_CALLBACK_MOUSE_DOWN:
332          return ((Evas_Event_Mouse_Down *) event_info)->event_flags;
333       case EVAS_CALLBACK_MOUSE_MOVE:
334          return ((Evas_Event_Mouse_Move *) event_info)->event_flags;
335       case EVAS_CALLBACK_MOUSE_UP:
336          return ((Evas_Event_Mouse_Up *) event_info)->event_flags;
337       case EVAS_CALLBACK_MOUSE_WHEEL:
338          return ((Evas_Event_Mouse_Wheel *) event_info)->event_flags;
339       case EVAS_CALLBACK_MULTI_DOWN:
340          return ((Evas_Event_Multi_Down *) event_info)->event_flags;
341       case EVAS_CALLBACK_MULTI_MOVE:
342          return ((Evas_Event_Multi_Move *) event_info)->event_flags;
343       case EVAS_CALLBACK_MULTI_UP:
344          return ((Evas_Event_Multi_Up *) event_info)->event_flags;
345       case EVAS_CALLBACK_KEY_DOWN:
346          return ((Evas_Event_Key_Down *) event_info)->event_flags;
347       case EVAS_CALLBACK_KEY_UP:
348          return ((Evas_Event_Key_Up *) event_info)->event_flags;
349       default:
350          return EVAS_EVENT_FLAG_NONE;
351      }
352 }
353
354 /**
355  * @internal
356  *
357  * Sets event flag to value returned from user callback
358  * @param wd Widget Data
359  * @param event_info pointer to event.
360  * @param event_type what type was ev (mouse down, etc...)
361  * @param ev_flags event flags
362  *
363  * @ingroup Elm_Gesture_Layer
364  */
365 static void
366 consume_event(Widget_Data *wd, void *event_info,
367       Evas_Callback_Type event_type, Evas_Event_Flags ev_flags)
368 {  /* Mark EVAS_EVENT_FLAG_ON_HOLD on events that are used by gesture layer */
369    /* ev_flags != EVAS_EVENT_FLAG_NONE means target used event and g-layer  */
370    /* should not refeed this event.                                         */
371    if ((ev_flags) || (!wd->repeat_events))
372      {
373         switch(event_type)
374           {
375            case EVAS_CALLBACK_MOUSE_DOWN:
376               ((Evas_Event_Mouse_Down *) event_info)->event_flags |= ev_flags;
377               break;
378            case EVAS_CALLBACK_MOUSE_MOVE:
379               ((Evas_Event_Mouse_Move *) event_info)->event_flags |= ev_flags;
380               break;
381            case EVAS_CALLBACK_MOUSE_UP:
382               ((Evas_Event_Mouse_Up *) event_info)->event_flags |= ev_flags;
383               break;
384            case EVAS_CALLBACK_MOUSE_WHEEL:
385               ((Evas_Event_Mouse_Wheel *) event_info)->event_flags |= ev_flags;
386               break;
387            case EVAS_CALLBACK_MULTI_DOWN:
388               ((Evas_Event_Multi_Down *) event_info)->event_flags |= ev_flags;
389               break;
390            case EVAS_CALLBACK_MULTI_MOVE:
391               ((Evas_Event_Multi_Move *) event_info)->event_flags |= ev_flags;
392               break;
393            case EVAS_CALLBACK_MULTI_UP:
394               ((Evas_Event_Multi_Up *) event_info)->event_flags |= ev_flags;
395               break;
396            case EVAS_CALLBACK_KEY_DOWN:
397               ((Evas_Event_Key_Down *) event_info)->event_flags |= ev_flags;
398               break;
399            case EVAS_CALLBACK_KEY_UP:
400               ((Evas_Event_Key_Up *) event_info)->event_flags |= ev_flags;
401               break;
402            default:
403               return;
404           }
405      }
406 }
407
408 /**
409  * @internal
410  *
411  * Report current state of a gesture by calling user callback.
412  * @param gesture what gesture state we report.
413  * @param info inforamtion for user callback
414  *
415  * @ingroup Elm_Gesture_Layer
416  */
417 static Evas_Event_Flags
418 _report_state(Gesture_Info *gesture, void *info)
419 {  /* We report current state (START, MOVE, END, ABORT), once */
420 #if defined(DEBUG_GESTURE_LAYER)
421    printf("%s reporting gesture=<%d> state=<%d>\n" , __func__, g_type,
422          gesture->state);
423 #endif
424    if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
425          (gesture->fn[gesture->state].cb))
426      {  /* Fill state-info struct and send ptr to user callback */
427         return gesture->fn[gesture->state].cb(
428               gesture->fn[gesture->state].user_data, info);
429      }
430
431    return EVAS_EVENT_FLAG_NONE;
432 }
433
434 /**
435  * @internal
436  *
437  * Update state for a given gesture.
438  * We may update gesture state to:
439  * UNDEFINED - current input did not start gesure yet.
440  * START - gesture started according to input.
441  * MOVE - gusture in progress.
442  * END - gesture completed according to input.
443  * ABORT - input does not matches gesure.
444  * note that we may move from UNDEFINED to ABORT
445  * because we may detect that gesture will not START
446  * with a given input.
447  *
448  * @param g given gesture to change state.
449  * @param s gesure new state.
450  * @param info buffer to be sent to user callback on report_state.
451  * @param force makes report_state to report the new-state even
452  * if its same as current state. Works for MOVE - gesture in progress.
453  *
454  * @ingroup Elm_Gesture_Layer
455  */
456 static Evas_Event_Flags
457 _set_state(Gesture_Info *g, Elm_Gesture_State s,
458       void *info, Eina_Bool force)
459 {
460    Elm_Gesture_State old_state;
461    if ((g->state == s) && (!force))
462      return EVAS_EVENT_FLAG_NONE;
463
464    old_state = g->state;
465
466    g->state = s;
467    g->info = info;  /* Information for user callback */
468    if ((g->state == ELM_GESTURE_STATE_ABORT) ||
469          (g->state == ELM_GESTURE_STATE_END))
470      g->test = EINA_FALSE;
471
472    if ((g->state != ELM_GESTURE_STATE_UNDEFINED) &&
473          (!((old_state == ELM_GESTURE_STATE_UNDEFINED) &&
474             (s == ELM_GESTURE_STATE_ABORT))))
475      return _report_state(g, g->info);
476
477    return EVAS_EVENT_FLAG_NONE;
478 }
479
480 /**
481  * @internal
482  *
483  * This resets all gesture states and sets test-bit.
484  * this is used for restarting gestures to listen to input.
485  * happens after we complete a gesture or no gesture was detected.
486  * @param wd Widget data of the gesture-layer object.
487  *
488  * @ingroup Elm_Gesture_Layer
489  */
490 static void
491 _reset_states(Widget_Data *wd)
492 {
493    int i;
494    Gesture_Info *p;
495    for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++)
496      {
497         p = wd->gesture[i];
498         if (p)
499           {
500              _set_state(p, ELM_GESTURE_STATE_UNDEFINED, NULL, EINA_FALSE);
501              SET_TEST_BIT(p);
502           }
503      }
504 }
505
506 /**
507  * @internal
508  *
509  * if gesture was NOT detected AND we only have gestures in ABORT state
510  * we clear history immediately to be ready for input.
511  *
512  * @param obj The gesture-layer object.
513  *
514  * @ingroup Elm_Gesture_Layer
515  */
516 static void
517 _clear_if_finished(Evas_Object *obj)
518 {
519    Widget_Data *wd = elm_widget_data_get(obj);
520    if (!wd) return;
521    int i;
522
523    /* Clear history if all we have aborted gestures */
524    Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE;
525    for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
526      {  /* If no gesture started and all we have aborted gestures, reset all */
527         Gesture_Info *p = wd->gesture[i];
528         if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED))
529           {
530              if ((p->state == ELM_GESTURE_STATE_START) ||
531                    (p->state == ELM_GESTURE_STATE_MOVE))
532                reset_s = EINA_FALSE;
533
534              all_undefined = EINA_FALSE;
535           }
536      }
537
538 //   if ((!wd->touched) || (reset_s && !all_undefined))
539    /* (!wd->touched && reset_s) - don't stop zoom with mouse-wheel */
540    if (reset_s && (!eina_list_count(wd->touched) || !all_undefined))
541      _event_history_clear(obj);
542 }
543
544 static Eina_Bool
545 _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
546 {
547    int w = elm_finger_size_get() >> 1; /* Finger size devided by 2 */
548    if (x1 < (x2 - w))
549      return EINA_FALSE;
550
551    if (x1 > (x2 + w))
552      return EINA_FALSE;
553
554    if (y1 < (y2 - w))
555      return EINA_FALSE;
556
557    if (y1 > (y2 + w))
558      return EINA_FALSE;
559
560    return EINA_TRUE;
561 }
562
563 /* All *test_reset() funcs are called to clear
564  * gesture intermediate data.
565  * This happens when we need to reset our tests.
566  * for example when gesture is detected or all ABORTed. */
567 static void
568 _dbl_click_test_reset(Gesture_Info *gesture)
569 {
570    if (!gesture)
571      return;
572
573    Widget_Data *wd = elm_widget_data_get(gesture->obj);
574    if (wd->dbl_timeout) ecore_timer_del(wd->dbl_timeout);
575    wd->dbl_timeout = NULL;
576    Eina_List *data;
577    Pointer_Event *pe;
578
579    if (!gesture->data)
580      return;
581
582    EINA_LIST_FREE(((Taps_Type *) gesture->data)->l, data)
583       EINA_LIST_FREE(data, pe)
584          free(pe);
585
586   memset(gesture->data, 0, sizeof(Taps_Type));
587 }
588
589 static void
590 _momentum_test_reset(Gesture_Info *gesture)
591 {
592    if (!gesture)
593      return;
594
595    if (!gesture->data)
596      return;
597
598    memset(gesture->data, 0, sizeof(Momentum_Type));
599 }
600
601 static void
602 _line_data_reset(Line_Data *st)
603 {
604    if (!st)
605      return;
606
607    memset(st, 0, sizeof(Line_Data));
608    st->line_angle = ELM_GESTURE_NEGATIVE_ANGLE;
609 }
610
611 static void
612 _line_test_reset(Gesture_Info *gesture)
613 {
614    if (!gesture)
615      return;
616
617    if (!gesture->data)
618      return;
619
620    Line_Type *st = gesture->data;
621    Eina_List *list = st->list;
622    Eina_List *l;
623    Line_Data *t_line;
624    EINA_LIST_FOREACH(list, l, t_line)
625       free(t_line);
626
627    eina_list_free(list);
628    st->list = NULL;
629 }
630
631 static void
632 _zoom_test_reset(Gesture_Info *gesture)
633 {
634    if (!gesture)
635      return;
636
637    if (!gesture->data)
638      return;
639
640    Widget_Data *wd = elm_widget_data_get(gesture->obj);
641    Zoom_Type *st = gesture->data;
642    Pointer_Event pe, pe1;
643    Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
644          evas_object_evas_get(wd->target), "Control");
645    evas_object_key_ungrab(wd->target, "Control_L", mask, 0);
646    evas_object_key_ungrab(wd->target, "Control_R", mask, 0);
647
648    pe.timestamp = pe1.timestamp = 0;
649
650    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
651             &st->zoom_st))
652      memcpy(&pe, &st->zoom_st, sizeof(Pointer_Event));
653
654    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
655             &st->zoom_st1))
656      memcpy(&pe1, &st->zoom_st1, sizeof(Pointer_Event));
657
658    memset(st, 0, sizeof(Zoom_Type));
659
660    /* If user released one finger only, restore down-info */
661    if (pe.timestamp && (!pe1.timestamp))
662      memcpy(&st->zoom_st, &pe, sizeof(Pointer_Event));
663
664    if (pe1.timestamp && (!pe.timestamp))
665      memcpy(&st->zoom_st1, &pe1, sizeof(Pointer_Event));
666
667    st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
668    st->info.zoom = 1.0;
669 }
670
671 static void
672 _rotate_test_reset(Gesture_Info *gesture)
673 {
674    if (!gesture)
675      return;
676
677    if (!gesture->data)
678      return;
679
680    Widget_Data *wd = elm_widget_data_get(gesture->obj);
681    Rotate_Type *st = gesture->data;
682    Pointer_Event pe, pe1;
683
684    pe.timestamp = pe1.timestamp = 0;
685
686    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
687             &st->rotate_st))
688      memcpy(&pe, &st->rotate_st, sizeof(Pointer_Event));
689
690    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
691             &st->rotate_st1))
692      memcpy(&pe1, &st->rotate_st1, sizeof(Pointer_Event));
693
694    memset(st, 0, sizeof(Rotate_Type));
695
696    /* If user released one finger only, restore down-info */
697    if (pe.timestamp && (!pe1.timestamp))
698      memcpy(&st->rotate_st, &pe, sizeof(Pointer_Event));
699
700    if (pe1.timestamp && (!pe.timestamp))
701      memcpy(&st->rotate_st1, &pe1, sizeof(Pointer_Event));
702
703
704    st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
705    st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
706 }
707
708
709 /**
710  * @internal
711  *
712  * We register callbacks when gesture layer is attached to an object
713  * or when its enabled after disable.
714  *
715  * @param obj The gesture-layer object.
716  *
717  * @ingroup Elm_Gesture_Layer
718  */
719 static void
720 _register_callbacks(Evas_Object *obj)
721 {
722    Widget_Data *wd = elm_widget_data_get(obj);
723    if (!wd) return;
724
725    if (wd->target)
726      {
727         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
728               _mouse_down, obj);
729         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
730               _mouse_move, obj);
731         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
732               _mouse_up, obj);
733
734         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
735               _mouse_wheel, obj);
736
737         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
738               _multi_down, obj);
739         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
740               _multi_move, obj);
741         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
742               _multi_up, obj);
743
744         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
745               _key_down_cb, obj);
746         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
747               _key_up_cb, obj);
748      }
749 }
750
751 /**
752  * @internal
753  *
754  * We unregister callbacks when gesture layer is disabled.
755  *
756  * @param obj The gesture-layer object.
757  *
758  * @ingroup Elm_Gesture_Layer
759  */
760 static void
761 _unregister_callbacks(Evas_Object *obj)
762 {
763    Widget_Data *wd = elm_widget_data_get(obj);
764    if (!wd) return;
765
766    if (wd->target)
767      {
768         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
769               _mouse_down);
770         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
771               _mouse_move);
772         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
773               _mouse_up);
774
775         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
776               _mouse_wheel);
777
778         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
779               _multi_down);
780
781         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
782               _multi_move);
783
784         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
785               _multi_up);
786
787         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
788               _key_down_cb);
789         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
790               _key_up_cb);
791      }
792 }
793
794 /* START - Event history list handling functions */
795 /**
796  * @internal
797  * This function is used to find if device number
798  * is found in a list of devices.
799  * The list contains devices for refeeding *UP event
800  *
801  * @ingroup Elm_Gesture_Layer
802  */
803 static int
804 device_in_pending_list(const void *data1, const void *data2)
805 {  /* Compare the two device numbers */
806    return (((int) data1) - ((int) data2));
807 }
808
809 /**
810  * @internal
811  *
812  * This functions adds device to refeed-pending device list
813  * @ingroup Elm_Gesture_Layer
814  */
815 static Eina_List *
816 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
817 {
818    int device = ELM_MOUSE_DEVICE;
819    switch(event_type)
820      {
821       case EVAS_CALLBACK_MOUSE_DOWN:
822          break;
823       case EVAS_CALLBACK_MULTI_DOWN:
824          device = ((Evas_Event_Multi_Down *) event)->device;
825          break;
826       default:
827          return list;
828      }
829
830    if (!eina_list_search_unsorted_list(list, device_in_pending_list,
831             (void *) device))
832      {
833         return eina_list_append(list, (void *) device);
834      }
835
836    return list;
837 }
838
839 /**
840  * @internal
841  *
842  * This functions returns pending-device node
843  * @ingroup Elm_Gesture_Layer
844  */
845 static Eina_List *
846 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
847 {
848    int device = ELM_MOUSE_DEVICE;
849    switch(event_type)
850      {
851       case EVAS_CALLBACK_MOUSE_UP:
852          break;
853       case EVAS_CALLBACK_MULTI_UP:
854          device = ((Evas_Event_Multi_Up *) event)->device;
855          break;
856       default:
857         return NULL;
858      }
859
860    return eina_list_search_unsorted_list(list, device_in_pending_list,
861          (void *) device);
862 }
863
864 /**
865  * @internal
866  *
867  * This function reports ABORT to all none-detected gestures
868  * Then resets test bits for all desired gesures
869  * and clears input-events history.
870  * note: if no gesture was detected, events from history list
871  * are streamed to the widget because it's unused by layer.
872  * user may cancel refeed of events by setting repeat events.
873  *
874  * @param obj The gesture-layer object.
875  *
876  * @ingroup Elm_Gesture_Layer
877  */
878 static void
879 _event_history_clear(Evas_Object *obj)
880 {
881    Widget_Data *wd = elm_widget_data_get(obj);
882    if (!wd) return;
883
884    int i;
885    Gesture_Info *p;
886    Evas *e = evas_object_evas_get(obj);
887    Eina_Bool gesture_found = EINA_FALSE;
888    for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
889      {
890         p = wd->gesture[i];
891         if (p)
892           {
893              if (p->state == ELM_GESTURE_STATE_END)
894                gesture_found = EINA_TRUE;
895              else
896                {  /* Report ABORT to all gestures that still not finished */
897                   _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
898                         EINA_FALSE);
899                }
900           }
901      }
902
903    _reset_states(wd); /* we are ready to start testing for gestures again */
904
905    /* Clear all gestures intermediate date */
906    _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
907    _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
908    _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
909    _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
910    _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
911    _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
912    _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
913    _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
914
915    /* Disable gesture layer so refeeded events won't be consumed by it */
916    _unregister_callbacks(obj);
917    while (wd->event_history_list)
918      {
919         Event_History *t;
920         t = wd->event_history_list;
921         Eina_List *pending = _device_is_pending(wd->pending,
922               wd->event_history_list->event,
923               wd->event_history_list->event_type);
924
925         /* Refeed events if no gesture matched input */
926         if (pending || ((!gesture_found) && (!wd->repeat_events)))
927           {
928              evas_event_refeed_event(e, wd->event_history_list->event,
929                    wd->event_history_list->event_type);
930
931              if (pending)
932                {
933                wd->pending = eina_list_remove_list(wd->pending, pending);
934                int device = ELM_MOUSE_DEVICE;
935                if (wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
936                  device = ((Evas_Event_Multi_Up *)
937                        (wd->event_history_list->event))->device;
938                }
939              else
940                wd->pending = _add_device_pending(wd->pending,
941                      wd->event_history_list->event,
942                      wd->event_history_list->event_type);
943           }
944
945         free(wd->event_history_list->event);
946         wd->event_history_list = (Event_History *) eina_inlist_remove(
947               EINA_INLIST_GET(wd->event_history_list),
948               EINA_INLIST_GET(wd->event_history_list));
949         free(t);
950      }
951    _register_callbacks(obj);
952 }
953
954 /**
955  * @internal
956  *
957  * This function copies input events.
958  * We copy event info before adding it to history.
959  * The memory is freed when we clear history.
960  *
961  * @param event the event to copy
962  * @param event_type event type to copy
963  *
964  * @ingroup Elm_Gesture_Layer
965  */
966 static void *
967 _copy_event_info(void *event, Evas_Callback_Type event_type)
968 {
969    switch(event_type)
970      {
971       case EVAS_CALLBACK_MOUSE_DOWN:
972          return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
973          break;
974       case EVAS_CALLBACK_MOUSE_MOVE:
975          return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
976          break;
977       case EVAS_CALLBACK_MOUSE_UP:
978          return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
979          break;
980       case EVAS_CALLBACK_MOUSE_WHEEL:
981          return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
982          break;
983       case EVAS_CALLBACK_MULTI_DOWN:
984          return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
985          break;
986       case EVAS_CALLBACK_MULTI_MOVE:
987          return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
988          break;
989       case EVAS_CALLBACK_MULTI_UP:
990          return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
991          break;
992       case EVAS_CALLBACK_KEY_DOWN:
993          return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
994          break;
995       case EVAS_CALLBACK_KEY_UP:
996          return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
997          break;
998       default:
999          return NULL;
1000      }
1001 }
1002
1003 static Eina_Bool
1004 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1005 {
1006    Widget_Data *wd = elm_widget_data_get(obj);
1007    Event_History *ev;
1008    if (!wd) return EINA_FALSE;
1009
1010    ev = malloc(sizeof(Event_History));
1011    ev->event = _copy_event_info(event, event_type);  /* Freed on event_history_clear */
1012    ev->event_type = event_type;
1013    wd->event_history_list = (Event_History *) eina_inlist_append(
1014          EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1015
1016    return EINA_TRUE;
1017 }
1018 /* END - Event history list handling functions */
1019
1020 static void
1021 _del_hook(Evas_Object *obj)
1022 {
1023    Widget_Data *wd = elm_widget_data_get(obj);
1024    if (!wd) return;
1025
1026    _event_history_clear(obj);
1027    eina_list_free(wd->pending);
1028
1029    Pointer_Event *data;
1030    EINA_LIST_FREE(wd->touched, data)
1031       free(data);
1032
1033    if (!elm_widget_disabled_get(obj))
1034      _unregister_callbacks(obj);
1035
1036    /* Free all gestures internal data structures */
1037    int i;
1038    for (i = 0; i < ELM_GESTURE_LAST; i++)
1039      if (wd->gesture[i])
1040        {
1041           if (wd->gesture[i]->data)
1042             free(wd->gesture[i]->data);
1043
1044           free(wd->gesture[i]);
1045        }
1046
1047    free(wd);
1048 }
1049
1050 static int
1051 compare_match_fingers(const void *data1, const void *data2)
1052 {  /* Compare coords of first item in list to cur coords */
1053    const Pointer_Event *pe1 = eina_list_data_get(data1);
1054    const Pointer_Event *pe2 = data2;
1055
1056    if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1057      return 0;
1058    else if (pe1->x < pe2->x)
1059      return -1;
1060    else
1061      {
1062         if (pe1->x == pe2->x)
1063           return pe1->y - pe2->y;
1064         else
1065           return 1;
1066      }
1067 }
1068
1069 static int
1070 compare_pe_device(const void *data1, const void *data2)
1071 {  /* Compare coords of first item in list to cur coords */
1072    const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1073    const Pointer_Event *pe2 = data2;
1074
1075    /* Only match if last was a down event */
1076    if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1077          (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1078      return 1;
1079
1080
1081    if (pe1->device == pe2->device)
1082      return 0;
1083    else if (pe1->device < pe2->device)
1084      return -1;
1085    else
1086      return 1;
1087 }
1088
1089 static Eina_List*
1090 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1091       Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1092 {  /* Keep copy of pe and record it in list */
1093    Pointer_Event *p = malloc(sizeof(Pointer_Event));
1094    memcpy(p, pe, sizeof(Pointer_Event));
1095    consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1096
1097    st->sum_x += pe->x;
1098    st->sum_y += pe->y;
1099    st->n_taps++;
1100
1101    /* This will also update middle-point to report to user later */
1102    st->info.x = st->sum_x / st->n_taps;
1103    st->info.y = st->sum_y / st->n_taps;
1104    st->info.timestamp = pe->timestamp;
1105
1106    if (!pe_list)
1107      {
1108         pe_list = eina_list_append(pe_list, p);
1109         st->l = eina_list_append(st->l, pe_list);
1110      }
1111    else
1112      pe_list = eina_list_append(pe_list, p);
1113
1114    return pe_list;
1115 }
1116
1117 /**
1118  * @internal
1119  *
1120  * when this timer expires we ABORT double click gesture.
1121  *
1122  * @param data The gesture-layer object.
1123  * @return cancles callback for this timer.
1124  *
1125  * @ingroup Elm_Gesture_Layer
1126  */
1127 static Eina_Bool
1128 _dbl_click_timeout(void *data)
1129 {
1130    Gesture_Info *gesture = data;
1131    Widget_Data *wd = elm_widget_data_get(gesture->obj);
1132
1133    wd->dbl_timeout = NULL;
1134    _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1135          gesture->info, EINA_FALSE);
1136
1137    _dbl_click_test_reset(gesture);
1138    _clear_if_finished(gesture->obj);
1139    return ECORE_CALLBACK_CANCEL;
1140 }
1141
1142 /**
1143  * @internal
1144  *
1145  * This function checks all click/tap and double/triple taps
1146  *
1147  * @param obj The gesture-layer object.
1148  * @param pe The recent input event as stored in pe struct.
1149  * @param event_info Original input event pointer.
1150  * @param event_type Type of original input event.
1151  * @param g_type what Gesture we are testing.
1152  * @param taps How many click/taps we test for.
1153  *
1154  * @ingroup Elm_Gesture_Layer
1155  */
1156 static void
1157 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
1158       void *event_info, Evas_Callback_Type event_type,
1159       Elm_Gesture_Types g_type, int taps)
1160 {  /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1161    Widget_Data *wd = elm_widget_data_get(obj);
1162    if (!wd) return;
1163
1164    if (!pe)   /* this happens when unhandled event arrived */
1165      return; /* see _make_pointer_event function */
1166
1167    Gesture_Info *gesture = wd->gesture[g_type];
1168    if (!gesture ) return;
1169
1170    if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1171          eina_list_count(wd->touched))
1172      return; /* user left a finger on device, do NOT start */
1173
1174    Taps_Type *st = gesture->data;
1175    if (!st)
1176      {  /* Allocated once on first time */
1177         st = calloc(1, sizeof(Taps_Type));
1178         gesture->data = st;
1179         _dbl_click_test_reset(gesture);
1180      }
1181
1182    Eina_List *pe_list = NULL;
1183    Pointer_Event *pe_down = NULL;
1184    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1185    switch (pe->event_type)
1186      {
1187       case EVAS_CALLBACK_MULTI_DOWN:
1188       case EVAS_CALLBACK_MOUSE_DOWN:
1189          pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1190          pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1191          if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1192            {  /* This is the first mouse down we got */
1193               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1194                     &st->info, EINA_FALSE);
1195               consume_event(wd, event_info, event_type, ev_flag);
1196
1197               /* To test dbl_click/dbl_tap */
1198               /* When this timer expires, gesture ABORTed if not completed */
1199               if (!wd->dbl_timeout && (taps > 1))
1200                 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
1201                       gesture);
1202
1203               return;
1204            }
1205
1206          break;
1207       case EVAS_CALLBACK_MULTI_UP:
1208       case EVAS_CALLBACK_MOUSE_UP:
1209          pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1210          if (!pe_list)
1211            return;  /* Got only first mouse_down and mouse_up */
1212
1213          pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1214
1215          if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
1216            return;  /* Got only first mouse_down and mouse_up */
1217
1218          /* Get first event in first list, this has to be Mouse Down event */
1219          pe_down = eina_list_data_get(pe_list);
1220
1221          if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1222            {
1223               st->count_ups++;
1224            }
1225          else
1226            {
1227               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1228                     &st->info, EINA_FALSE);
1229               consume_event(wd, event_info, event_type, ev_flag);
1230               break;
1231            }
1232
1233          if (st->count_ups == eina_list_count(st->l))
1234            {
1235               /* Abort if we found a single click */
1236               if ((taps == 1) && (st->count_ups == 1))
1237                 {
1238                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1239                          &st->info, EINA_FALSE);
1240                    consume_event(wd, event_info, event_type, ev_flag);
1241                    break;
1242                 }
1243               st->info.n = st->count_ups;
1244               ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1245                     &st->info, EINA_FALSE);
1246               consume_event(wd, event_info, event_type, ev_flag);
1247
1248               return;
1249            }
1250
1251          break;
1252
1253       case EVAS_CALLBACK_MULTI_MOVE:
1254       case EVAS_CALLBACK_MOUSE_MOVE:
1255          /* Get first event in first list, this has to be a Mouse Down event  */
1256          /* and verify that user didn't move out of this area before next tap */
1257          pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1258          if (pe_list)
1259            {
1260               pe_down = eina_list_data_get(pe_list);
1261               if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1262                 {
1263                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1264                       &st->info, EINA_FALSE);
1265                 consume_event(wd, event_info, event_type, ev_flag);
1266                 }
1267            }
1268          break;
1269
1270       default:
1271          return;
1272      }
1273 }
1274
1275 /**
1276  * @internal
1277  *
1278  * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1279  * This momentum value will be sent to widget when gesture is completed.
1280  *
1281  * @param momentum pointer to buffer where we record momentum value.
1282  * @param x1 x coord where user started gesture.
1283  * @param y1 y coord where user started gesture.
1284  * @param x2 x coord where user completed gesture.
1285  * @param y2 y coord where user completed gesture.
1286  * @param t1x timestamp for X, when user started gesture.
1287  * @param t1y timestamp for Y, when user started gesture.
1288  * @param t2  timestamp when user completed gesture.
1289  *
1290  * @ingroup Elm_Gesture_Layer
1291  */
1292 static void
1293 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1294       Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1295       unsigned int t2)
1296 {
1297    Evas_Coord velx = 0, vely = 0, vel;
1298    Evas_Coord dx = x2 - x1;
1299    Evas_Coord dy = y2 - y1;
1300    int dtx = t2 - t1x;
1301    int dty = t2 - t1y;
1302    if (dtx > 0)
1303      velx = (dx * 1000) / dtx;
1304
1305    if (dty > 0)
1306      vely = (dy * 1000) / dty;
1307
1308    vel = sqrt((velx * velx) + (vely * vely));
1309
1310    if ((_elm_config->thumbscroll_friction > 0.0) &&
1311          (vel > _elm_config->thumbscroll_momentum_threshold))
1312      {  /* report momentum */
1313         momentum->mx = velx;
1314         momentum->my = vely;
1315      }
1316    else
1317      {
1318         momentum->mx = 0;
1319         momentum->my = 0;
1320      }
1321 }
1322
1323 /**
1324  * @internal
1325  *
1326  * This function is used for computing rotation angle (DEG).
1327  *
1328  * @param x1 first finger x location.
1329  * @param y1 first finger y location.
1330  * @param x2 second finger x location.
1331  * @param y2 second finger y location.
1332  *
1333  * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1334  *
1335  * @ingroup Elm_Gesture_Layer
1336  */
1337 static double
1338 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1339 {
1340    double a, xx, yy;
1341    xx = fabs(x2 - x1);
1342    yy = fabs(y2 - y1);
1343
1344    if (((int) xx) && ((int) yy))
1345      {
1346         a = atan(yy / xx);
1347         if (x1 < x2)
1348           {
1349              if (y1 < y2)
1350                {
1351                   return RAD_360DEG - a;
1352                }
1353              else
1354                {
1355                   return (a);
1356                }
1357           }
1358         else
1359           {
1360              if (y1 < y2)
1361                {
1362                   return RAD_180DEG + a;
1363                }
1364              else
1365                {
1366                   return RAD_180DEG - a;
1367                }
1368           }
1369      }
1370
1371    if (((int) xx))
1372      {  /* Horizontal line */
1373         if (x2 < x1)
1374           {
1375              return RAD_180DEG;
1376           }
1377         else
1378           {
1379              return 0.0;
1380           }
1381      }
1382
1383    /* Vertical line */
1384    if (y2 < y1)
1385      {
1386         return RAD_90DEG;
1387      }
1388    else
1389      {
1390         return RAD_270DEG;
1391      }
1392 }
1393
1394 /**
1395  * @internal
1396  *
1397  * This function is used for computing the magnitude and direction
1398  * of vector between two points.
1399  *
1400  * @param x1 first finger x location.
1401  * @param y1 first finger y location.
1402  * @param x2 second finger x location.
1403  * @param y2 second finger y location.
1404  * @param l length computed (output)
1405  * @param a angle computed (output)
1406  *
1407  * @ingroup Elm_Gesture_Layer
1408  */
1409 static void
1410 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1411       Evas_Coord *l, double *a)
1412 {
1413    Evas_Coord xx, yy;
1414    xx = x2 - x1;
1415    yy = y2 - y1;
1416    *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1417    *a = get_angle(x1, y1, x2, y2);
1418 }
1419
1420 static int
1421 _get_direction(Evas_Coord x1, Evas_Coord x2)
1422 {
1423    if (x1 == x2)
1424      return 0;
1425    else if (x2 < x1)
1426      return -1;
1427    else
1428      return 1;
1429 }
1430
1431 /**
1432  * @internal
1433  *
1434  * This function tests momentum gesture.
1435  * @param obj The gesture-layer object.
1436  * @param pe The recent input event as stored in pe struct.
1437  * @param event_info recent input event.
1438  * @param event_type recent event type.
1439  * @param g_type what Gesture we are testing.
1440  *
1441  * @ingroup Elm_Gesture_Layer
1442  */
1443 static void
1444 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1445       void *event_info, Evas_Callback_Type event_type,
1446       Elm_Gesture_Types g_type)
1447 {
1448    Widget_Data *wd = elm_widget_data_get(obj);
1449    if (!wd) return;
1450    Gesture_Info *gesture = wd->gesture[g_type];
1451    if (!gesture ) return;
1452
1453    if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1454          eina_list_count(wd->touched))
1455      return; /* user left a finger on device, do NOT start */
1456
1457    Momentum_Type *st = gesture->data;
1458    if (!st)
1459      {  /* Allocated once on first time */
1460         st = calloc(1, sizeof(Momentum_Type));
1461         gesture->data = st;
1462         _momentum_test_reset(gesture);
1463      }
1464
1465    if (!pe)
1466      return;
1467
1468    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1469    switch (pe->event_type)
1470      {
1471       case EVAS_CALLBACK_MOUSE_DOWN:
1472          st->line_st.x = st->line_end.x = pe->x;
1473          st->line_st.y = st->line_end.y = pe->y;
1474          st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1475          st->xdir = st->ydir = 0;
1476          st->info.x2 = st->info.x1 = pe->x;
1477          st->info.y2 = st->info.y1 = pe->y;
1478          st->info.tx = st->info.ty = pe->timestamp;
1479          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1480                &st->info, EINA_FALSE);
1481          consume_event(wd, event_info, event_type, ev_flag);
1482          break;
1483
1484       case EVAS_CALLBACK_MOUSE_UP:
1485          /* IGNORE if line info was cleared, like long press, move */
1486          if (!st->t_st_x)
1487            return;
1488
1489          if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1490            {
1491               /* Too long of a wait, reset all values */
1492               st->line_st.x = pe->x;
1493               st->line_st.y = pe->y;
1494               st->t_st_y = st->t_st_x = pe->timestamp;
1495               st->xdir = st->ydir = 0;
1496            }
1497
1498          st->info.x2 = pe->x;
1499          st->info.y2 = pe->y;
1500          st->line_end.x = pe->x;
1501          st->line_end.y = pe->y;
1502          st->t_end = pe->timestamp;
1503
1504          _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1505                st->t_st_x, st->t_st_y, pe->timestamp);
1506
1507          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1508                EINA_FALSE);
1509          consume_event(wd, event_info, event_type, ev_flag);
1510
1511          return;
1512
1513       case EVAS_CALLBACK_MOUSE_MOVE:
1514          /* IGNORE if line info was cleared, like long press, move */
1515          if (!st->t_st_x)
1516            return;
1517
1518          if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1519            {
1520               /* Too long of a wait, reset all values */
1521               st->line_st.x = pe->x;
1522               st->line_st.y = pe->y;
1523               st->t_st_y = st->t_st_x = pe->timestamp;
1524               st->info.tx = st->t_st_x;
1525               st->info.ty = st->t_st_y;
1526               st->xdir = st->ydir = 0;
1527            }
1528          else
1529            {
1530               int xdir, ydir;
1531               xdir = _get_direction(st->line_end.x, pe->x);
1532               ydir = _get_direction(st->line_end.y, pe->y);
1533               if (!xdir || (xdir == (-st->xdir)))
1534                 {
1535                    st->line_st.x = st->line_end.x;
1536                    st->info.tx = st->t_st_x = st->t_end;
1537                    st->xdir = xdir;
1538                 }
1539
1540               if (!ydir || (ydir == (-st->ydir)))
1541                 {
1542                    st->line_st.y = st->line_end.y;
1543                    st->info.ty = st->t_st_y = st->t_end;
1544                    st->ydir = ydir;
1545                 }
1546            }
1547
1548          st->info.x2 = st->line_end.x = pe->x;
1549          st->info.y2 = st->line_end.y = pe->y;
1550          st->t_end = pe->timestamp;
1551          _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1552                st->t_st_x, st->t_st_y, pe->timestamp);
1553          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE, &st->info,
1554                EINA_TRUE);
1555          consume_event(wd, event_info, event_type, ev_flag);
1556          break;
1557
1558       case EVAS_CALLBACK_MULTI_UP:
1559          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1560                EINA_FALSE);
1561          consume_event(wd, event_info, event_type, ev_flag);
1562          return;
1563
1564       default:
1565          return;
1566      }
1567 }
1568
1569 static int
1570 compare_line_device(const void *data1, const void *data2)
1571 {  /* Compare device component of line struct */
1572    const Line_Data *ln1 = data1;
1573    const int *device = data2;
1574
1575    if (ln1->t_st) /* Compare only with lines that started */
1576      return (ln1->device - (*device));
1577
1578    return (-1);
1579 }
1580
1581 /**
1582  * @internal
1583  *
1584  * This function construct line struct from input.
1585  * @param info pointer to store line momentum.
1586  * @param st line info to store input data.
1587  * @param pe The recent input event as stored in pe struct.
1588  *
1589  * @ingroup Elm_Gesture_Layer
1590  */
1591 static Eina_Bool
1592 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1593       Pointer_Event *pe)
1594 {  /* Record events and set momentum for line pointed by st */
1595    if (!pe)
1596      return EINA_FALSE;
1597
1598    switch (pe->event_type)
1599      {
1600       case EVAS_CALLBACK_MOUSE_DOWN:
1601       case EVAS_CALLBACK_MULTI_DOWN:
1602          st->line_st.x = pe->x;
1603          st->line_st.y = pe->y;
1604          st->t_st = pe->timestamp;
1605          st->device = pe->device;
1606          info->momentum.x1 = pe->x;
1607          info->momentum.y1 = pe->y;
1608          info->momentum.tx = pe->timestamp;
1609          info->momentum.ty = pe->timestamp;
1610
1611          return EINA_TRUE;
1612          break;
1613
1614       case EVAS_CALLBACK_MOUSE_UP:
1615       case EVAS_CALLBACK_MULTI_UP:
1616          /* IGNORE if line info was cleared, like long press, move */
1617          if (!st->t_st)
1618            return EINA_FALSE;
1619
1620          st->line_end.x = pe->x;
1621          st->line_end.y = pe->y;
1622          st->t_end = pe->timestamp;
1623          break;
1624
1625       case EVAS_CALLBACK_MOUSE_MOVE:
1626       case EVAS_CALLBACK_MULTI_MOVE:
1627          /* IGNORE if line info was cleared, like long press, move */
1628          if (!st->t_st)
1629            return EINA_FALSE;
1630
1631          break;
1632       default:
1633          return EINA_FALSE;
1634      }
1635
1636    if (!st->t_st)
1637      {
1638         _line_data_reset(st);
1639         return EINA_FALSE;
1640      }
1641
1642    info->momentum.x2 = pe->x;
1643    info->momentum.y2 = pe->y;
1644    _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1645          st->t_st, st->t_st, pe->timestamp);
1646
1647    return EINA_TRUE;
1648 }
1649
1650 /**
1651  * @internal
1652  *
1653  * This function test for (n) line gesture.
1654  * @param obj The gesture-layer object.
1655  * @param pe The recent input event as stored in pe struct.
1656  * @param event_info Original input event pointer.
1657  * @param event_type Type of original input event.
1658  * @param g_type what Gesture we are testing.
1659  *
1660  * @ingroup Elm_Gesture_Layer
1661  */
1662 static void
1663 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1664       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1665 {
1666    if (!pe)
1667      return;
1668    Widget_Data *wd = elm_widget_data_get(obj);
1669    if (!wd) return;
1670    Gesture_Info *gesture = wd->gesture[g_type];
1671    if (!gesture ) return;
1672
1673    if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1674          eina_list_count(wd->touched))
1675      return; /* user left a finger on device, do NOT start */
1676
1677    Line_Type *st = gesture->data;
1678    if (!st)
1679      {
1680         st = calloc(1, sizeof(Line_Type));
1681         gesture->data = st;
1682      }
1683
1684    Line_Data *line = NULL;
1685    Eina_List *list = st->list;
1686    unsigned int i, cnt = eina_list_count(list);
1687
1688    if (cnt)
1689      {  /* list is not empty, locate this device on list */
1690         line = (Line_Data *) eina_list_search_unsorted(st->list,
1691               compare_line_device, &pe->device);
1692
1693         if (!line)
1694           {  /* Try to locate an empty-node */
1695              for (i = 0; i < cnt; i++)
1696                {
1697                   line = eina_list_nth(list, i);
1698                   if (!line->t_st)
1699                     break; /* Found a free node */
1700
1701                   line = NULL;
1702                }
1703           }
1704      }
1705
1706    if (!line)
1707      {  /* List is empty or device not found, new line-struct on START only */
1708         if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1709               (event_type == EVAS_CALLBACK_MULTI_DOWN))
1710           {  /* Allocate new item on START */
1711              line = calloc(1, sizeof(Line_Data));
1712              _line_data_reset(line);
1713              list = eina_list_append(list, line);
1714              st->list = list;
1715           }
1716      }
1717
1718    if (!line)  /* This may happen on MOVE that comes before DOWN      */
1719      return;   /* No line-struct to work with, can't continue testing */
1720
1721
1722    if (_single_line_process(&st->info, line, pe)) /* update st with input */
1723      consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1724
1725    /* Get direction and magnitude of the line */
1726    double angle;
1727    get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1728          &line->line_length, &angle);
1729
1730    /* These are used later to compare lines length */
1731    Evas_Coord shortest_line_len = line->line_length;
1732    Evas_Coord longest_line_len = line->line_length;
1733    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1734
1735    /* Now update line-state */
1736    if (line->t_st)
1737      {  /* Analyze line only if line started */
1738         if (line->line_angle >= 0.0)
1739           {  /* if line direction was set, we test if broke tolerance */
1740              double a = fabs(angle - line->line_angle);
1741
1742              double d = (tan(a)) * line->line_length; /* Distance from line */
1743 #if defined(DEBUG_GESTURE_LAYER)
1744              printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
1745 #endif
1746              if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
1747                {  /* Broke tolerance: abort line and start a new one */
1748                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1749                         &st->info, EINA_FALSE);
1750                   consume_event(wd, event_info, event_type, ev_flag);
1751                   return;
1752                }
1753           }
1754         else
1755           {  /* Record the line angle as it broke minimum length for line */
1756              if (line->line_length >= wd->line_min_length)
1757                st->info.angle = line->line_angle = angle;
1758           }
1759
1760         if (line->t_end)
1761           {
1762              if (line->line_angle < 0.0)
1763                { /* it's not a line, too short more close to a tap */
1764                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1765                         &st->info, EINA_FALSE);
1766                   consume_event(wd, event_info, event_type, ev_flag);
1767                   return;
1768                }
1769           }
1770      }
1771
1772    /* Count how many lines already started / ended */
1773    int started = 0;
1774    int ended = 0;
1775    unsigned int tm_start = pe->timestamp;
1776    unsigned int tm_end = pe->timestamp;
1777    Eina_List *l;
1778    Line_Data *t_line;
1779    double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1780    Eina_Bool lines_parallel = EINA_TRUE;
1781    EINA_LIST_FOREACH(list, l, t_line)
1782      {
1783         if (base_angle < 0)
1784           base_angle = t_line->line_angle;
1785         else
1786           {
1787              if (t_line->line_angle >= 0)
1788                {  /* Compare angle only with lines with direction defined */
1789                   if (fabs(base_angle - t_line->line_angle) >
1790                         wd->line_angular_tolerance)
1791                     lines_parallel = EINA_FALSE;
1792                }
1793           }
1794
1795         if (t_line->line_length)
1796           {  /* update only if this line is used */
1797              if (shortest_line_len > t_line->line_length)
1798                shortest_line_len = t_line->line_length;
1799
1800              if (longest_line_len < t_line->line_length)
1801                longest_line_len = t_line->line_length;
1802           }
1803
1804         if (t_line->t_st)
1805           {
1806              started++;
1807              if (t_line->t_st < tm_start)
1808                tm_start = t_line->t_st;
1809           }
1810
1811         if (t_line->t_end)
1812           {
1813              ended++;
1814              if (t_line->t_end < tm_end)
1815                tm_end = t_line->t_end;
1816           }
1817      }
1818
1819    st->info.n = started;
1820
1821
1822    if (ended &&
1823          ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1824           (event_type == EVAS_CALLBACK_MULTI_DOWN)))
1825      {  /* user lift one finger then starts again without line-end - ABORT */
1826         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1827               EINA_FALSE);
1828         consume_event(wd, event_info, event_type, ev_flag);
1829         return;
1830      }
1831
1832    if (!lines_parallel)
1833      { /* Lines are NOT at same direction, abort this gesture */
1834         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1835               EINA_FALSE);
1836         consume_event(wd, event_info, event_type, ev_flag);
1837         return;
1838      }
1839
1840
1841    /* We report ABORT if lines length are NOT matching when fingers are up */
1842    if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
1843      {
1844         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1845               EINA_FALSE);
1846         consume_event(wd, event_info, event_type, ev_flag);
1847         return;
1848      }
1849
1850    if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
1851      {  /* We consider FLICK as a fast line.ABORT if take too long to finish */
1852         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1853               EINA_FALSE);
1854         consume_event(wd, event_info, event_type, ev_flag);
1855         return;
1856      }
1857
1858    switch (event_type)
1859      {
1860       case EVAS_CALLBACK_MOUSE_UP:
1861       case EVAS_CALLBACK_MULTI_UP:
1862          if ((started) && (started == ended))
1863            {
1864               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
1865                     &st->info, EINA_FALSE);
1866               consume_event(wd, event_info, event_type, ev_flag);
1867            }
1868
1869          return;
1870
1871       case EVAS_CALLBACK_MOUSE_DOWN:
1872       case EVAS_CALLBACK_MULTI_DOWN:
1873          if (started)
1874            {
1875               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1876                     &st->info, EINA_TRUE);
1877               consume_event(wd, event_info, event_type, ev_flag);
1878            }
1879
1880          break;
1881
1882       case EVAS_CALLBACK_MOUSE_MOVE:
1883       case EVAS_CALLBACK_MULTI_MOVE:
1884          if (started)
1885            {
1886               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1887                  &st->info, EINA_TRUE);
1888               consume_event(wd, event_info, event_type, ev_flag);
1889            }
1890
1891          break;
1892
1893       default:
1894          return;  /* Unhandeld event type */
1895      }
1896 }
1897
1898 /**
1899  * @internal
1900  *
1901  * This function is used to check if rotation gesture started.
1902  * @param st Contains current rotation values from user input.
1903  * @return TRUE/FALSE if we need to set rotation START.
1904  *
1905  * @ingroup Elm_Gesture_Layer
1906  */
1907 static Eina_Bool
1908 rotation_broke_tolerance(Rotate_Type *st)
1909 {
1910    if (st->info.base_angle < 0)
1911      return EINA_FALSE; /* Angle has to be computed first */
1912
1913    if (st->rotate_angular_tolerance < 0)
1914      return EINA_TRUE;
1915
1916    double low  = st->info.base_angle - st->rotate_angular_tolerance;
1917    double high = st->info.base_angle + st->rotate_angular_tolerance;
1918    double t = st->info.angle;
1919
1920    if (low < 0)
1921      {
1922         low += RAD_180DEG;
1923         high += RAD_180DEG;
1924
1925         if (t < RAD_180DEG)
1926           t += RAD_180DEG;
1927         else
1928           t -= RAD_180DEG;
1929      }
1930
1931    if (high > RAD_360DEG)
1932      {
1933         low -= RAD_180DEG;
1934         high -= RAD_180DEG;
1935
1936         if (t < RAD_180DEG)
1937           t += RAD_180DEG;
1938         else
1939           t -= RAD_180DEG;
1940      }
1941
1942 #if defined(DEBUG_GESTURE_LAYER)
1943    printf("%s angle=<%d> low=<%d> high=<%d>\n", __func__, t, low, high);
1944 #endif
1945    if ((t < low) || (t > high))
1946      {  /* This marks that roation action has started */
1947         st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
1948         st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
1949         return EINA_TRUE;
1950      }
1951
1952    return EINA_FALSE;
1953 }
1954
1955 /**
1956  * @internal
1957  *
1958  * This function is used for computing the gap between fingers.
1959  * It returns the length and center point between fingers.
1960  *
1961  * @param x1 first finger x location.
1962  * @param y1 first finger y location.
1963  * @param x2 second finger x location.
1964  * @param y2 second finger y location.
1965  * @param x  Gets center point x cord (output)
1966  * @param y  Gets center point y cord (output)
1967  *
1968  * @return length of the line between (x1,y1), (x2,y2) in pixels.
1969  *
1970  * @ingroup Elm_Gesture_Layer
1971  */
1972 static Evas_Coord
1973 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
1974       Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
1975 {
1976    double a, b, xx, yy, gap;
1977    xx = fabs(x2 - x1);
1978    yy = fabs(y2 - y1);
1979    gap = sqrt(xx*xx + yy*yy);
1980
1981    /* START - Compute zoom center point */
1982    /* The triangle defined as follows:
1983     *             B
1984     *           / |
1985     *          /  |
1986     *     gap /   | a
1987     *        /    |
1988     *       A-----C
1989     *          b
1990     * http://en.wikipedia.org/wiki/Trigonometric_functions
1991     *************************************/
1992    if (((int) xx) && ((int) yy))
1993      {
1994         double A = atan((yy / xx));
1995 #if defined(DEBUG_GESTURE_LAYER)
1996         printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
1997 #endif
1998         a = (Evas_Coord) ((gap / 2) * sin(A));
1999         b = (Evas_Coord) ((gap / 2) * cos(A));
2000         *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
2001         *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
2002      }
2003    else
2004      {
2005         if ((int) xx)
2006           {  /* horiz line, take half width */
2007 #if defined(DEBUG_GESTURE_LAYER)
2008              printf("==== HORIZ ====\n");
2009 #endif
2010              *x = (Evas_Coord) (xx / 2);
2011              *y = (Evas_Coord) (y1);
2012           }
2013
2014         if ((int) yy)
2015           {  /* vert line, take half width */
2016 #if defined(DEBUG_GESTURE_LAYER)
2017              printf("==== VERT ====\n");
2018 #endif
2019              *x = (Evas_Coord) (x1);
2020              *y = (Evas_Coord) (yy / 2);
2021           }
2022      }
2023    /* END   - Compute zoom center point */
2024
2025    return (Evas_Coord) gap;
2026 }
2027
2028 /**
2029  * @internal
2030  *
2031  * This function is used for computing zoom value.
2032  *
2033  * @param st Pointer to zoom data based on user input.
2034  * @param x1 first finger x location.
2035  * @param y1 first finger y location.
2036  * @param x2 second finger x location.
2037  * @param y2 second finger y location.
2038  * @param factor zoom-factor, used to determine how fast zoom works.
2039  *
2040  * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2041  *
2042  * @ingroup Elm_Gesture_Layer
2043  */
2044 /* FIXME change float to double */
2045 static double
2046 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2047       Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2048 {
2049    double rt = 1.0;
2050    Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2051          &st->info.x, &st->info.y);
2052
2053    st->info.radius = diam / 2;
2054
2055    if (!st->zoom_base)
2056      {
2057         st->zoom_base = diam;
2058         return st->info.zoom;
2059      }
2060
2061    if (st->zoom_distance_tolerance)
2062      {  /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2063         if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2064           {  /* avoid jump with zoom value when break tolerance */
2065              st->zoom_base -= st->zoom_distance_tolerance;
2066              st->zoom_distance_tolerance = 0;
2067           }
2068
2069         if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2070           {  /* avoid jump with zoom value when break tolerance */
2071              st->zoom_base += st->zoom_distance_tolerance;
2072              st->zoom_distance_tolerance = 0;
2073           }
2074
2075         return rt;
2076      }
2077
2078    /* We use factor only on the difference between gap-base   */
2079    /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2080    rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2081                (float) st->zoom_base) * zoom_finger_factor));
2082
2083 #if 0
2084    /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2085    st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2086 #else
2087    (void) tm1;
2088    (void) tm2;
2089 #endif
2090    return rt;
2091 }
2092
2093 /**
2094  * @internal
2095  *
2096  * This function handles zoom with mouse wheel.
2097  * thats a combination of wheel + CTRL key.
2098  * @param obj The gesture-layer object.
2099  * @param event_info Original input event pointer.
2100  * @param event_type Type of original input event.
2101  * @param g_type what Gesture we are testing.
2102  *
2103  * @ingroup Elm_Gesture_Layer
2104  */
2105 static void
2106 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2107       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2108 {
2109    Widget_Data *wd = elm_widget_data_get(obj);
2110    if (!wd) return;
2111    if (!wd->gesture[g_type]) return;
2112
2113    Gesture_Info *gesture_zoom = wd->gesture[g_type];
2114    Zoom_Type *st = gesture_zoom->data;
2115    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2116    if (!st)
2117      {  /* Allocated once on first time, used for zoom intermediate data */
2118         st = calloc(1, sizeof(Zoom_Type));
2119         gesture_zoom->data = st;
2120         _zoom_test_reset(gesture_zoom);
2121      }
2122
2123    switch (event_type)
2124      {
2125       case EVAS_CALLBACK_KEY_UP:
2126            {
2127               Evas_Event_Key_Up *p = event_info;
2128               if ((!strcmp(p->keyname, "Control_L")) ||
2129                     (!strcmp(p->keyname, "Control_R")))
2130                 {  /* Test if we ended a zoom gesture when releasing CTRL */
2131                    if ((st->zoom_wheel) &&
2132                          ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2133                           (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2134                      {  /* User released CTRL after zooming */
2135                         ev_flag = _set_state(gesture_zoom,
2136                               ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2137                         consume_event(wd, event_info, event_type, ev_flag);
2138
2139                         return;
2140                      }
2141                 }
2142               break;
2143            }
2144
2145       case EVAS_CALLBACK_MOUSE_WHEEL:
2146            {
2147               Eina_Bool force;
2148               Elm_Gesture_State s;
2149               if (!evas_key_modifier_is_set(
2150                        ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2151                        "Control"))
2152                 {  /* if using wheel witout CTRL after starting zoom */
2153                    if ((st->zoom_wheel) &&
2154                          ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2155                           (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2156                      {
2157                         ev_flag = _set_state(gesture_zoom,
2158                               ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2159                         consume_event(wd, event_info, event_type, ev_flag);
2160
2161                         return;
2162                      }
2163                    else
2164                      return; /* Ignore mouse-wheel without control */
2165                 }
2166
2167               /* Using mouse wheel with CTRL for zoom */
2168               if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2169                 {  /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2170                       we continue a zoom gesture */
2171                    force = EINA_TRUE;
2172                    s = ELM_GESTURE_STATE_MOVE;
2173                 }
2174               else
2175                 {  /* On first wheel event, report START */
2176                    Evas_Modifier_Mask mask = evas_key_modifier_mask_get(
2177                             evas_object_evas_get(wd->target), "Control");
2178                    force = EINA_FALSE;
2179                    s = ELM_GESTURE_STATE_START;
2180                    if (!evas_object_key_grab(wd->target, "Control_L", mask, 0, EINA_FALSE))
2181                      ERR("Failed to Grabbed CTRL_L");
2182                    if (!evas_object_key_grab(wd->target, "Control_R", mask, 0, EINA_FALSE))
2183                      ERR("Failed to Grabbed CTRL_R");
2184                 }
2185
2186               st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2187               st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2188               st->info.x  = st->zoom_wheel->canvas.x;
2189               st->info.y  = st->zoom_wheel->canvas.y;
2190
2191               if (st->zoom_wheel->z > 0) /* zoom in */
2192                 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2193
2194               if (st->zoom_wheel->z < 0) /* zoom out */
2195                 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2196
2197               if (st->info.zoom < 0.0)
2198                 st->info.zoom = 0.0;
2199
2200               ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2201               consume_event(wd, event_info, event_type, ev_flag);
2202               break;
2203            }
2204
2205       default:
2206            return;
2207      }
2208 }
2209
2210 /**
2211  * @internal
2212  *
2213  * This function is used to test zoom gesture.
2214  * user may combine zoom, rotation together.
2215  * so its possible that both will be detected from input.
2216  * (both are two-finger movement-oriented gestures)
2217  *
2218  * @param obj The gesture-layer object.
2219  * @param event_info Pointer to recent input event.
2220  * @param event_type Recent input event type.
2221  * @param g_type what Gesture we are testing.
2222  *
2223  * @ingroup Elm_Gesture_Layer
2224  */
2225 static void
2226 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2227       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2228 {
2229    if (!pe)
2230      return;
2231    Widget_Data *wd = elm_widget_data_get(obj);
2232    if (!wd) return;
2233    if (!wd->gesture[g_type]) return;
2234
2235    Gesture_Info *gesture_zoom = wd->gesture[g_type];
2236    Zoom_Type *st = gesture_zoom->data;
2237
2238    if (!st)
2239      {  /* Allocated once on first time, used for zoom data */
2240         st = calloc(1, sizeof(Zoom_Type));
2241         gesture_zoom->data = st;
2242         _zoom_test_reset(gesture_zoom);
2243      }
2244
2245    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2246    switch (event_type)
2247      {
2248       case EVAS_CALLBACK_MOUSE_DOWN:
2249          consume_event(wd, event_info, event_type, ev_flag);
2250          memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2251
2252          break;
2253
2254       case EVAS_CALLBACK_MOUSE_MOVE:
2255          consume_event(wd, event_info, event_type, ev_flag);
2256          if (!st->zoom_st.timestamp)
2257            return;  /* we got move event before down event.Ignore it */
2258
2259          consume_event(wd, event_info, event_type, ev_flag);
2260          memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2261
2262          /* We match this point to previous multi-move or multi-down event */
2263          if (st->zoom_mv1.timestamp)
2264            {
2265               st->info.zoom = compute_zoom(st,
2266                     st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2267                     st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2268                     wd->zoom_finger_factor);
2269               break;
2270            }
2271
2272          if (st->zoom_st1.timestamp)
2273            {
2274               st->info.zoom = compute_zoom(st,
2275                     st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2276                     st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2277                     wd->zoom_finger_factor);
2278               break;
2279            }
2280
2281          break;
2282
2283       case EVAS_CALLBACK_MULTI_MOVE:
2284            if (!st->zoom_st1.timestamp)
2285              return;  /* We get move event before down event.Ignore it */
2286
2287            consume_event(wd, event_info, event_type, ev_flag);
2288            if (st->zoom_mv1.timestamp)
2289              {
2290              if (st->zoom_mv1.device !=
2291                    ((Evas_Event_Multi_Move *) event_info)->device)
2292                {  /* A third finger on screen, abort zoom */
2293                   ev_flag = _set_state(gesture_zoom,
2294                         ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2295                   consume_event(wd, event_info, event_type, ev_flag);
2296
2297                   return;
2298                }
2299              }
2300
2301            memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2302
2303            /* Match this point to previous mouse-move or mouse-down event */
2304            if (st->zoom_mv.timestamp)
2305              {
2306                 st->info.zoom = compute_zoom(st,
2307                       st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2308                       st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2309                       wd->zoom_finger_factor);
2310                 break;
2311              }
2312
2313            if (st->zoom_st.timestamp)
2314              {
2315                 st->info.zoom = compute_zoom(st,
2316                       st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2317                       st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2318                       wd->zoom_finger_factor);
2319                 break;
2320              }
2321
2322            break;
2323
2324       case EVAS_CALLBACK_MULTI_DOWN:
2325            consume_event(wd, event_info, event_type, ev_flag);
2326            memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2327            break;
2328
2329       case EVAS_CALLBACK_MOUSE_UP:
2330       case EVAS_CALLBACK_MULTI_UP:
2331            /* Reset timestamp of finger-up.This is used later
2332               by _zoom_test_reset() to retain finger-down data */
2333            consume_event(wd, event_info, event_type, ev_flag);
2334            if (((st->zoom_wheel) || (st->zoom_base)) &&
2335                  (st->zoom_distance_tolerance == 0))
2336              {
2337                 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2338                       &st->info, EINA_FALSE);
2339                 consume_event(wd, event_info, event_type, ev_flag);
2340
2341                 return;
2342              }
2343
2344            /* if we got here not a ZOOM */
2345            if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2346              {  /* Must be != undefined, if gesture started */
2347                 ev_flag = _set_state(gesture_zoom,
2348                       ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2349                 consume_event(wd, event_info, event_type, ev_flag);
2350              }
2351
2352            _zoom_test_reset(gesture_zoom);
2353
2354            return;
2355
2356       default:
2357            return;
2358      }
2359
2360
2361    if (!st->zoom_distance_tolerance)
2362      if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2363            (event_type == EVAS_CALLBACK_MULTI_MOVE))
2364        {
2365             {  /* Zoom broke tolerance, report move */
2366                double d = st->info.zoom - st->next_step;
2367                if (d < 0.0)
2368                  d = (-d);
2369
2370                if (d >= wd->zoom_step)
2371                  {  /* Report move in steps */
2372                     st->next_step = st->info.zoom;
2373
2374                     ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2375                           &st->info, EINA_TRUE);
2376                     consume_event(wd, event_info, event_type, ev_flag);
2377                  }
2378             }
2379
2380           return;
2381        }
2382
2383    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2384          (event_type == EVAS_CALLBACK_MULTI_DOWN))
2385      {  /* report zoom start finger location is zoom-center temporarly */
2386         /* Zoom may have started with mouse-wheel, don't report START  */
2387         if ((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2388           {  /* Set zoom-base after BOTH down events were recorded   */
2389              /* Compute length of line between fingers on zoom start */
2390              st->info.zoom = 1.0;
2391              st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2392                       st->zoom_st1.y, st->zoom_st.x,  st->zoom_st.y,
2393                       &st->info.x, &st->info.y);
2394
2395              st->info.radius = st->zoom_base / 2;
2396
2397              if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2398                    (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2399                {  /* Report START only when two fingers touching */
2400                   ev_flag = _set_state(gesture_zoom,
2401                         ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2402                   consume_event(wd, event_info, event_type, ev_flag);
2403                }
2404           }
2405      }
2406
2407    return;
2408 }
2409
2410 static void
2411 _get_rotate_properties(Rotate_Type *st,
2412       Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2413       Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2414       double *angle)
2415 {
2416    st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2417          &st->info.x, &st->info.y) / 2;
2418
2419    *angle = get_angle(x1, y1, x2, y2);
2420 #if 0 /* (NOT YET SUPPORTED) */
2421    if (angle == &st->info.angle)
2422      {  /* Compute momentum: TODO: bug when breaking 0, 360 values */
2423         st->info.momentum = (((*angle) - st->info.base_angle) /
2424            (fabs(tm2 - tm1))) * 1000;
2425      }
2426    else
2427      st->info.momentum = 0;
2428 #else
2429    (void) tm1;
2430    (void) tm2;
2431 #endif
2432 }
2433
2434 /**
2435  * @internal
2436  *
2437  * This function is used to test rotation gesture.
2438  * user may combine zoom, rotation together.
2439  * so its possible that both will be detected from input.
2440  * (both are two-finger movement-oriented gestures)
2441  *
2442  * @param obj The gesture-layer object.
2443  * @param event_info Pointer to recent input event.
2444  * @param event_type Recent input event type.
2445  * @param g_type what Gesture we are testing.
2446  *
2447  * @ingroup Elm_Gesture_Layer
2448  */
2449 static void
2450 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2451       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2452 {
2453    if (!pe)
2454      return;
2455
2456    Widget_Data *wd = elm_widget_data_get(obj);
2457    if (!wd) return;
2458    if (!wd->gesture[g_type]) return;
2459
2460    Gesture_Info *gesture = wd->gesture[g_type];
2461    Rotate_Type *st = gesture->data;
2462    if (gesture)
2463    {
2464       st = gesture->data;
2465       if (!st)
2466         {  /* Allocated once on first time */
2467            st = calloc(1, sizeof(Rotate_Type));
2468            gesture->data = st;
2469            _rotate_test_reset(gesture);
2470         }
2471    }
2472
2473    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2474
2475    switch (event_type)
2476      {
2477       case EVAS_CALLBACK_MOUSE_DOWN:
2478          consume_event(wd, event_info, event_type, ev_flag);
2479          memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2480
2481            break;
2482
2483       case EVAS_CALLBACK_MOUSE_MOVE:
2484          if (!st->rotate_st.timestamp)
2485            break;  /* We got move event before down event.Ignore it */
2486
2487          consume_event(wd, event_info, event_type, ev_flag);
2488          memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2489
2490          /* Match this point to previous multi-move or multi-down event */
2491          if (st->rotate_mv1.timestamp)
2492              {  /* Compute rotation angle and report to user */
2493                 _get_rotate_properties(st,
2494                       st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2495                       st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2496                       &st->info.angle);
2497                 break;
2498              }
2499
2500            if (st->rotate_st1.timestamp)
2501              {  /* Compute rotation angle and report to user */
2502                 _get_rotate_properties(st,
2503                       st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2504                       st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2505                       &st->info.angle);
2506                 break;
2507              }
2508
2509            return;
2510
2511       case EVAS_CALLBACK_MULTI_MOVE:
2512            if (!st->rotate_st1.timestamp)
2513              break;  /* We got move event before down event.Ignore it */
2514
2515            consume_event(wd, event_info, event_type, ev_flag);
2516            if (st->rotate_mv1.timestamp)
2517              {
2518              if (st->rotate_mv1.device !=
2519                    ((Evas_Event_Multi_Move *) event_info)->device)
2520                {  /* A third finger on screen, abort rotate */
2521                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2522                         &st->info, EINA_FALSE);
2523                   consume_event(wd, event_info, event_type, ev_flag);
2524
2525                   return;
2526                }
2527              }
2528
2529            memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2530
2531            /* Match this point to previous mouse-move or mouse-down event */
2532            if (st->rotate_mv.timestamp)
2533              {  /* Compute rotation angle and report to user */
2534                 _get_rotate_properties(st,
2535                       st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2536                       st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2537                       &st->info.angle);
2538                 break;
2539              }
2540
2541            if (st->rotate_st.timestamp)
2542              {  /* Compute rotation angle and report to user */
2543                 _get_rotate_properties(st,
2544                       st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2545                       st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2546                       &st->info.angle);
2547                 break;
2548              }
2549
2550            return;
2551
2552       case EVAS_CALLBACK_MULTI_DOWN:
2553            consume_event(wd, event_info, event_type, ev_flag);
2554            memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2555            _get_rotate_properties(st,
2556                  st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2557                  st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2558                  &st->info.angle);
2559            break;
2560
2561       case EVAS_CALLBACK_MOUSE_UP:
2562       case EVAS_CALLBACK_MULTI_UP:
2563            consume_event(wd, event_info, event_type, ev_flag);
2564            /* Reset timestamp of finger-up.This is used later
2565               by rotate_test_reset() to retain finger-down data */
2566            if (st->rotate_angular_tolerance < 0)
2567              {
2568                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2569                       &st->info, EINA_FALSE);
2570                 consume_event(wd, event_info, event_type, ev_flag);
2571
2572                 return;
2573              }
2574
2575            if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2576              {  /* Must be != undefined, if gesture started */
2577                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2578                       &st->info, EINA_FALSE);
2579                 consume_event(wd, event_info, event_type, ev_flag);
2580              }
2581
2582            _rotate_test_reset(gesture);
2583            return;
2584
2585       default:
2586            return;
2587      }
2588
2589    if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2590          (event_type == EVAS_CALLBACK_MULTI_MOVE))
2591      {  /* Report MOVE or ABORT for *MOVE event */
2592         if (rotation_broke_tolerance(st))
2593           {  /* Rotation broke tolerance, report move */
2594              double d = st->info.angle - st->next_step;
2595              if (d < 0.0)
2596                d = (-d);
2597
2598              if (d >= wd->rotate_step)
2599                {  /* Report move in steps */
2600                   st->next_step = st->info.angle;
2601
2602                   ev_flag = _set_state(gesture,
2603                         ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2604                   consume_event(wd, event_info, event_type, ev_flag);
2605                }
2606           }
2607
2608         return;
2609      }
2610
2611    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2612          (event_type == EVAS_CALLBACK_MULTI_DOWN))
2613      {
2614         if ((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2615           {  /* two-fingers on touch screen - report rotate start */
2616              /* Set base angle, then report start.                */
2617              _get_rotate_properties(st,
2618                    st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2619                    st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2620                    &st->info.base_angle);
2621
2622              ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2623                    &st->info, EINA_FALSE);
2624              consume_event(wd, event_info, event_type, ev_flag);
2625           }
2626      }
2627
2628    return;
2629 }
2630
2631 /**
2632  * @internal
2633  *
2634  * This function is used to save input events in an abstract struct
2635  * to be used later by getsure-testing functions.
2636  *
2637  * @param data The gesture-layer object.
2638  * @param event_info Pointer to recent input event.
2639  * @param event_type Recent input event type.
2640  * @param pe The abstract data-struct (output).
2641  *
2642  * @ingroup Elm_Gesture_Layer
2643  */
2644 static Eina_Bool
2645 _make_pointer_event(void *data, void *event_info,
2646       Evas_Callback_Type event_type, Pointer_Event *pe)
2647 {
2648    Widget_Data *wd = elm_widget_data_get(data);
2649    if (!wd) return EINA_FALSE;
2650
2651    switch (event_type)
2652      {
2653       case EVAS_CALLBACK_MOUSE_DOWN:
2654            pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2655            pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2656            pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2657            pe->device = ELM_MOUSE_DEVICE;
2658            break;
2659
2660       case EVAS_CALLBACK_MOUSE_UP:
2661            pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2662            pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2663            pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2664            pe->device = ELM_MOUSE_DEVICE;
2665            break;
2666
2667       case EVAS_CALLBACK_MOUSE_MOVE:
2668            pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2669            pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2670            pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2671            pe->device = ELM_MOUSE_DEVICE;
2672            break;
2673
2674       case EVAS_CALLBACK_MULTI_DOWN:
2675            pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2676            pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2677            pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2678            pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2679            break;
2680
2681       case EVAS_CALLBACK_MULTI_UP:
2682            pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2683            pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2684            pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2685            pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2686            break;
2687
2688       case EVAS_CALLBACK_MULTI_MOVE:
2689            pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2690            pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2691            pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2692            pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2693            break;
2694
2695       default:
2696            return EINA_FALSE;
2697      }
2698
2699    pe->event_type = event_type;
2700    return EINA_TRUE;
2701 }
2702
2703 /**
2704  * @internal
2705  *
2706  * This function the core-function where input handling is done.
2707  * Here we get user input and stream it to gesture testing.
2708  * We notify user about any gestures with new state:
2709  * Valid states are:
2710  * START - gesture started.
2711  * MOVE - gesture is ongoing.
2712  * END - gesture was completed.
2713  * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
2714  *
2715  * We also check if a gesture was detected, then reset event history
2716  * If no gestures were found we reset gesture test flag
2717  * after streaming event-history to widget.
2718  * (stream to the widget all events not consumed as a gesture)
2719  *
2720  * @param data The gesture-layer object.
2721  * @param event_info Pointer to recent input event.
2722  * @param event_type Recent input event type.
2723  *
2724  * @ingroup Elm_Gesture_Layer
2725  */
2726 static void
2727 _event_process(void *data, Evas_Object *obj __UNUSED__,
2728       void *event_info, Evas_Callback_Type event_type)
2729 {
2730    Pointer_Event _pe;
2731    Pointer_Event *pe = NULL;
2732    Widget_Data *wd = elm_widget_data_get(data);
2733    if (!wd) return;
2734
2735    /* Start testing candidate gesture from here */
2736    if (_make_pointer_event(data, event_info, event_type, &_pe))
2737      pe = &_pe;
2738
2739    if (IS_TESTED(ELM_GESTURE_N_TAPS))
2740      _dbl_click_test(data, pe, event_info, event_type,
2741            ELM_GESTURE_N_TAPS, 1);
2742
2743    if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
2744      _dbl_click_test(data, pe, event_info, event_type,
2745            ELM_GESTURE_N_DOUBLE_TAPS, 2);
2746
2747    if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
2748      _dbl_click_test(data, pe, event_info, event_type,
2749            ELM_GESTURE_N_TRIPLE_TAPS, 3);
2750
2751    if (IS_TESTED(ELM_GESTURE_MOMENTUM))
2752      _momentum_test(data, pe, event_info, event_type,
2753            ELM_GESTURE_MOMENTUM);
2754
2755    if (IS_TESTED(ELM_GESTURE_N_LINES))
2756      _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
2757
2758    if (IS_TESTED(ELM_GESTURE_N_FLICKS))
2759      _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
2760
2761    if (IS_TESTED(ELM_GESTURE_ZOOM))
2762      _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
2763
2764    if (IS_TESTED(ELM_GESTURE_ZOOM))
2765      _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
2766
2767    if (IS_TESTED(ELM_GESTURE_ROTATE))
2768      _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
2769
2770    if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
2771      _event_history_add(data, event_info, event_type);
2772    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2773          (event_type == EVAS_CALLBACK_MULTI_UP))
2774      {
2775         Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
2776         if (pending)
2777           {
2778              consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
2779              _event_history_add(data, event_info, event_type);
2780           }
2781      }
2782
2783    /* we maintain list of touched devices*/
2784    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2785          (event_type == EVAS_CALLBACK_MULTI_DOWN))
2786      {
2787         wd->touched = _add_touched_device(wd->touched, pe);
2788      }
2789    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2790          (event_type == EVAS_CALLBACK_MULTI_UP))
2791      {
2792         wd->touched = _remove_touched_device(wd->touched, pe);
2793      }
2794
2795    /* Report current states and clear history if needed */
2796    _clear_if_finished(data);
2797 }
2798
2799
2800 /**
2801  * For all _mouse_* / multi_* functions wethen send this event to
2802  * _event_process function.
2803  *
2804  * @param data The gesture-layer object.
2805  * @param event_info Pointer to recent input event.
2806  *
2807  * @ingroup Elm_Gesture_Layer
2808  */
2809 static void
2810 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2811       void *event_info)
2812 {
2813    Widget_Data *wd = elm_widget_data_get(data);
2814    if (!wd) return;
2815    if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
2816      return; /* We only process left-click at the moment */
2817
2818    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
2819 }
2820
2821 static void
2822 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2823       void *event_info)
2824 {
2825    Widget_Data *wd = elm_widget_data_get(data);
2826    if (!wd) return;
2827
2828    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
2829 }
2830
2831 static void
2832 _key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2833       void *event_info)
2834 {
2835    Widget_Data *wd = elm_widget_data_get(data);
2836    if (!wd) return;
2837
2838    _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_DOWN);
2839 }
2840
2841 static void
2842 _key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2843       void *event_info)
2844 {
2845    Widget_Data *wd = elm_widget_data_get(data);
2846    if (!wd) return;
2847
2848    _event_process(data, obj, event_info, EVAS_CALLBACK_KEY_UP);
2849 }
2850
2851 static void
2852 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2853       void *event_info)
2854 {
2855    Widget_Data *wd = elm_widget_data_get(data);
2856    if (!wd) return;
2857
2858    if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
2859      return; /* We only process left-click at the moment */
2860
2861    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
2862 }
2863
2864 static void
2865 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2866       void *event_info)
2867 {
2868    Widget_Data *wd = elm_widget_data_get(data);
2869    if (!wd) return;
2870
2871    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
2872 }
2873
2874 static void
2875 _multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2876       void *event_info)
2877 {
2878    Widget_Data *wd = elm_widget_data_get(data);
2879    if (!wd) return;
2880
2881    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_DOWN);
2882 }
2883
2884 static void
2885 _multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2886       void *event_info)
2887 {
2888    Widget_Data *wd = elm_widget_data_get(data);
2889    if (!wd) return;
2890
2891    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_MOVE);
2892 }
2893
2894 static void
2895 _multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2896       void *event_info)
2897 {
2898    Widget_Data *wd = elm_widget_data_get(data);
2899    if (!wd) return;
2900
2901    _event_process(data, obj, event_info, EVAS_CALLBACK_MULTI_UP);
2902 }
2903
2904 EAPI Eina_Bool
2905 elm_gesture_layer_hold_events_get(Evas_Object *obj)
2906 {
2907    Widget_Data *wd = elm_widget_data_get(obj);
2908    if (!wd) return EINA_FALSE;
2909
2910    return !wd->repeat_events;
2911 }
2912
2913 EAPI void
2914 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
2915 {
2916    Widget_Data *wd = elm_widget_data_get(obj);
2917    if (!wd) return;
2918
2919    wd->repeat_events = !r;
2920 }
2921
2922 EAPI void
2923 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
2924 {
2925    Widget_Data *wd = elm_widget_data_get(obj);
2926    if (!wd) return;
2927
2928    if (s < 0.0)
2929      return;
2930
2931    wd->zoom_step = s;
2932 }
2933
2934 EAPI void
2935 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
2936 {
2937    Widget_Data *wd = elm_widget_data_get(obj);
2938    if (!wd) return;
2939
2940    if (s < 0.0)
2941      return;
2942
2943    wd->rotate_step = s;
2944 }
2945
2946 EAPI Eina_Bool
2947 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
2948 {
2949    Widget_Data *wd = elm_widget_data_get(obj);
2950    if (!wd) return EINA_FALSE;
2951
2952    if (!t)
2953      return EINA_FALSE;
2954
2955    /* if was attached before, unregister callbacks first */
2956    if (wd->target)
2957      _unregister_callbacks(obj);
2958
2959    wd->target = t;
2960
2961    _register_callbacks(obj);
2962    return EINA_TRUE;
2963 }
2964
2965 EAPI void
2966 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
2967       Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
2968 {
2969    Widget_Data *wd = elm_widget_data_get(obj);
2970    if (!wd) return;
2971
2972    if (!wd->gesture[idx])
2973      wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
2974
2975    Gesture_Info *p = wd->gesture[idx];
2976    p->obj = obj;
2977    p->g_type = idx;
2978    p->fn[cb_type].cb = cb;
2979    p->fn[cb_type].user_data = data;
2980    p->state = ELM_GESTURE_STATE_UNDEFINED;
2981    SET_TEST_BIT(p);
2982 }
2983
2984 static void
2985 _disable_hook(Evas_Object *obj)
2986 {
2987    if (elm_widget_disabled_get(obj))
2988      _unregister_callbacks(obj);
2989    else
2990      _register_callbacks(obj);
2991 }
2992
2993 EAPI Evas_Object *
2994 elm_gesture_layer_add(Evas_Object *parent)
2995 {
2996    Evas_Object *obj;
2997    Evas *e;
2998    Widget_Data *wd;
2999
3000    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
3001
3002    wd = ELM_NEW(Widget_Data);
3003    e = evas_object_evas_get(parent);
3004    if (!e) return NULL;
3005    obj = elm_widget_add(e);
3006    ELM_SET_WIDTYPE(widtype, "gesture_layer");
3007    elm_widget_type_set(obj, "gesture_layer");
3008    elm_widget_sub_object_add(parent, obj);
3009    elm_widget_data_set(obj, wd);
3010    elm_widget_del_hook_set(obj, _del_hook);
3011    elm_widget_disable_hook_set(obj, _disable_hook);
3012
3013    wd->target = NULL;
3014    wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3015    wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3016    wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3017    wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3018    wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3019    wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3020    wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3021    wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3022    wd->repeat_events = EINA_TRUE;
3023
3024 #if defined(DEBUG_GESTURE_LAYER)
3025    printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3026    printf("initial values:\n\tzoom_finger_factor=<%f>\n\tzoom_distance_tolerance=<%d>\n\tline_min_length=<%d>\n\tline_distance_tolerance=<%d>\n\tzoom_wheel_factor=<%f>\n\trotate_angular_tolerance=<%f>\n\twd->line_angular_tolerance=<%f>\n\twd->flick_time_limit_ms=<%d>\n", wd->zoom_finger_factor, wd->zoom_distance_tolerance, wd->line_min_length, wd->line_distance_tolerance, wd->zoom_wheel_factor, wd->rotate_angular_tolerance, wd->line_angular_tolerance, wd->flick_time_limit_ms);
3027 #endif
3028    memset(wd->gesture, 0, sizeof(wd->gesture));
3029
3030    return obj;
3031 }