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