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