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