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