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