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