Elm glayer: Added glayer values to elm config.
[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
644    pe.timestamp = pe1.timestamp = 0;
645
646    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
647             &st->zoom_st))
648      memcpy(&pe, &st->zoom_st, sizeof(Pointer_Event));
649
650    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
651             &st->zoom_st1))
652      memcpy(&pe1, &st->zoom_st1, sizeof(Pointer_Event));
653
654    memset(st, 0, sizeof(Zoom_Type));
655
656    /* If user released one finger only, restore down-info */
657    if (pe.timestamp && (!pe1.timestamp))
658      memcpy(&st->zoom_st, &pe, sizeof(Pointer_Event));
659
660    if (pe1.timestamp && (!pe.timestamp))
661      memcpy(&st->zoom_st1, &pe1, sizeof(Pointer_Event));
662
663    st->zoom_distance_tolerance = wd->zoom_distance_tolerance;
664    st->info.zoom = 1.0;
665 }
666
667 static void
668 _rotate_test_reset(Gesture_Info *gesture)
669 {
670    if (!gesture)
671      return;
672
673    if (!gesture->data)
674      return;
675
676    Widget_Data *wd = elm_widget_data_get(gesture->obj);
677    Rotate_Type *st = gesture->data;
678    Pointer_Event pe, pe1;
679
680    pe.timestamp = pe1.timestamp = 0;
681
682    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
683             &st->rotate_st))
684      memcpy(&pe, &st->rotate_st, sizeof(Pointer_Event));
685
686    if (eina_list_search_unsorted_list(wd->touched, device_is_touched,
687             &st->rotate_st1))
688      memcpy(&pe1, &st->rotate_st1, sizeof(Pointer_Event));
689
690    memset(st, 0, sizeof(Rotate_Type));
691
692    /* If user released one finger only, restore down-info */
693    if (pe.timestamp && (!pe1.timestamp))
694      memcpy(&st->rotate_st, &pe, sizeof(Pointer_Event));
695
696    if (pe1.timestamp && (!pe.timestamp))
697      memcpy(&st->rotate_st1, &pe1, sizeof(Pointer_Event));
698
699
700    st->info.base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
701    st->rotate_angular_tolerance = wd->rotate_angular_tolerance;
702 }
703
704
705 /**
706  * @internal
707  *
708  * We register callbacks when gesture layer is attached to an object
709  * or when its enabled after disable.
710  *
711  * @param obj The gesture-layer object.
712  *
713  * @ingroup Elm_Gesture_Layer
714  */
715 static void
716 _register_callbacks(Evas_Object *obj)
717 {
718    Widget_Data *wd = elm_widget_data_get(obj);
719    if (!wd) return;
720
721    if (wd->target)
722      {
723         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
724               _mouse_down, obj);
725         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
726               _mouse_move, obj);
727         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_UP,
728               _mouse_up, obj);
729
730         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
731               _mouse_wheel, obj);
732
733         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_DOWN,
734               _multi_down, obj);
735         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_MOVE,
736               _multi_move, obj);
737         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MULTI_UP,
738               _multi_up, obj);
739
740         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_DOWN,
741               _key_down_cb, obj);
742         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_KEY_UP,
743               _key_up_cb, obj);
744      }
745 }
746
747 /**
748  * @internal
749  *
750  * We unregister callbacks when gesture layer is disabled.
751  *
752  * @param obj The gesture-layer object.
753  *
754  * @ingroup Elm_Gesture_Layer
755  */
756 static void
757 _unregister_callbacks(Evas_Object *obj)
758 {
759    Widget_Data *wd = elm_widget_data_get(obj);
760    if (!wd) return;
761
762    if (wd->target)
763      {
764         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_DOWN,
765               _mouse_down);
766         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_MOVE,
767               _mouse_move);
768         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_UP,
769               _mouse_up);
770
771         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MOUSE_WHEEL,
772               _mouse_wheel);
773
774         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_DOWN,
775               _multi_down);
776
777         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_MOVE,
778               _multi_move);
779
780         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_MULTI_UP,
781               _multi_up);
782
783         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_DOWN,
784               _key_down_cb);
785         evas_object_event_callback_del(wd->target, EVAS_CALLBACK_KEY_UP,
786               _key_up_cb);
787      }
788 }
789
790 /* START - Event history list handling functions */
791 /**
792  * @internal
793  * This function is used to find if device number
794  * is found in a list of devices.
795  * The list contains devices for refeeding *UP event
796  *
797  * @ingroup Elm_Gesture_Layer
798  */
799 static int
800 device_in_pending_list(const void *data1, const void *data2)
801 {  /* Compare the two device numbers */
802    return (((int) data1) - ((int) data2));
803 }
804
805 /**
806  * @internal
807  *
808  * This functions adds device to refeed-pending device list
809  * @ingroup Elm_Gesture_Layer
810  */
811 static Eina_List *
812 _add_device_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
813 {
814    int device = ELM_MOUSE_DEVICE;
815    switch(event_type)
816      {
817       case EVAS_CALLBACK_MOUSE_DOWN:
818          break;
819       case EVAS_CALLBACK_MULTI_DOWN:
820          device = ((Evas_Event_Multi_Down *) event)->device;
821          break;
822       default:
823          return list;
824      }
825
826    if (!eina_list_search_unsorted_list(list, device_in_pending_list,
827             (void *) device))
828      {
829         return eina_list_append(list, (void *) device);
830      }
831
832    return list;
833 }
834
835 /**
836  * @internal
837  *
838  * This functions returns pending-device node
839  * @ingroup Elm_Gesture_Layer
840  */
841 static Eina_List *
842 _device_is_pending(Eina_List *list, void *event, Evas_Callback_Type event_type)
843 {
844    int device = ELM_MOUSE_DEVICE;
845    switch(event_type)
846      {
847       case EVAS_CALLBACK_MOUSE_UP:
848          break;
849       case EVAS_CALLBACK_MULTI_UP:
850          device = ((Evas_Event_Multi_Up *) event)->device;
851          break;
852       default:
853         return NULL;
854      }
855
856    return eina_list_search_unsorted_list(list, device_in_pending_list,
857          (void *) device);
858 }
859
860 /**
861  * @internal
862  *
863  * This function reports ABORT to all none-detected gestures
864  * Then resets test bits for all desired gesures
865  * and clears input-events history.
866  * note: if no gesture was detected, events from history list
867  * are streamed to the widget because it's unused by layer.
868  * user may cancel refeed of events by setting repeat events.
869  *
870  * @param obj The gesture-layer object.
871  *
872  * @ingroup Elm_Gesture_Layer
873  */
874 static void
875 _event_history_clear(Evas_Object *obj)
876 {
877    Widget_Data *wd = elm_widget_data_get(obj);
878    if (!wd) return;
879
880    int i;
881    Gesture_Info *p;
882    Evas *e = evas_object_evas_get(obj);
883    Eina_Bool gesture_found = EINA_FALSE;
884    for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++)
885      {
886         p = wd->gesture[i];
887         if (p)
888           {
889              if (p->state == ELM_GESTURE_STATE_END)
890                gesture_found = EINA_TRUE;
891              else
892                {  /* Report ABORT to all gestures that still not finished */
893                   _set_state(p, ELM_GESTURE_STATE_ABORT, wd->gesture[i]->info,
894                         EINA_FALSE);
895                }
896           }
897      }
898
899    _reset_states(wd); /* we are ready to start testing for gestures again */
900
901    /* Clear all gestures intermediate date */
902    _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]);
903    _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]);
904    _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]);
905    _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]);
906    _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]);
907    _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]);
908    _zoom_test_reset(wd->gesture[ELM_GESTURE_ZOOM]);
909    _rotate_test_reset(wd->gesture[ELM_GESTURE_ROTATE]);
910
911    /* Disable gesture layer so refeeded events won't be consumed by it */
912    _unregister_callbacks(obj);
913    while (wd->event_history_list)
914      {
915         Event_History *t;
916         t = wd->event_history_list;
917         Eina_List *pending = _device_is_pending(wd->pending,
918               wd->event_history_list->event,
919               wd->event_history_list->event_type);
920
921         /* Refeed events if no gesture matched input */
922         if (pending || ((!gesture_found) && (!wd->repeat_events)))
923           {
924              evas_event_refeed_event(e, wd->event_history_list->event,
925                    wd->event_history_list->event_type);
926
927              if (pending)
928                {
929                wd->pending = eina_list_remove_list(wd->pending, pending);
930                int device = ELM_MOUSE_DEVICE;
931                if (wd->event_history_list->event_type == EVAS_CALLBACK_MULTI_UP)
932                  device = ((Evas_Event_Multi_Up *)
933                        (wd->event_history_list->event))->device;
934                }
935              else
936                wd->pending = _add_device_pending(wd->pending,
937                      wd->event_history_list->event,
938                      wd->event_history_list->event_type);
939           }
940
941         free(wd->event_history_list->event);
942         wd->event_history_list = (Event_History *) eina_inlist_remove(
943               EINA_INLIST_GET(wd->event_history_list),
944               EINA_INLIST_GET(wd->event_history_list));
945         free(t);
946      }
947    _register_callbacks(obj);
948 }
949
950 /**
951  * @internal
952  *
953  * This function copies input events.
954  * We copy event info before adding it to history.
955  * The memory is freed when we clear history.
956  *
957  * @param event the event to copy
958  * @param event_type event type to copy
959  *
960  * @ingroup Elm_Gesture_Layer
961  */
962 static void *
963 _copy_event_info(void *event, Evas_Callback_Type event_type)
964 {
965    switch(event_type)
966      {
967       case EVAS_CALLBACK_MOUSE_DOWN:
968          return COPY_EVENT_INFO((Evas_Event_Mouse_Down *) event);
969          break;
970       case EVAS_CALLBACK_MOUSE_MOVE:
971          return COPY_EVENT_INFO((Evas_Event_Mouse_Move *) event);
972          break;
973       case EVAS_CALLBACK_MOUSE_UP:
974          return COPY_EVENT_INFO((Evas_Event_Mouse_Up *) event);
975          break;
976       case EVAS_CALLBACK_MOUSE_WHEEL:
977          return COPY_EVENT_INFO((Evas_Event_Mouse_Wheel *) event);
978          break;
979       case EVAS_CALLBACK_MULTI_DOWN:
980          return COPY_EVENT_INFO((Evas_Event_Multi_Down *) event);
981          break;
982       case EVAS_CALLBACK_MULTI_MOVE:
983          return COPY_EVENT_INFO((Evas_Event_Multi_Move *) event);
984          break;
985       case EVAS_CALLBACK_MULTI_UP:
986          return COPY_EVENT_INFO((Evas_Event_Multi_Up *) event);
987          break;
988       case EVAS_CALLBACK_KEY_DOWN:
989          return COPY_EVENT_INFO((Evas_Event_Key_Down *) event);
990          break;
991       case EVAS_CALLBACK_KEY_UP:
992          return COPY_EVENT_INFO((Evas_Event_Key_Up *) event);
993          break;
994       default:
995          return NULL;
996      }
997 }
998
999 static Eina_Bool
1000 _event_history_add(Evas_Object *obj, void *event, Evas_Callback_Type event_type)
1001 {
1002    Widget_Data *wd = elm_widget_data_get(obj);
1003    Event_History *ev;
1004    if (!wd) return EINA_FALSE;
1005
1006    ev = malloc(sizeof(Event_History));
1007    ev->event = _copy_event_info(event, event_type);  /* Freed on event_history_clear */
1008    ev->event_type = event_type;
1009    wd->event_history_list = (Event_History *) eina_inlist_append(
1010          EINA_INLIST_GET(wd->event_history_list), EINA_INLIST_GET(ev));
1011
1012    return EINA_TRUE;
1013 }
1014 /* END - Event history list handling functions */
1015
1016 static void
1017 _del_hook(Evas_Object *obj)
1018 {
1019    Widget_Data *wd = elm_widget_data_get(obj);
1020    if (!wd) return;
1021
1022    _event_history_clear(obj);
1023    eina_list_free(wd->pending);
1024
1025    Pointer_Event *data;
1026    EINA_LIST_FREE(wd->touched, data)
1027       free(data);
1028
1029    if (!elm_widget_disabled_get(obj))
1030      _unregister_callbacks(obj);
1031
1032    /* Free all gestures internal data structures */
1033    int i;
1034    for (i = 0; i < ELM_GESTURE_LAST; i++)
1035      if (wd->gesture[i])
1036        {
1037           if (wd->gesture[i]->data)
1038             free(wd->gesture[i]->data);
1039
1040           free(wd->gesture[i]);
1041        }
1042
1043    free(wd);
1044 }
1045
1046 static int
1047 compare_match_fingers(const void *data1, const void *data2)
1048 {  /* Compare coords of first item in list to cur coords */
1049    const Pointer_Event *pe1 = eina_list_data_get(data1);
1050    const Pointer_Event *pe2 = data2;
1051
1052    if (_inside(pe1->x, pe1->y, pe2->x, pe2->y))
1053      return 0;
1054    else if (pe1->x < pe2->x)
1055      return -1;
1056    else
1057      {
1058         if (pe1->x == pe2->x)
1059           return pe1->y - pe2->y;
1060         else
1061           return 1;
1062      }
1063 }
1064
1065 static int
1066 compare_pe_device(const void *data1, const void *data2)
1067 {  /* Compare coords of first item in list to cur coords */
1068    const Pointer_Event *pe1 = eina_list_data_get(eina_list_last(data1));
1069    const Pointer_Event *pe2 = data2;
1070
1071    /* Only match if last was a down event */
1072    if ((pe1->event_type != EVAS_CALLBACK_MULTI_DOWN) &&
1073          (pe1->event_type != EVAS_CALLBACK_MOUSE_DOWN))
1074      return 1;
1075
1076
1077    if (pe1->device == pe2->device)
1078      return 0;
1079    else if (pe1->device < pe2->device)
1080      return -1;
1081    else
1082      return 1;
1083 }
1084
1085 static Eina_List*
1086 _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe,
1087       Widget_Data *wd, void *event_info, Evas_Callback_Type event_type)
1088 {  /* Keep copy of pe and record it in list */
1089    Pointer_Event *p = malloc(sizeof(Pointer_Event));
1090    memcpy(p, pe, sizeof(Pointer_Event));
1091    consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1092
1093    st->sum_x += pe->x;
1094    st->sum_y += pe->y;
1095    st->n_taps++;
1096
1097    /* This will also update middle-point to report to user later */
1098    st->info.x = st->sum_x / st->n_taps;
1099    st->info.y = st->sum_y / st->n_taps;
1100    st->info.timestamp = pe->timestamp;
1101
1102    if (!pe_list)
1103      {
1104         pe_list = eina_list_append(pe_list, p);
1105         st->l = eina_list_append(st->l, pe_list);
1106      }
1107    else
1108      pe_list = eina_list_append(pe_list, p);
1109
1110    return pe_list;
1111 }
1112
1113 /**
1114  * @internal
1115  *
1116  * when this timer expires we ABORT double click gesture.
1117  *
1118  * @param data The gesture-layer object.
1119  * @return cancles callback for this timer.
1120  *
1121  * @ingroup Elm_Gesture_Layer
1122  */
1123 static Eina_Bool
1124 _dbl_click_timeout(void *data)
1125 {
1126    Gesture_Info *gesture = data;
1127    Widget_Data *wd = elm_widget_data_get(gesture->obj);
1128
1129    wd->dbl_timeout = NULL;
1130    _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1131          gesture->info, EINA_FALSE);
1132
1133    _dbl_click_test_reset(gesture);
1134    _clear_if_finished(gesture->obj);
1135    return ECORE_CALLBACK_CANCEL;
1136 }
1137
1138 /**
1139  * @internal
1140  *
1141  * This function checks all click/tap and double/triple taps
1142  *
1143  * @param obj The gesture-layer object.
1144  * @param pe The recent input event as stored in pe struct.
1145  * @param event_info Original input event pointer.
1146  * @param event_type Type of original input event.
1147  * @param g_type what Gesture we are testing.
1148  * @param taps How many click/taps we test for.
1149  *
1150  * @ingroup Elm_Gesture_Layer
1151  */
1152 static void
1153 _dbl_click_test(Evas_Object *obj, Pointer_Event *pe,
1154       void *event_info, Evas_Callback_Type event_type,
1155       Elm_Gesture_Types g_type, int taps)
1156 {  /* Here we fill Recent_Taps struct and fire-up click/tap timers */
1157    Widget_Data *wd = elm_widget_data_get(obj);
1158    if (!wd) return;
1159
1160    if (!pe)   /* this happens when unhandled event arrived */
1161      return; /* see _make_pointer_event function */
1162
1163    Gesture_Info *gesture = wd->gesture[g_type];
1164    if (!gesture ) return;
1165
1166    if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1167          eina_list_count(wd->touched))
1168      return; /* user left a finger on device, do NOT start */
1169
1170    Taps_Type *st = gesture->data;
1171    if (!st)
1172      {  /* Allocated once on first time */
1173         st = calloc(1, sizeof(Taps_Type));
1174         gesture->data = st;
1175         _dbl_click_test_reset(gesture);
1176      }
1177
1178    Eina_List *pe_list = NULL;
1179    Pointer_Event *pe_down = NULL;
1180    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1181    switch (pe->event_type)
1182      {
1183       case EVAS_CALLBACK_MULTI_DOWN:
1184       case EVAS_CALLBACK_MOUSE_DOWN:
1185          pe_list = eina_list_search_unsorted(st->l, compare_match_fingers, pe);
1186          pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1187          if ((pe->device == 0) && (eina_list_count(pe_list) == 1))
1188            {  /* This is the first mouse down we got */
1189               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1190                     &st->info, EINA_FALSE);
1191               consume_event(wd, event_info, event_type, ev_flag);
1192
1193               /* To test dbl_click/dbl_tap */
1194               /* When this timer expires, gesture ABORTed if not completed */
1195               if (!wd->dbl_timeout && (taps > 1))
1196                 wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout,
1197                       gesture);
1198
1199               return;
1200            }
1201
1202          break;
1203       case EVAS_CALLBACK_MULTI_UP:
1204       case EVAS_CALLBACK_MOUSE_UP:
1205          pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1206          if (!pe_list)
1207            return;  /* Got only first mouse_down and mouse_up */
1208
1209          pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type);
1210
1211          if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2))
1212            return;  /* Got only first mouse_down and mouse_up */
1213
1214          /* Get first event in first list, this has to be Mouse Down event */
1215          pe_down = eina_list_data_get(pe_list);
1216
1217          if (_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1218            {
1219               st->count_ups++;
1220            }
1221          else
1222            {
1223               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1224                     &st->info, EINA_FALSE);
1225               consume_event(wd, event_info, event_type, ev_flag);
1226               break;
1227            }
1228
1229          if (st->count_ups == eina_list_count(st->l))
1230            {
1231               /* Abort if we found a single click */
1232               if ((taps == 1) && (st->count_ups == 1))
1233                 {
1234                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1235                          &st->info, EINA_FALSE);
1236                    consume_event(wd, event_info, event_type, ev_flag);
1237                    break;
1238                 }
1239               st->info.n = st->count_ups;
1240               ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END,
1241                     &st->info, EINA_FALSE);
1242               consume_event(wd, event_info, event_type, ev_flag);
1243
1244               return;
1245            }
1246
1247          break;
1248
1249       case EVAS_CALLBACK_MULTI_MOVE:
1250       case EVAS_CALLBACK_MOUSE_MOVE:
1251          /* Get first event in first list, this has to be a Mouse Down event  */
1252          /* and verify that user didn't move out of this area before next tap */
1253          pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe);
1254          if (pe_list)
1255            {
1256               pe_down = eina_list_data_get(pe_list);
1257               if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y))
1258                 {
1259                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1260                       &st->info, EINA_FALSE);
1261                 consume_event(wd, event_info, event_type, ev_flag);
1262                 }
1263            }
1264          break;
1265
1266       default:
1267          return;
1268      }
1269 }
1270
1271 /**
1272  * @internal
1273  *
1274  * This function computes momentum for MOMENTUM, LINE and FLICK gestures
1275  * This momentum value will be sent to widget when gesture is completed.
1276  *
1277  * @param momentum pointer to buffer where we record momentum value.
1278  * @param x1 x coord where user started gesture.
1279  * @param y1 y coord where user started gesture.
1280  * @param x2 x coord where user completed gesture.
1281  * @param y2 y coord where user completed gesture.
1282  * @param t1x timestamp for X, when user started gesture.
1283  * @param t1y timestamp for Y, when user started gesture.
1284  * @param t2  timestamp when user completed gesture.
1285  *
1286  * @ingroup Elm_Gesture_Layer
1287  */
1288 static void
1289 _set_momentum(Elm_Gesture_Momentum_Info *momentum, Evas_Coord x1, Evas_Coord y1,
1290       Evas_Coord x2, Evas_Coord y2, unsigned int t1x, unsigned int t1y,
1291       unsigned int t2)
1292 {
1293    Evas_Coord velx = 0, vely = 0, vel;
1294    Evas_Coord dx = x2 - x1;
1295    Evas_Coord dy = y2 - y1;
1296    int dtx = t2 - t1x;
1297    int dty = t2 - t1y;
1298    if (dtx > 0)
1299      velx = (dx * 1000) / dtx;
1300
1301    if (dty > 0)
1302      vely = (dy * 1000) / dty;
1303
1304    vel = sqrt((velx * velx) + (vely * vely));
1305
1306    if ((_elm_config->thumbscroll_friction > 0.0) &&
1307          (vel > _elm_config->thumbscroll_momentum_threshold))
1308      {  /* report momentum */
1309         momentum->mx = velx;
1310         momentum->my = vely;
1311      }
1312    else
1313      {
1314         momentum->mx = 0;
1315         momentum->my = 0;
1316      }
1317 }
1318
1319 /**
1320  * @internal
1321  *
1322  * This function is used for computing rotation angle (DEG).
1323  *
1324  * @param x1 first finger x location.
1325  * @param y1 first finger y location.
1326  * @param x2 second finger x location.
1327  * @param y2 second finger y location.
1328  *
1329  * @return angle of the line between (x1,y1), (x2,y2) in Radians.
1330  *
1331  * @ingroup Elm_Gesture_Layer
1332  */
1333 static double
1334 get_angle(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
1335 {
1336    double a, xx, yy;
1337    xx = fabs(x2 - x1);
1338    yy = fabs(y2 - y1);
1339
1340    if (((int) xx) && ((int) yy))
1341      {
1342         a = atan(yy / xx);
1343         if (x1 < x2)
1344           {
1345              if (y1 < y2)
1346                {
1347                   return RAD_360DEG - a;
1348                }
1349              else
1350                {
1351                   return (a);
1352                }
1353           }
1354         else
1355           {
1356              if (y1 < y2)
1357                {
1358                   return RAD_180DEG + a;
1359                }
1360              else
1361                {
1362                   return RAD_180DEG - a;
1363                }
1364           }
1365      }
1366
1367    if (((int) xx))
1368      {  /* Horizontal line */
1369         if (x2 < x1)
1370           {
1371              return RAD_180DEG;
1372           }
1373         else
1374           {
1375              return 0.0;
1376           }
1377      }
1378
1379    /* Vertical line */
1380    if (y2 < y1)
1381      {
1382         return RAD_90DEG;
1383      }
1384    else
1385      {
1386         return RAD_270DEG;
1387      }
1388 }
1389
1390 /**
1391  * @internal
1392  *
1393  * This function is used for computing the magnitude and direction
1394  * of vector between two points.
1395  *
1396  * @param x1 first finger x location.
1397  * @param y1 first finger y location.
1398  * @param x2 second finger x location.
1399  * @param y2 second finger y location.
1400  * @param l length computed (output)
1401  * @param a angle computed (output)
1402  *
1403  * @ingroup Elm_Gesture_Layer
1404  */
1405 static void
1406 get_vector(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2,
1407       Evas_Coord *l, double *a)
1408 {
1409    Evas_Coord xx, yy;
1410    xx = x2 - x1;
1411    yy = y2 - y1;
1412    *l = (Evas_Coord) sqrt(xx*xx + yy*yy);
1413    *a = get_angle(x1, y1, x2, y2);
1414 }
1415
1416 static int
1417 _get_direction(Evas_Coord x1, Evas_Coord x2)
1418 {
1419    if (x1 == x2)
1420      return 0;
1421    else if (x2 < x1)
1422      return -1;
1423    else
1424      return 1;
1425 }
1426
1427 /**
1428  * @internal
1429  *
1430  * This function tests momentum gesture.
1431  * @param obj The gesture-layer object.
1432  * @param pe The recent input event as stored in pe struct.
1433  * @param event_info recent input event.
1434  * @param event_type recent event type.
1435  * @param g_type what Gesture we are testing.
1436  *
1437  * @ingroup Elm_Gesture_Layer
1438  */
1439 static void
1440 _momentum_test(Evas_Object *obj, Pointer_Event *pe,
1441       void *event_info, Evas_Callback_Type event_type,
1442       Elm_Gesture_Types g_type)
1443 {
1444    Widget_Data *wd = elm_widget_data_get(obj);
1445    if (!wd) return;
1446    Gesture_Info *gesture = wd->gesture[g_type];
1447    if (!gesture ) return;
1448
1449    if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1450          eina_list_count(wd->touched))
1451      return; /* user left a finger on device, do NOT start */
1452
1453    Momentum_Type *st = gesture->data;
1454    if (!st)
1455      {  /* Allocated once on first time */
1456         st = calloc(1, sizeof(Momentum_Type));
1457         gesture->data = st;
1458         _momentum_test_reset(gesture);
1459      }
1460
1461    if (!pe)
1462      return;
1463
1464    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1465    switch (pe->event_type)
1466      {
1467       case EVAS_CALLBACK_MOUSE_DOWN:
1468          st->line_st.x = st->line_end.x = pe->x;
1469          st->line_st.y = st->line_end.y = pe->y;
1470          st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
1471          st->xdir = st->ydir = 0;
1472          st->info.x2 = st->info.x1 = pe->x;
1473          st->info.y2 = st->info.y1 = pe->y;
1474          st->info.tx = st->info.ty = pe->timestamp;
1475          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1476                &st->info, EINA_FALSE);
1477          consume_event(wd, event_info, event_type, ev_flag);
1478          break;
1479
1480       case EVAS_CALLBACK_MOUSE_UP:
1481          /* IGNORE if line info was cleared, like long press, move */
1482          if (!st->t_st_x)
1483            return;
1484
1485          if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1486            {
1487               /* Too long of a wait, reset all values */
1488               st->line_st.x = pe->x;
1489               st->line_st.y = pe->y;
1490               st->t_st_y = st->t_st_x = pe->timestamp;
1491               st->xdir = st->ydir = 0;
1492            }
1493
1494          st->info.x2 = pe->x;
1495          st->info.y2 = pe->y;
1496          st->line_end.x = pe->x;
1497          st->line_end.y = pe->y;
1498          st->t_end = pe->timestamp;
1499
1500          _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1501                st->t_st_x, st->t_st_y, pe->timestamp);
1502
1503          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
1504                EINA_FALSE);
1505          consume_event(wd, event_info, event_type, ev_flag);
1506
1507          return;
1508
1509       case EVAS_CALLBACK_MOUSE_MOVE:
1510          /* IGNORE if line info was cleared, like long press, move */
1511          if (!st->t_st_x)
1512            return;
1513
1514          if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
1515            {
1516               /* Too long of a wait, reset all values */
1517               st->line_st.x = pe->x;
1518               st->line_st.y = pe->y;
1519               st->t_st_y = st->t_st_x = pe->timestamp;
1520               st->info.tx = st->t_st_x;
1521               st->info.ty = st->t_st_y;
1522               st->xdir = st->ydir = 0;
1523            }
1524          else
1525            {
1526               int xdir, ydir;
1527               xdir = _get_direction(st->line_end.x, pe->x);
1528               ydir = _get_direction(st->line_end.y, pe->y);
1529               if (!xdir || (xdir == (-st->xdir)))
1530                 {
1531                    st->line_st.x = st->line_end.x;
1532                    st->info.tx = st->t_st_x = st->t_end;
1533                    st->xdir = xdir;
1534                 }
1535
1536               if (!ydir || (ydir == (-st->ydir)))
1537                 {
1538                    st->line_st.y = st->line_end.y;
1539                    st->info.ty = st->t_st_y = st->t_end;
1540                    st->ydir = ydir;
1541                 }
1542            }
1543
1544          st->info.x2 = st->line_end.x = pe->x;
1545          st->info.y2 = st->line_end.y = pe->y;
1546          st->t_end = pe->timestamp;
1547          _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
1548                st->t_st_x, st->t_st_y, pe->timestamp);
1549          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE, &st->info,
1550                EINA_TRUE);
1551          consume_event(wd, event_info, event_type, ev_flag);
1552          break;
1553
1554       case EVAS_CALLBACK_MULTI_UP:
1555          ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1556                EINA_FALSE);
1557          consume_event(wd, event_info, event_type, ev_flag);
1558          return;
1559
1560       default:
1561          return;
1562      }
1563 }
1564
1565 static int
1566 compare_line_device(const void *data1, const void *data2)
1567 {  /* Compare device component of line struct */
1568    const Line_Data *ln1 = data1;
1569    const int *device = data2;
1570
1571    if (ln1->t_st) /* Compare only with lines that started */
1572      return (ln1->device - (*device));
1573
1574    return (-1);
1575 }
1576
1577 /**
1578  * @internal
1579  *
1580  * This function construct line struct from input.
1581  * @param info pointer to store line momentum.
1582  * @param st line info to store input data.
1583  * @param pe The recent input event as stored in pe struct.
1584  *
1585  * @ingroup Elm_Gesture_Layer
1586  */
1587 static Eina_Bool
1588 _single_line_process(Elm_Gesture_Line_Info *info, Line_Data *st,
1589       Pointer_Event *pe)
1590 {  /* Record events and set momentum for line pointed by st */
1591    if (!pe)
1592      return EINA_FALSE;
1593
1594    switch (pe->event_type)
1595      {
1596       case EVAS_CALLBACK_MOUSE_DOWN:
1597       case EVAS_CALLBACK_MULTI_DOWN:
1598          st->line_st.x = pe->x;
1599          st->line_st.y = pe->y;
1600          st->t_st = pe->timestamp;
1601          st->device = pe->device;
1602          info->momentum.x1 = pe->x;
1603          info->momentum.y1 = pe->y;
1604          info->momentum.tx = pe->timestamp;
1605          info->momentum.ty = pe->timestamp;
1606
1607          return EINA_TRUE;
1608          break;
1609
1610       case EVAS_CALLBACK_MOUSE_UP:
1611       case EVAS_CALLBACK_MULTI_UP:
1612          /* IGNORE if line info was cleared, like long press, move */
1613          if (!st->t_st)
1614            return EINA_FALSE;
1615
1616          st->line_end.x = pe->x;
1617          st->line_end.y = pe->y;
1618          st->t_end = pe->timestamp;
1619          break;
1620
1621       case EVAS_CALLBACK_MOUSE_MOVE:
1622       case EVAS_CALLBACK_MULTI_MOVE:
1623          /* IGNORE if line info was cleared, like long press, move */
1624          if (!st->t_st)
1625            return EINA_FALSE;
1626
1627          break;
1628       default:
1629          return EINA_FALSE;
1630      }
1631
1632    if (!st->t_st)
1633      {
1634         _line_data_reset(st);
1635         return EINA_FALSE;
1636      }
1637
1638    info->momentum.x2 = pe->x;
1639    info->momentum.y2 = pe->y;
1640    _set_momentum(&info->momentum, st->line_st.x, st->line_st.y, pe->x, pe->y,
1641          st->t_st, st->t_st, pe->timestamp);
1642
1643    return EINA_TRUE;
1644 }
1645
1646 /**
1647  * @internal
1648  *
1649  * This function test for (n) line gesture.
1650  * @param obj The gesture-layer object.
1651  * @param pe The recent input event as stored in pe struct.
1652  * @param event_info Original input event pointer.
1653  * @param event_type Type of original input event.
1654  * @param g_type what Gesture we are testing.
1655  *
1656  * @ingroup Elm_Gesture_Layer
1657  */
1658 static void
1659 _n_line_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
1660       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
1661 {
1662    if (!pe)
1663      return;
1664    Widget_Data *wd = elm_widget_data_get(obj);
1665    if (!wd) return;
1666    Gesture_Info *gesture = wd->gesture[g_type];
1667    if (!gesture ) return;
1668
1669    if ((gesture->state == ELM_GESTURE_STATE_UNDEFINED) &&
1670          eina_list_count(wd->touched))
1671      return; /* user left a finger on device, do NOT start */
1672
1673    Line_Type *st = gesture->data;
1674    if (!st)
1675      {
1676         st = calloc(1, sizeof(Line_Type));
1677         gesture->data = st;
1678      }
1679
1680    Line_Data *line = NULL;
1681    Eina_List *list = st->list;
1682    unsigned int i, cnt = eina_list_count(list);
1683
1684    if (cnt)
1685      {  /* list is not empty, locate this device on list */
1686         line = (Line_Data *) eina_list_search_unsorted(st->list,
1687               compare_line_device, &pe->device);
1688
1689         if (!line)
1690           {  /* Try to locate an empty-node */
1691              for (i = 0; i < cnt; i++)
1692                {
1693                   line = eina_list_nth(list, i);
1694                   if (!line->t_st)
1695                     break; /* Found a free node */
1696
1697                   line = NULL;
1698                }
1699           }
1700      }
1701
1702    if (!line)
1703      {  /* List is empty or device not found, new line-struct on START only */
1704         if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1705               (event_type == EVAS_CALLBACK_MULTI_DOWN))
1706           {  /* Allocate new item on START */
1707              line = calloc(1, sizeof(Line_Data));
1708              _line_data_reset(line);
1709              list = eina_list_append(list, line);
1710              st->list = list;
1711           }
1712      }
1713
1714    if (!line)  /* This may happen on MOVE that comes before DOWN      */
1715      return;   /* No line-struct to work with, can't continue testing */
1716
1717
1718    if (_single_line_process(&st->info, line, pe)) /* update st with input */
1719      consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_NONE);
1720
1721    /* Get direction and magnitude of the line */
1722    double angle;
1723    get_vector(line->line_st.x, line->line_st.y, pe->x, pe->y,
1724          &line->line_length, &angle);
1725
1726    /* These are used later to compare lines length */
1727    Evas_Coord shortest_line_len = line->line_length;
1728    Evas_Coord longest_line_len = line->line_length;
1729    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
1730
1731    /* Now update line-state */
1732    if (line->t_st)
1733      {  /* Analyze line only if line started */
1734         if (line->line_angle >= 0.0)
1735           {  /* if line direction was set, we test if broke tolerance */
1736              double a = fabs(angle - line->line_angle);
1737
1738              double d = (tan(a)) * line->line_length; /* Distance from line */
1739 #if defined(DEBUG_GESTURE_LAYER)
1740              printf("%s a=<%f> d=<%f>\n", __func__, (a * 57.295779513), d);
1741 #endif
1742              if ((d > wd->line_distance_tolerance) || (a > wd->line_angular_tolerance))
1743                {  /* Broke tolerance: abort line and start a new one */
1744                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1745                         &st->info, EINA_FALSE);
1746                   consume_event(wd, event_info, event_type, ev_flag);
1747                   return;
1748                }
1749           }
1750         else
1751           {  /* Record the line angle as it broke minimum length for line */
1752              if (line->line_length >= wd->line_min_length)
1753                st->info.angle = line->line_angle = angle;
1754           }
1755
1756         if (line->t_end)
1757           {
1758              if (line->line_angle < 0.0)
1759                { /* it's not a line, too short more close to a tap */
1760                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
1761                         &st->info, EINA_FALSE);
1762                   consume_event(wd, event_info, event_type, ev_flag);
1763                   return;
1764                }
1765           }
1766      }
1767
1768    /* Count how many lines already started / ended */
1769    int started = 0;
1770    int ended = 0;
1771    unsigned int tm_start = pe->timestamp;
1772    unsigned int tm_end = pe->timestamp;
1773    Eina_List *l;
1774    Line_Data *t_line;
1775    double base_angle = ELM_GESTURE_NEGATIVE_ANGLE;
1776    Eina_Bool lines_parallel = EINA_TRUE;
1777    EINA_LIST_FOREACH(list, l, t_line)
1778      {
1779         if (base_angle < 0)
1780           base_angle = t_line->line_angle;
1781         else
1782           {
1783              if (t_line->line_angle >= 0)
1784                {  /* Compare angle only with lines with direction defined */
1785                   if (fabs(base_angle - t_line->line_angle) >
1786                         wd->line_angular_tolerance)
1787                     lines_parallel = EINA_FALSE;
1788                }
1789           }
1790
1791         if (t_line->line_length)
1792           {  /* update only if this line is used */
1793              if (shortest_line_len > t_line->line_length)
1794                shortest_line_len = t_line->line_length;
1795
1796              if (longest_line_len < t_line->line_length)
1797                longest_line_len = t_line->line_length;
1798           }
1799
1800         if (t_line->t_st)
1801           {
1802              started++;
1803              if (t_line->t_st < tm_start)
1804                tm_start = t_line->t_st;
1805           }
1806
1807         if (t_line->t_end)
1808           {
1809              ended++;
1810              if (t_line->t_end < tm_end)
1811                tm_end = t_line->t_end;
1812           }
1813      }
1814
1815    st->info.n = started;
1816
1817
1818    if (ended &&
1819          ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
1820           (event_type == EVAS_CALLBACK_MULTI_DOWN)))
1821      {  /* user lift one finger then starts again without line-end - ABORT */
1822         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1823               EINA_FALSE);
1824         consume_event(wd, event_info, event_type, ev_flag);
1825         return;
1826      }
1827
1828    if (!lines_parallel)
1829      { /* Lines are NOT at same direction, abort this gesture */
1830         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1831               EINA_FALSE);
1832         consume_event(wd, event_info, event_type, ev_flag);
1833         return;
1834      }
1835
1836
1837    /* We report ABORT if lines length are NOT matching when fingers are up */
1838    if ((longest_line_len - shortest_line_len) > (elm_finger_size_get()*2))
1839      {
1840         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1841               EINA_FALSE);
1842         consume_event(wd, event_info, event_type, ev_flag);
1843         return;
1844      }
1845
1846    if ((g_type == ELM_GESTURE_N_FLICKS) && ((tm_end - tm_start) > wd->flick_time_limit_ms))
1847      {  /* We consider FLICK as a fast line.ABORT if take too long to finish */
1848         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
1849               EINA_FALSE);
1850         consume_event(wd, event_info, event_type, ev_flag);
1851         return;
1852      }
1853
1854    switch (event_type)
1855      {
1856       case EVAS_CALLBACK_MOUSE_UP:
1857       case EVAS_CALLBACK_MULTI_UP:
1858          if ((started) && (started == ended))
1859            {
1860               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
1861                     &st->info, EINA_FALSE);
1862               consume_event(wd, event_info, event_type, ev_flag);
1863            }
1864
1865          return;
1866
1867       case EVAS_CALLBACK_MOUSE_DOWN:
1868       case EVAS_CALLBACK_MULTI_DOWN:
1869          if (started)
1870            {
1871               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
1872                     &st->info, EINA_TRUE);
1873               consume_event(wd, event_info, event_type, ev_flag);
1874            }
1875
1876          break;
1877
1878       case EVAS_CALLBACK_MOUSE_MOVE:
1879       case EVAS_CALLBACK_MULTI_MOVE:
1880          if (started)
1881            {
1882               ev_flag = _set_state(gesture, ELM_GESTURE_STATE_MOVE,
1883                  &st->info, EINA_TRUE);
1884               consume_event(wd, event_info, event_type, ev_flag);
1885            }
1886
1887          break;
1888
1889       default:
1890          return;  /* Unhandeld event type */
1891      }
1892 }
1893
1894 /**
1895  * @internal
1896  *
1897  * This function is used to check if rotation gesture started.
1898  * @param st Contains current rotation values from user input.
1899  * @return TRUE/FALSE if we need to set rotation START.
1900  *
1901  * @ingroup Elm_Gesture_Layer
1902  */
1903 static Eina_Bool
1904 rotation_broke_tolerance(Rotate_Type *st)
1905 {
1906    if (st->info.base_angle < 0)
1907      return EINA_FALSE; /* Angle has to be computed first */
1908
1909    if (st->rotate_angular_tolerance < 0)
1910      return EINA_TRUE;
1911
1912    double low  = st->info.base_angle - st->rotate_angular_tolerance;
1913    double high = st->info.base_angle + st->rotate_angular_tolerance;
1914    double t = st->info.angle;
1915
1916    if (low < 0)
1917      {
1918         low += RAD_180DEG;
1919         high += RAD_180DEG;
1920
1921         if (t < RAD_180DEG)
1922           t += RAD_180DEG;
1923         else
1924           t -= RAD_180DEG;
1925      }
1926
1927    if (high > RAD_360DEG)
1928      {
1929         low -= RAD_180DEG;
1930         high -= RAD_180DEG;
1931
1932         if (t < RAD_180DEG)
1933           t += RAD_180DEG;
1934         else
1935           t -= RAD_180DEG;
1936      }
1937
1938 #if defined(DEBUG_GESTURE_LAYER)
1939    printf("%s angle=<%d> low=<%d> high=<%d>\n", __func__, t, low, high);
1940 #endif
1941    if ((t < low) || (t > high))
1942      {  /* This marks that roation action has started */
1943         st->rotate_angular_tolerance = ELM_GESTURE_NEGATIVE_ANGLE;
1944         st->info.base_angle = st->info.angle; /* Avoid jump in angle value */
1945         return EINA_TRUE;
1946      }
1947
1948    return EINA_FALSE;
1949 }
1950
1951 /**
1952  * @internal
1953  *
1954  * This function is used for computing the gap between fingers.
1955  * It returns the length and center point between fingers.
1956  *
1957  * @param x1 first finger x location.
1958  * @param y1 first finger y location.
1959  * @param x2 second finger x location.
1960  * @param y2 second finger y location.
1961  * @param x  Gets center point x cord (output)
1962  * @param y  Gets center point y cord (output)
1963  *
1964  * @return length of the line between (x1,y1), (x2,y2) in pixels.
1965  *
1966  * @ingroup Elm_Gesture_Layer
1967  */
1968 static Evas_Coord
1969 get_finger_gap_length(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2,
1970       Evas_Coord y2, Evas_Coord *x, Evas_Coord *y)
1971 {
1972    double a, b, xx, yy, gap;
1973    xx = fabs(x2 - x1);
1974    yy = fabs(y2 - y1);
1975    gap = sqrt(xx*xx + yy*yy);
1976
1977    /* START - Compute zoom center point */
1978    /* The triangle defined as follows:
1979     *             B
1980     *           / |
1981     *          /  |
1982     *     gap /   | a
1983     *        /    |
1984     *       A-----C
1985     *          b
1986     * http://en.wikipedia.org/wiki/Trigonometric_functions
1987     *************************************/
1988    if (((int) xx) && ((int) yy))
1989      {
1990         double A = atan((yy / xx));
1991 #if defined(DEBUG_GESTURE_LAYER)
1992         printf("xx=<%f> yy=<%f> A=<%f>\n", xx, yy, A);
1993 #endif
1994         a = (Evas_Coord) ((gap / 2) * sin(A));
1995         b = (Evas_Coord) ((gap / 2) * cos(A));
1996         *x = (Evas_Coord) ((x2 > x1) ? (x1 + b) : (x2 + b));
1997         *y = (Evas_Coord) ((y2 > y1) ? (y1 + a) : (y2 + a));
1998      }
1999    else
2000      {
2001         if ((int) xx)
2002           {  /* horiz line, take half width */
2003 #if defined(DEBUG_GESTURE_LAYER)
2004              printf("==== HORIZ ====\n");
2005 #endif
2006              *x = (Evas_Coord) (xx / 2);
2007              *y = (Evas_Coord) (y1);
2008           }
2009
2010         if ((int) yy)
2011           {  /* vert line, take half width */
2012 #if defined(DEBUG_GESTURE_LAYER)
2013              printf("==== VERT ====\n");
2014 #endif
2015              *x = (Evas_Coord) (x1);
2016              *y = (Evas_Coord) (yy / 2);
2017           }
2018      }
2019    /* END   - Compute zoom center point */
2020
2021    return (Evas_Coord) gap;
2022 }
2023
2024 /**
2025  * @internal
2026  *
2027  * This function is used for computing zoom value.
2028  *
2029  * @param st Pointer to zoom data based on user input.
2030  * @param x1 first finger x location.
2031  * @param y1 first finger y location.
2032  * @param x2 second finger x location.
2033  * @param y2 second finger y location.
2034  * @param factor zoom-factor, used to determine how fast zoom works.
2035  *
2036  * @return zoom value, when 1.0 means no zoom, 0.5 half size...
2037  *
2038  * @ingroup Elm_Gesture_Layer
2039  */
2040 /* FIXME change float to double */
2041 static double
2042 compute_zoom(Zoom_Type *st, Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2043       Evas_Coord x2, Evas_Coord y2, unsigned int tm2, double zoom_finger_factor)
2044 {
2045    double rt = 1.0;
2046    Evas_Coord diam = get_finger_gap_length(x1, y1, x2, y2,
2047          &st->info.x, &st->info.y);
2048
2049    st->info.radius = diam / 2;
2050
2051    if (!st->zoom_base)
2052      {
2053         st->zoom_base = diam;
2054         return st->info.zoom;
2055      }
2056
2057    if (st->zoom_distance_tolerance)
2058      {  /* zoom tolerance <> ZERO, means zoom action NOT started yet */
2059         if (diam < (st->zoom_base - st->zoom_distance_tolerance))
2060           {  /* avoid jump with zoom value when break tolerance */
2061              st->zoom_base -= st->zoom_distance_tolerance;
2062              st->zoom_distance_tolerance = 0;
2063           }
2064
2065         if (diam > (st->zoom_base + st->zoom_distance_tolerance))
2066           {  /* avoid jump with zoom value when break tolerance */
2067              st->zoom_base += st->zoom_distance_tolerance;
2068              st->zoom_distance_tolerance = 0;
2069           }
2070
2071         return rt;
2072      }
2073
2074    /* We use factor only on the difference between gap-base   */
2075    /* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
2076    rt = ((1.0) + ((((float) diam - (float) st->zoom_base) /
2077                (float) st->zoom_base) * zoom_finger_factor));
2078
2079 #if 0
2080    /* Momentum: zoom per second: (NOT YET SUPPORTED) */
2081    st->info.momentum = (((rt - 1.0) * 1000) / (tm2 - tm1));
2082 #else
2083    (void) tm1;
2084    (void) tm2;
2085 #endif
2086    return rt;
2087 }
2088
2089 /**
2090  * @internal
2091  *
2092  * This function handles zoom with mouse wheel.
2093  * thats a combination of wheel + CTRL key.
2094  * @param obj The gesture-layer object.
2095  * @param event_info Original input event pointer.
2096  * @param event_type Type of original input event.
2097  * @param g_type what Gesture we are testing.
2098  *
2099  * @ingroup Elm_Gesture_Layer
2100  */
2101 static void
2102 _zoom_with_wheel_test(Evas_Object *obj, void *event_info,
2103       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2104 {
2105    Widget_Data *wd = elm_widget_data_get(obj);
2106    if (!wd) return;
2107    if (!wd->gesture[g_type]) return;
2108
2109    Gesture_Info *gesture_zoom = wd->gesture[g_type];
2110    Zoom_Type *st = gesture_zoom->data;
2111    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2112    if (!st)
2113      {  /* Allocated once on first time, used for zoom intermediate data */
2114         st = calloc(1, sizeof(Zoom_Type));
2115         gesture_zoom->data = st;
2116         _zoom_test_reset(gesture_zoom);
2117      }
2118
2119    switch (event_type)
2120      {
2121       case EVAS_CALLBACK_KEY_UP:
2122            {
2123               Evas_Event_Key_Up *p = event_info;
2124               if ((!strcmp(p->keyname, "Control_L")) ||
2125                     (!strcmp(p->keyname, "Control_R")))
2126                 {  /* Test if we ended a zoom gesture when releasing CTRL */
2127                    if ((st->zoom_wheel) &&
2128                          ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2129                           (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2130                      {  /* User released CTRL after zooming */
2131                         ev_flag = _set_state(gesture_zoom,
2132                               ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2133                         consume_event(wd, event_info, event_type, ev_flag);
2134
2135                         return;
2136                      }
2137                 }
2138               break;
2139            }
2140
2141       case EVAS_CALLBACK_MOUSE_WHEEL:
2142            {
2143               Eina_Bool force;
2144               Elm_Gesture_State s;
2145               if (!evas_key_modifier_is_set(
2146                        ((Evas_Event_Mouse_Wheel *) event_info)->modifiers,
2147                        "Control"))
2148                 {  /* if using wheel witout CTRL after starting zoom */
2149                    if ((st->zoom_wheel) &&
2150                          ((gesture_zoom->state == ELM_GESTURE_STATE_START) ||
2151                           (gesture_zoom->state == ELM_GESTURE_STATE_MOVE)))
2152                      {
2153                         ev_flag = _set_state(gesture_zoom,
2154                               ELM_GESTURE_STATE_END, &st->info, EINA_FALSE);
2155                         consume_event(wd, event_info, event_type, ev_flag);
2156
2157                         return;
2158                      }
2159                    else
2160                      return; /* Ignore mouse-wheel without control */
2161                 }
2162
2163               /* Using mouse wheel with CTRL for zoom */
2164               if (st->zoom_wheel || (st->zoom_distance_tolerance == 0))
2165                 {  /* when (zoom_wheel == NULL) and (zoom_distance_tolerance == 0)
2166                       we continue a zoom gesture */
2167                    force = EINA_TRUE;
2168                    s = ELM_GESTURE_STATE_MOVE;
2169                 }
2170               else
2171                 {  /* On first wheel event, report START */
2172                    force = EINA_FALSE;
2173                    s = ELM_GESTURE_STATE_START;
2174                 }
2175
2176               st->zoom_distance_tolerance = 0; /* Cancel tolerance */
2177               st->zoom_wheel = (Evas_Event_Mouse_Wheel *) event_info;
2178               st->info.x  = st->zoom_wheel->canvas.x;
2179               st->info.y  = st->zoom_wheel->canvas.y;
2180
2181               if (st->zoom_wheel->z > 0) /* zoom in */
2182                 st->info.zoom += (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2183
2184               if (st->zoom_wheel->z < 0) /* zoom out */
2185                 st->info.zoom -= (wd->zoom_finger_factor * wd->zoom_wheel_factor);
2186
2187               if (st->info.zoom < 0.0)
2188                 st->info.zoom = 0.0;
2189
2190               ev_flag = _set_state(gesture_zoom, s, &st->info, force);
2191               consume_event(wd, event_info, event_type, ev_flag);
2192               break;
2193            }
2194
2195       default:
2196            return;
2197      }
2198 }
2199
2200 /**
2201  * @internal
2202  *
2203  * This function is used to test zoom gesture.
2204  * user may combine zoom, rotation together.
2205  * so its possible that both will be detected from input.
2206  * (both are two-finger movement-oriented gestures)
2207  *
2208  * @param obj The gesture-layer object.
2209  * @param event_info Pointer to recent input event.
2210  * @param event_type Recent input event type.
2211  * @param g_type what Gesture we are testing.
2212  *
2213  * @ingroup Elm_Gesture_Layer
2214  */
2215 static void
2216 _zoom_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2217       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2218 {
2219    if (!pe)
2220      return;
2221    Widget_Data *wd = elm_widget_data_get(obj);
2222    if (!wd) return;
2223    if (!wd->gesture[g_type]) return;
2224
2225    Gesture_Info *gesture_zoom = wd->gesture[g_type];
2226    Zoom_Type *st = gesture_zoom->data;
2227
2228    if (!st)
2229      {  /* Allocated once on first time, used for zoom data */
2230         st = calloc(1, sizeof(Zoom_Type));
2231         gesture_zoom->data = st;
2232         _zoom_test_reset(gesture_zoom);
2233      }
2234
2235    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2236    switch (event_type)
2237      {
2238       case EVAS_CALLBACK_MOUSE_DOWN:
2239          consume_event(wd, event_info, event_type, ev_flag);
2240          memcpy(&st->zoom_st, pe, sizeof(Pointer_Event));
2241
2242          break;
2243
2244       case EVAS_CALLBACK_MOUSE_MOVE:
2245          consume_event(wd, event_info, event_type, ev_flag);
2246          if (!st->zoom_st.timestamp)
2247            return;  /* we got move event before down event.Ignore it */
2248
2249          consume_event(wd, event_info, event_type, ev_flag);
2250          memcpy(&st->zoom_mv, pe, sizeof(Pointer_Event));
2251
2252          /* We match this point to previous multi-move or multi-down event */
2253          if (st->zoom_mv1.timestamp)
2254            {
2255               st->info.zoom = compute_zoom(st,
2256                     st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2257                     st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2258                     wd->zoom_finger_factor);
2259               break;
2260            }
2261
2262          if (st->zoom_st1.timestamp)
2263            {
2264               st->info.zoom = compute_zoom(st,
2265                     st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2266                     st->zoom_st1.x, st->zoom_st1.y, st->zoom_st1.timestamp,
2267                     wd->zoom_finger_factor);
2268               break;
2269            }
2270
2271          break;
2272
2273       case EVAS_CALLBACK_MULTI_MOVE:
2274            if (!st->zoom_st1.timestamp)
2275              return;  /* We get move event before down event.Ignore it */
2276
2277            consume_event(wd, event_info, event_type, ev_flag);
2278            if (st->zoom_mv1.timestamp)
2279              {
2280              if (st->zoom_mv1.device !=
2281                    ((Evas_Event_Multi_Move *) event_info)->device)
2282                {  /* A third finger on screen, abort zoom */
2283                   ev_flag = _set_state(gesture_zoom,
2284                         ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2285                   consume_event(wd, event_info, event_type, ev_flag);
2286
2287                   return;
2288                }
2289              }
2290
2291            memcpy(&st->zoom_mv1, pe, sizeof(Pointer_Event));
2292
2293            /* Match this point to previous mouse-move or mouse-down event */
2294            if (st->zoom_mv.timestamp)
2295              {
2296                 st->info.zoom = compute_zoom(st,
2297                       st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2298                       st->zoom_mv.x, st->zoom_mv.y, st->zoom_mv.timestamp,
2299                       wd->zoom_finger_factor);
2300                 break;
2301              }
2302
2303            if (st->zoom_st.timestamp)
2304              {
2305                 st->info.zoom = compute_zoom(st,
2306                       st->zoom_mv1.x, st->zoom_mv1.y, st->zoom_mv1.timestamp,
2307                       st->zoom_st.x, st->zoom_st.y, st->zoom_st.timestamp,
2308                       wd->zoom_finger_factor);
2309                 break;
2310              }
2311
2312            break;
2313
2314       case EVAS_CALLBACK_MULTI_DOWN:
2315            consume_event(wd, event_info, event_type, ev_flag);
2316            memcpy(&st->zoom_st1, pe, sizeof(Pointer_Event));
2317            break;
2318
2319       case EVAS_CALLBACK_MOUSE_UP:
2320       case EVAS_CALLBACK_MULTI_UP:
2321            /* Reset timestamp of finger-up.This is used later
2322               by _zoom_test_reset() to retain finger-down data */
2323            consume_event(wd, event_info, event_type, ev_flag);
2324            if (((st->zoom_wheel) || (st->zoom_base)) &&
2325                  (st->zoom_distance_tolerance == 0))
2326              {
2327                 ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_END,
2328                       &st->info, EINA_FALSE);
2329                 consume_event(wd, event_info, event_type, ev_flag);
2330
2331                 return;
2332              }
2333
2334            /* if we got here not a ZOOM */
2335            if (gesture_zoom->state != ELM_GESTURE_STATE_UNDEFINED)
2336              {  /* Must be != undefined, if gesture started */
2337                 ev_flag = _set_state(gesture_zoom,
2338                       ELM_GESTURE_STATE_ABORT, &st->info, EINA_FALSE);
2339                 consume_event(wd, event_info, event_type, ev_flag);
2340              }
2341
2342            _zoom_test_reset(gesture_zoom);
2343
2344            return;
2345
2346       default:
2347            return;
2348      }
2349
2350
2351    if (!st->zoom_distance_tolerance)
2352      if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2353            (event_type == EVAS_CALLBACK_MULTI_MOVE))
2354        {
2355             {  /* Zoom broke tolerance, report move */
2356                double d = st->info.zoom - st->next_step;
2357                if (d < 0.0)
2358                  d = (-d);
2359
2360                if (d >= wd->zoom_step)
2361                  {  /* Report move in steps */
2362                     st->next_step = st->info.zoom;
2363
2364                     ev_flag = _set_state(gesture_zoom, ELM_GESTURE_STATE_MOVE,
2365                           &st->info, EINA_TRUE);
2366                     consume_event(wd, event_info, event_type, ev_flag);
2367                  }
2368             }
2369
2370           return;
2371        }
2372
2373    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2374          (event_type == EVAS_CALLBACK_MULTI_DOWN))
2375      {  /* report zoom start finger location is zoom-center temporarly */
2376         /* Zoom may have started with mouse-wheel, don't report START  */
2377         if ((st->zoom_st.timestamp) && (st->zoom_st1.timestamp))
2378           {  /* Set zoom-base after BOTH down events were recorded   */
2379              /* Compute length of line between fingers on zoom start */
2380              st->info.zoom = 1.0;
2381              st->zoom_base = get_finger_gap_length(st->zoom_st1.x,
2382                       st->zoom_st1.y, st->zoom_st.x,  st->zoom_st.y,
2383                       &st->info.x, &st->info.y);
2384
2385              st->info.radius = st->zoom_base / 2;
2386
2387              if ((gesture_zoom->state != ELM_GESTURE_STATE_START) &&
2388                    (gesture_zoom->state != ELM_GESTURE_STATE_MOVE))
2389                {  /* Report START only when two fingers touching */
2390                   ev_flag = _set_state(gesture_zoom,
2391                         ELM_GESTURE_STATE_START, &st->info, EINA_FALSE);
2392                   consume_event(wd, event_info, event_type, ev_flag);
2393                }
2394           }
2395      }
2396
2397    return;
2398 }
2399
2400 static void
2401 _get_rotate_properties(Rotate_Type *st,
2402       Evas_Coord x1, Evas_Coord y1, unsigned int tm1,
2403       Evas_Coord x2, Evas_Coord y2, unsigned int tm2,
2404       double *angle)
2405 {
2406    st->info.radius = get_finger_gap_length(x1, y1, x2, y2,
2407          &st->info.x, &st->info.y) / 2;
2408
2409    *angle = get_angle(x1, y1, x2, y2);
2410 #if 0 /* (NOT YET SUPPORTED) */
2411    if (angle == &st->info.angle)
2412      {  /* Compute momentum: TODO: bug when breaking 0, 360 values */
2413         st->info.momentum = (((*angle) - st->info.base_angle) /
2414            (fabs(tm2 - tm1))) * 1000;
2415      }
2416    else
2417      st->info.momentum = 0;
2418 #else
2419    (void) tm1;
2420    (void) tm2;
2421 #endif
2422 }
2423
2424 /**
2425  * @internal
2426  *
2427  * This function is used to test rotation gesture.
2428  * user may combine zoom, rotation together.
2429  * so its possible that both will be detected from input.
2430  * (both are two-finger movement-oriented gestures)
2431  *
2432  * @param obj The gesture-layer object.
2433  * @param event_info Pointer to recent input event.
2434  * @param event_type Recent input event type.
2435  * @param g_type what Gesture we are testing.
2436  *
2437  * @ingroup Elm_Gesture_Layer
2438  */
2439 static void
2440 _rotate_test(Evas_Object *obj, Pointer_Event *pe, void *event_info,
2441       Evas_Callback_Type event_type, Elm_Gesture_Types g_type)
2442 {
2443    if (!pe)
2444      return;
2445
2446    Widget_Data *wd = elm_widget_data_get(obj);
2447    if (!wd) return;
2448    if (!wd->gesture[g_type]) return;
2449
2450    Gesture_Info *gesture = wd->gesture[g_type];
2451    Rotate_Type *st = gesture->data;
2452    if (gesture)
2453    {
2454       st = gesture->data;
2455       if (!st)
2456         {  /* Allocated once on first time */
2457            st = calloc(1, sizeof(Rotate_Type));
2458            gesture->data = st;
2459            _rotate_test_reset(gesture);
2460         }
2461    }
2462
2463    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
2464
2465    switch (event_type)
2466      {
2467       case EVAS_CALLBACK_MOUSE_DOWN:
2468          consume_event(wd, event_info, event_type, ev_flag);
2469          memcpy(&st->rotate_st, pe, sizeof(Pointer_Event));
2470
2471            break;
2472
2473       case EVAS_CALLBACK_MOUSE_MOVE:
2474          if (!st->rotate_st.timestamp)
2475            break;  /* We got move event before down event.Ignore it */
2476
2477          consume_event(wd, event_info, event_type, ev_flag);
2478          memcpy(&st->rotate_mv, pe, sizeof(Pointer_Event));
2479
2480          /* Match this point to previous multi-move or multi-down event */
2481          if (st->rotate_mv1.timestamp)
2482              {  /* Compute rotation angle and report to user */
2483                 _get_rotate_properties(st,
2484                       st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2485                       st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2486                       &st->info.angle);
2487                 break;
2488              }
2489
2490            if (st->rotate_st1.timestamp)
2491              {  /* Compute rotation angle and report to user */
2492                 _get_rotate_properties(st,
2493                       st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2494                       st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2495                       &st->info.angle);
2496                 break;
2497              }
2498
2499            return;
2500
2501       case EVAS_CALLBACK_MULTI_MOVE:
2502            if (!st->rotate_st1.timestamp)
2503              break;  /* We got move event before down event.Ignore it */
2504
2505            consume_event(wd, event_info, event_type, ev_flag);
2506            if (st->rotate_mv1.timestamp)
2507              {
2508              if (st->rotate_mv1.device !=
2509                    ((Evas_Event_Multi_Move *) event_info)->device)
2510                {  /* A third finger on screen, abort rotate */
2511                   ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2512                         &st->info, EINA_FALSE);
2513                   consume_event(wd, event_info, event_type, ev_flag);
2514
2515                   return;
2516                }
2517              }
2518
2519            memcpy(&st->rotate_mv1, pe, sizeof(Pointer_Event));
2520
2521            /* Match this point to previous mouse-move or mouse-down event */
2522            if (st->rotate_mv.timestamp)
2523              {  /* Compute rotation angle and report to user */
2524                 _get_rotate_properties(st,
2525                       st->rotate_mv.x, st->rotate_mv.y, st->rotate_mv.timestamp,
2526                       st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2527                       &st->info.angle);
2528                 break;
2529              }
2530
2531            if (st->rotate_st.timestamp)
2532              {  /* Compute rotation angle and report to user */
2533                 _get_rotate_properties(st,
2534                       st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2535                       st->rotate_mv1.x, st->rotate_mv1.y, st->rotate_mv1.timestamp,
2536                       &st->info.angle);
2537                 break;
2538              }
2539
2540            return;
2541
2542       case EVAS_CALLBACK_MULTI_DOWN:
2543            consume_event(wd, event_info, event_type, ev_flag);
2544            memcpy(&st->rotate_st1, pe, sizeof(Pointer_Event));
2545            _get_rotate_properties(st,
2546                  st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2547                  st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2548                  &st->info.angle);
2549            break;
2550
2551       case EVAS_CALLBACK_MOUSE_UP:
2552       case EVAS_CALLBACK_MULTI_UP:
2553            consume_event(wd, event_info, event_type, ev_flag);
2554            /* Reset timestamp of finger-up.This is used later
2555               by rotate_test_reset() to retain finger-down data */
2556            if (st->rotate_angular_tolerance < 0)
2557              {
2558                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END,
2559                       &st->info, EINA_FALSE);
2560                 consume_event(wd, event_info, event_type, ev_flag);
2561
2562                 return;
2563              }
2564
2565            if (gesture->state != ELM_GESTURE_STATE_UNDEFINED)
2566              {  /* Must be != undefined, if gesture started */
2567                 ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT,
2568                       &st->info, EINA_FALSE);
2569                 consume_event(wd, event_info, event_type, ev_flag);
2570              }
2571
2572            _rotate_test_reset(gesture);
2573            return;
2574
2575       default:
2576            return;
2577      }
2578
2579    if ((event_type == EVAS_CALLBACK_MOUSE_MOVE) ||
2580          (event_type == EVAS_CALLBACK_MULTI_MOVE))
2581      {  /* Report MOVE or ABORT for *MOVE event */
2582         if (rotation_broke_tolerance(st))
2583           {  /* Rotation broke tolerance, report move */
2584              double d = st->info.angle - st->next_step;
2585              if (d < 0.0)
2586                d = (-d);
2587
2588              if (d >= wd->rotate_step)
2589                {  /* Report move in steps */
2590                   st->next_step = st->info.angle;
2591
2592                   ev_flag = _set_state(gesture,
2593                         ELM_GESTURE_STATE_MOVE, &st->info, EINA_TRUE);
2594                   consume_event(wd, event_info, event_type, ev_flag);
2595                }
2596           }
2597
2598         return;
2599      }
2600
2601    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2602          (event_type == EVAS_CALLBACK_MULTI_DOWN))
2603      {
2604         if ((st->rotate_st.timestamp) && (st->rotate_st1.timestamp))
2605           {  /* two-fingers on touch screen - report rotate start */
2606              /* Set base angle, then report start.                */
2607              _get_rotate_properties(st,
2608                    st->rotate_st.x, st->rotate_st.y, st->rotate_st.timestamp,
2609                    st->rotate_st1.x, st->rotate_st1.y, st->rotate_st1.timestamp,
2610                    &st->info.base_angle);
2611
2612              ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
2613                    &st->info, EINA_FALSE);
2614              consume_event(wd, event_info, event_type, ev_flag);
2615           }
2616      }
2617
2618    return;
2619 }
2620
2621 /**
2622  * @internal
2623  *
2624  * This function is used to save input events in an abstract struct
2625  * to be used later by getsure-testing functions.
2626  *
2627  * @param data The gesture-layer object.
2628  * @param event_info Pointer to recent input event.
2629  * @param event_type Recent input event type.
2630  * @param pe The abstract data-struct (output).
2631  *
2632  * @ingroup Elm_Gesture_Layer
2633  */
2634 static Eina_Bool
2635 _make_pointer_event(void *data, void *event_info,
2636       Evas_Callback_Type event_type, Pointer_Event *pe)
2637 {
2638    Widget_Data *wd = elm_widget_data_get(data);
2639    if (!wd) return EINA_FALSE;
2640
2641    switch (event_type)
2642      {
2643       case EVAS_CALLBACK_MOUSE_DOWN:
2644            pe->x = ((Evas_Event_Mouse_Down *) event_info)->canvas.x;
2645            pe->y = ((Evas_Event_Mouse_Down *) event_info)->canvas.y;
2646            pe->timestamp = ((Evas_Event_Mouse_Down *) event_info)->timestamp;
2647            pe->device = ELM_MOUSE_DEVICE;
2648            break;
2649
2650       case EVAS_CALLBACK_MOUSE_UP:
2651            pe->x = ((Evas_Event_Mouse_Up *) event_info)->canvas.x;
2652            pe->y = ((Evas_Event_Mouse_Up *) event_info)->canvas.y;
2653            pe->timestamp = ((Evas_Event_Mouse_Up *) event_info)->timestamp;
2654            pe->device = ELM_MOUSE_DEVICE;
2655            break;
2656
2657       case EVAS_CALLBACK_MOUSE_MOVE:
2658            pe->x = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.x;
2659            pe->y = ((Evas_Event_Mouse_Move *) event_info)->cur.canvas.y;
2660            pe->timestamp = ((Evas_Event_Mouse_Move *) event_info)->timestamp;
2661            pe->device = ELM_MOUSE_DEVICE;
2662            break;
2663
2664       case EVAS_CALLBACK_MULTI_DOWN:
2665            pe->x = ((Evas_Event_Multi_Down *) event_info)->canvas.x;
2666            pe->y = ((Evas_Event_Multi_Down *) event_info)->canvas.y;
2667            pe->timestamp = ((Evas_Event_Multi_Down *) event_info)->timestamp;
2668            pe->device = ((Evas_Event_Multi_Down *) event_info)->device;
2669            break;
2670
2671       case EVAS_CALLBACK_MULTI_UP:
2672            pe->x = ((Evas_Event_Multi_Up *) event_info)->canvas.x;
2673            pe->y = ((Evas_Event_Multi_Up *) event_info)->canvas.y;
2674            pe->timestamp = ((Evas_Event_Multi_Up *) event_info)->timestamp;
2675            pe->device = ((Evas_Event_Multi_Up *) event_info)->device;
2676            break;
2677
2678       case EVAS_CALLBACK_MULTI_MOVE:
2679            pe->x = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.x;
2680            pe->y = ((Evas_Event_Multi_Move *) event_info)->cur.canvas.y;
2681            pe->timestamp = ((Evas_Event_Multi_Move *) event_info)->timestamp;
2682            pe->device = ((Evas_Event_Multi_Move *) event_info)->device;
2683            break;
2684
2685       default:
2686            return EINA_FALSE;
2687      }
2688
2689    pe->event_type = event_type;
2690    return EINA_TRUE;
2691 }
2692
2693 /**
2694  * @internal
2695  *
2696  * This function the core-function where input handling is done.
2697  * Here we get user input and stream it to gesture testing.
2698  * We notify user about any gestures with new state:
2699  * Valid states are:
2700  * START - gesture started.
2701  * MOVE - gesture is ongoing.
2702  * END - gesture was completed.
2703  * ABORT - gesture was aborted after START, MOVE (will NOT be completed)
2704  *
2705  * We also check if a gesture was detected, then reset event history
2706  * If no gestures were found we reset gesture test flag
2707  * after streaming event-history to widget.
2708  * (stream to the widget all events not consumed as a gesture)
2709  *
2710  * @param data The gesture-layer object.
2711  * @param event_info Pointer to recent input event.
2712  * @param event_type Recent input event type.
2713  *
2714  * @ingroup Elm_Gesture_Layer
2715  */
2716 static void
2717 _event_process(void *data, Evas_Object *obj __UNUSED__,
2718       void *event_info, Evas_Callback_Type event_type)
2719 {
2720    Pointer_Event _pe;
2721    Pointer_Event *pe = NULL;
2722    Widget_Data *wd = elm_widget_data_get(data);
2723    if (!wd) return;
2724
2725    /* Start testing candidate gesture from here */
2726    if (_make_pointer_event(data, event_info, event_type, &_pe))
2727      pe = &_pe;
2728
2729    if (IS_TESTED(ELM_GESTURE_N_TAPS))
2730      _dbl_click_test(data, pe, event_info, event_type,
2731            ELM_GESTURE_N_TAPS, 1);
2732
2733    if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS))
2734      _dbl_click_test(data, pe, event_info, event_type,
2735            ELM_GESTURE_N_DOUBLE_TAPS, 2);
2736
2737    if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS))
2738      _dbl_click_test(data, pe, event_info, event_type,
2739            ELM_GESTURE_N_TRIPLE_TAPS, 3);
2740
2741    if (IS_TESTED(ELM_GESTURE_MOMENTUM))
2742      _momentum_test(data, pe, event_info, event_type,
2743            ELM_GESTURE_MOMENTUM);
2744
2745    if (IS_TESTED(ELM_GESTURE_N_LINES))
2746      _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_LINES);
2747
2748    if (IS_TESTED(ELM_GESTURE_N_FLICKS))
2749      _n_line_test(data, pe, event_info, event_type, ELM_GESTURE_N_FLICKS);
2750
2751    if (IS_TESTED(ELM_GESTURE_ZOOM))
2752      _zoom_test(data, pe, event_info, event_type, ELM_GESTURE_ZOOM);
2753
2754    if (IS_TESTED(ELM_GESTURE_ZOOM))
2755      _zoom_with_wheel_test(data, event_info, event_type, ELM_GESTURE_ZOOM);
2756
2757    if (IS_TESTED(ELM_GESTURE_ROTATE))
2758      _rotate_test(data, pe, event_info, event_type, ELM_GESTURE_ROTATE);
2759
2760    if (_get_event_flag(event_info, event_type) & EVAS_EVENT_FLAG_ON_HOLD)
2761      _event_history_add(data, event_info, event_type);
2762    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2763          (event_type == EVAS_CALLBACK_MULTI_UP))
2764      {
2765         Eina_List *pending = _device_is_pending(wd->pending, event_info, event_type);
2766         if (pending)
2767           {
2768              consume_event(wd, event_info, event_type, EVAS_EVENT_FLAG_ON_HOLD);
2769              _event_history_add(data, event_info, event_type);
2770           }
2771      }
2772
2773    /* we maintain list of touched devices*/
2774    if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
2775          (event_type == EVAS_CALLBACK_MULTI_DOWN))
2776      {
2777         wd->touched = _add_touched_device(wd->touched, pe);
2778      }
2779    else if ((event_type == EVAS_CALLBACK_MOUSE_UP) ||
2780          (event_type == EVAS_CALLBACK_MULTI_UP))
2781      {
2782         wd->touched = _remove_touched_device(wd->touched, pe);
2783      }
2784
2785    /* Report current states and clear history if needed */
2786    _clear_if_finished(data);
2787 }
2788
2789
2790 /**
2791  * For all _mouse_* / multi_* functions wethen send this event to
2792  * _event_process function.
2793  *
2794  * @param data The gesture-layer object.
2795  * @param event_info Pointer to recent input event.
2796  *
2797  * @ingroup Elm_Gesture_Layer
2798  */
2799 static void
2800 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2801       void *event_info)
2802 {
2803    Widget_Data *wd = elm_widget_data_get(data);
2804    if (!wd) return;
2805    if (((Evas_Event_Mouse_Down *) event_info)->button != 1)
2806      return; /* We only process left-click at the moment */
2807
2808    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_DOWN);
2809 }
2810
2811 static void
2812 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2813       void *event_info)
2814 {
2815    Widget_Data *wd = elm_widget_data_get(data);
2816    if (!wd) return;
2817
2818    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_MOVE);
2819 }
2820
2821 static void
2822 _key_down_cb(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_KEY_DOWN);
2829 }
2830
2831 static void
2832 _key_up_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_UP);
2839 }
2840
2841 static void
2842 _mouse_up(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    if (((Evas_Event_Mouse_Up *) event_info)->button != 1)
2849      return; /* We only process left-click at the moment */
2850
2851    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_UP);
2852 }
2853
2854 static void
2855 _mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
2856       void *event_info)
2857 {
2858    Widget_Data *wd = elm_widget_data_get(data);
2859    if (!wd) return;
2860
2861    _event_process(data, obj, event_info, EVAS_CALLBACK_MOUSE_WHEEL);
2862 }
2863
2864 static void
2865 _multi_down(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_MULTI_DOWN);
2872 }
2873
2874 static void
2875 _multi_move(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_MOVE);
2882 }
2883
2884 static void
2885 _multi_up(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_UP);
2892 }
2893
2894 EAPI Eina_Bool
2895 elm_gesture_layer_hold_events_get(Evas_Object *obj)
2896 {
2897    Widget_Data *wd = elm_widget_data_get(obj);
2898    if (!wd) return EINA_FALSE;
2899
2900    return !wd->repeat_events;
2901 }
2902
2903 EAPI void
2904 elm_gesture_layer_hold_events_set(Evas_Object *obj, Eina_Bool r)
2905 {
2906    Widget_Data *wd = elm_widget_data_get(obj);
2907    if (!wd) return;
2908
2909    wd->repeat_events = !r;
2910 }
2911
2912 EAPI void
2913 elm_gesture_layer_zoom_step_set(Evas_Object *obj, double s)
2914 {
2915    Widget_Data *wd = elm_widget_data_get(obj);
2916    if (!wd) return;
2917
2918    if (s < 0.0)
2919      return;
2920
2921    wd->zoom_step = s;
2922 }
2923
2924 EAPI void
2925 elm_gesture_layer_rotate_step_set(Evas_Object *obj, double s)
2926 {
2927    Widget_Data *wd = elm_widget_data_get(obj);
2928    if (!wd) return;
2929
2930    if (s < 0.0)
2931      return;
2932
2933    wd->rotate_step = s;
2934 }
2935
2936 EAPI Eina_Bool
2937 elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *t)
2938 {
2939    Widget_Data *wd = elm_widget_data_get(obj);
2940    if (!wd) return EINA_FALSE;
2941
2942    if (!t)
2943      return EINA_FALSE;
2944
2945    /* if was attached before, unregister callbacks first */
2946    if (wd->target)
2947      _unregister_callbacks(obj);
2948
2949    wd->target = t;
2950
2951    _register_callbacks(obj);
2952    return EINA_TRUE;
2953 }
2954
2955 EAPI void
2956 elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Types idx,
2957       Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data)
2958 {
2959    Widget_Data *wd = elm_widget_data_get(obj);
2960    if (!wd) return;
2961
2962    if (!wd->gesture[idx])
2963      wd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
2964
2965    Gesture_Info *p = wd->gesture[idx];
2966    p->obj = obj;
2967    p->g_type = idx;
2968    p->fn[cb_type].cb = cb;
2969    p->fn[cb_type].user_data = data;
2970    p->state = ELM_GESTURE_STATE_UNDEFINED;
2971    SET_TEST_BIT(p);
2972 }
2973
2974 static void
2975 _disable_hook(Evas_Object *obj)
2976 {
2977    if (elm_widget_disabled_get(obj))
2978      _unregister_callbacks(obj);
2979    else
2980      _register_callbacks(obj);
2981 }
2982
2983 EAPI Evas_Object *
2984 elm_gesture_layer_add(Evas_Object *parent)
2985 {
2986    Evas_Object *obj;
2987    Evas *e;
2988    Widget_Data *wd;
2989
2990    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2991
2992    wd = ELM_NEW(Widget_Data);
2993    e = evas_object_evas_get(parent);
2994    if (!e) return NULL;
2995    obj = elm_widget_add(e);
2996    ELM_SET_WIDTYPE(widtype, "gesture_layer");
2997    elm_widget_type_set(obj, "gesture_layer");
2998    elm_widget_sub_object_add(parent, obj);
2999    elm_widget_data_set(obj, wd);
3000    elm_widget_del_hook_set(obj, _del_hook);
3001    elm_widget_disable_hook_set(obj, _disable_hook);
3002
3003    wd->target = NULL;
3004    wd->line_min_length =_elm_config->glayer_line_min_length * elm_finger_size_get();
3005    wd->zoom_distance_tolerance = _elm_config->glayer_zoom_distance_tolerance * elm_finger_size_get();
3006    wd->line_distance_tolerance = _elm_config->glayer_line_distance_tolerance * elm_finger_size_get();
3007    wd->zoom_finger_factor = _elm_config->glayer_zoom_finger_factor;
3008    wd->zoom_wheel_factor = _elm_config->glayer_zoom_wheel_factor; /* mouse wheel zoom steps */
3009    wd->rotate_angular_tolerance = _elm_config->glayer_rotate_angular_tolerance;
3010    wd->line_angular_tolerance = _elm_config->glayer_line_angular_tolerance;
3011    wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms;
3012    wd->repeat_events = EINA_TRUE;
3013
3014 #if defined(DEBUG_GESTURE_LAYER)
3015    printf("size of Gestures = <%d>\n", sizeof(wd->gesture));
3016    printf("initial values:\n\tzoom_finger_factor=<%f>\n\tzoom_distance_tolerance=<%d>\n\tline_min_length=<%d>\n\tline_distance_tolerance=<%d>\n\tzoom_wheel_factor=<%f>\n\trotate_angular_tolerance=<%f>\n\twd->line_angular_tolerance=<%f>\n\twd->flick_time_limit_ms=<%d>\n", wd->zoom_finger_factor, wd->zoom_distance_tolerance, wd->line_min_length, wd->line_distance_tolerance, wd->zoom_wheel_factor, wd->rotate_angular_tolerance, wd->line_angular_tolerance, wd->flick_time_limit_ms);
3017 #endif
3018    memset(wd->gesture, 0, sizeof(wd->gesture));
3019
3020    return obj;
3021 }