1 #include "efl_canvas_gesture_private.h"
2 
3 #define MY_CLASS                       EFL_CANVAS_GESTURE_RECOGNIZER_MOMENTUM_CLASS
4 
5 #define MOMENTUM_TIMEOUT               50
6 #define THUMBSCROLL_FRICTION           0.95
7 #define THUMBSCROLL_MOMENTUM_THRESHOLD 100.0
8 #define EFL_GESTURE_MINIMUM_MOMENTUM   0.001
9 
10 EOLIAN static const Efl_Class *
_efl_canvas_gesture_recognizer_momentum_efl_canvas_gesture_recognizer_type_get(const Eo * obj EINA_UNUSED,Efl_Canvas_Gesture_Recognizer_Momentum_Data * pd EINA_UNUSED)11 _efl_canvas_gesture_recognizer_momentum_efl_canvas_gesture_recognizer_type_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Gesture_Recognizer_Momentum_Data *pd EINA_UNUSED)
12 {
13    return EFL_CANVAS_GESTURE_MOMENTUM_CLASS;
14 }
15 
16 static void
_momentum_set(Eo * obj,Efl_Canvas_Gesture_Momentum_Data * md,Eina_Position2D v1,Eina_Position2D v2,unsigned int t1,unsigned int t2)17 _momentum_set(Eo *obj,
18               Efl_Canvas_Gesture_Momentum_Data *md,
19               Eina_Position2D v1,
20               Eina_Position2D v2,
21               unsigned int t1,
22               unsigned int t2)
23 {
24    Evas_Coord velx = 0, vely = 0, vel;
25    Evas_Coord dx = v2.x - v1.x;
26    Evas_Coord dy = v2.y - v1.y;
27    int dt = t2 - t1;
28    Eina_Value *tf, *tmt;
29    double thumbscroll_momentum_friction, thumbscroll_momentum_threshold;
30 
31    if (dt > 0)
32      {
33         velx = (dx * 1000) / dt;
34         vely = (dy * 1000) / dt;
35      }
36 
37    vel = sqrt((velx * velx) + (vely * vely));
38 
39    tf = _recognizer_config_get(obj, "thumbscroll_momentum_friction");
40    if (tf) eina_value_get(tf, &thumbscroll_momentum_friction);
41    else thumbscroll_momentum_friction = THUMBSCROLL_FRICTION;
42 
43    tmt = _recognizer_config_get(obj, "thumbscroll_momentum_threshold");
44    if (tmt) eina_value_get(tmt, &thumbscroll_momentum_threshold);
45    else thumbscroll_momentum_threshold = THUMBSCROLL_MOMENTUM_THRESHOLD;
46 
47    if ((thumbscroll_momentum_friction > 0.0) &&
48        (vel > thumbscroll_momentum_threshold)) /* report
49                                                 * momentum */
50      {
51         md->momentum.x = velx;
52         md->momentum.y = vely;
53      }
54    else
55      {
56         md->momentum.x = 0;
57         md->momentum.y = 0;
58      }
59 }
60 
61 EOLIAN static Efl_Canvas_Gesture_Recognizer_Result
_efl_canvas_gesture_recognizer_momentum_efl_canvas_gesture_recognizer_recognize(Eo * obj,Efl_Canvas_Gesture_Recognizer_Momentum_Data * pd,Efl_Canvas_Gesture * gesture,Efl_Object * watched EINA_UNUSED,Efl_Canvas_Gesture_Touch * event)62 _efl_canvas_gesture_recognizer_momentum_efl_canvas_gesture_recognizer_recognize(Eo *obj,
63                                                                                 Efl_Canvas_Gesture_Recognizer_Momentum_Data *pd,
64                                                                                 Efl_Canvas_Gesture *gesture, Efl_Object *watched EINA_UNUSED,
65                                                                                 Efl_Canvas_Gesture_Touch *event)
66 {
67    Eina_Value *val;
68    unsigned char glayer_continues_enable;
69    Efl_Canvas_Gesture_Recognizer_Result result = EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
70    Efl_Canvas_Gesture_Recognizer_Data *rd = efl_data_scope_get(obj, EFL_CANVAS_GESTURE_RECOGNIZER_CLASS);
71    Efl_Canvas_Gesture_Momentum_Data *md = efl_data_scope_get(gesture, EFL_CANVAS_GESTURE_MOMENTUM_CLASS);
72 
73    val = _recognizer_config_get(obj, "glayer_continues_enable");
74    if (val) eina_value_get(val, &glayer_continues_enable);
75    else glayer_continues_enable = 1;
76 
77    //Check the touched to ignore very first event.
78    //It does not have any meanging of this gesture.
79    if (glayer_continues_enable && !pd->touched)
80      {
81         if (efl_gesture_touch_state_get(event) != EFL_GESTURE_TOUCH_STATE_END)
82           {
83              /* guard against successive multi-touch cancels */
84              if (efl_gesture_touch_points_count_get(event) == 1)
85                {
86                   pd->touched = EINA_TRUE;
87                   rd->continues = EINA_TRUE;
88                   md->id = -1;
89                }
90           }
91 
92         return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
93      }
94    if (pd->touched && (efl_gesture_touch_current_data_get(event)->action == EFL_POINTER_ACTION_DOWN))
95      {
96         /* a second finger was pressed at the same time-ish as the first: combine into same event */
97         if (efl_gesture_touch_points_count_get(event) > 1)
98           {
99              if (efl_gesture_touch_current_timestamp_get(event) - efl_gesture_touch_previous_data_get(event)->cur.timestamp < TAP_TOUCH_TIME_THRESHOLD)
100                return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
101           }
102         else if (efl_gesture_touch_current_timestamp_get(event) - efl_gesture_timestamp_get(gesture) < TAP_TOUCH_TIME_THRESHOLD)
103           return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
104      }
105    if (pd->t_st && (md->id != -1) && (md->id != efl_gesture_touch_current_data_get(event)->id))
106      {
107         int xdir, ydir;
108         const Efl_Gesture_Touch_Point_Data *data = efl_gesture_touch_current_data_get(event);
109         xdir = _direction_get(data->prev.pos.x, data->cur.pos.x);
110         ydir = _direction_get(data->prev.pos.y, data->cur.pos.y);
111         if ((xdir != pd->xdir) || (ydir != pd->ydir))
112           {
113              memset(pd, 0, sizeof(Efl_Canvas_Gesture_Recognizer_Momentum_Data));
114              rd->continues = EINA_FALSE;
115              return EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
116           }
117         return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
118      }
119 
120    switch (efl_gesture_touch_state_get(event))
121      {
122       case EFL_GESTURE_TOUCH_STATE_BEGIN:
123       case EFL_GESTURE_TOUCH_STATE_UPDATE:
124       {
125          if (!pd->t_st)
126            {
127               if (efl_gesture_touch_state_get(event) == EFL_GESTURE_TOUCH_STATE_BEGIN ||
128                   glayer_continues_enable)
129                 {
130 
131                    pd->t_st = pd->t_end = efl_gesture_touch_current_timestamp_get(event);
132 
133                    pd->st_line = pd->end_line =
134                        efl_gesture_touch_start_point_get(event);
135 
136                    efl_gesture_hotspot_set(gesture, pd->st_line);
137                    md->id = efl_gesture_touch_current_data_get(event)->id;
138                    if (efl_gesture_touch_previous_data_get(event))
139                      {
140                         /* if multiple fingers are pressed simultaneously, start tracking the latest finger for gesture */
141                         if (efl_gesture_touch_previous_data_get(event)->action == efl_gesture_touch_current_data_get(event)->action)
142                           return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
143                      }
144                    return EFL_GESTURE_RECOGNIZER_RESULT_TRIGGER;
145                 }
146            }
147 
148          if ((efl_gesture_touch_current_timestamp_get(event) - MOMENTUM_TIMEOUT) >
149              pd->t_end)
150            {
151               pd->st_line = efl_gesture_touch_current_point_get(event);
152               pd->t_st = efl_gesture_touch_current_timestamp_get(event);
153               pd->xdir = pd->ydir = 0;
154            }
155          else
156            {
157               int xdir, ydir;
158               Eina_Position2D cur_p = efl_gesture_touch_current_point_get(event);
159 
160               xdir = _direction_get(pd->end_line.x, cur_p.x);
161               ydir = _direction_get(pd->end_line.y, cur_p.y);
162 
163               if (xdir && (xdir != pd->xdir))
164                 {
165                    pd->st_line.x = pd->end_line.x;
166                    pd->t_st = pd->t_end;
167                    pd->xdir = xdir;
168                 }
169 
170               if (ydir && (ydir != pd->ydir))
171                 {
172                    pd->st_line.y = pd->end_line.y;
173                    pd->t_st = pd->t_end;
174                    pd->ydir = ydir;
175                 }
176            }
177 
178          pd->end_line = efl_gesture_touch_current_point_get(event);
179          pd->t_end = efl_gesture_touch_current_timestamp_get(event);
180          efl_gesture_hotspot_set(gesture, pd->end_line);
181 
182          _momentum_set(obj, md, pd->st_line, efl_gesture_touch_current_point_get(event),
183                        pd->t_st, efl_gesture_touch_current_timestamp_get(event));
184 
185          result = EFL_GESTURE_RECOGNIZER_RESULT_TRIGGER;
186 
187          break;
188       }
189 
190       case EFL_GESTURE_TOUCH_STATE_END:
191       {
192          Eina_Bool touched = !!efl_gesture_touch_points_count_get(event);
193          if (!pd->t_st)
194            {
195               Eina_Bool prev_touched = pd->touched;
196 
197               rd->continues = pd->touched = touched;
198 
199               if (prev_touched)
200                 return EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
201               return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
202            }
203 
204          if ((efl_gesture_touch_current_timestamp_get(event) - MOMENTUM_TIMEOUT) > pd->t_end)
205            {
206               pd->st_line = efl_gesture_touch_current_point_get(event);
207               pd->t_st = efl_gesture_touch_current_timestamp_get(event);
208               pd->xdir = pd->ydir = 0;
209            }
210 
211          pd->end_line = efl_gesture_touch_current_point_get(event);
212          pd->t_end = efl_gesture_touch_current_timestamp_get(event);
213          rd->continues = touched;
214          efl_gesture_hotspot_set(gesture, pd->end_line);
215 
216          if ((fabs(md->momentum.x) > EFL_GESTURE_MINIMUM_MOMENTUM) ||
217              (fabs(md->momentum.y) > EFL_GESTURE_MINIMUM_MOMENTUM))
218            result = EFL_GESTURE_RECOGNIZER_RESULT_FINISH;
219          else
220            result = EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
221 
222          memset(pd, 0, sizeof(Efl_Canvas_Gesture_Recognizer_Momentum_Data));
223          pd->touched = touched;
224 
225          break;
226       }
227 
228       default:
229 
230         break;
231      }
232 
233    return result;
234 }
235 
236 #include "efl_canvas_gesture_recognizer_momentum.eo.c"
237