1 /**
2 * @file lv_indev.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 ********************/
9 #include "lv_indev.h"
10 #include "lv_disp.h"
11 #include "lv_obj.h"
12 #include "lv_indev_scroll.h"
13 #include "lv_group.h"
14 #include "lv_refr.h"
15
16 #include "../hal/lv_hal_tick.h"
17 #include "../misc/lv_timer.h"
18 #include "../misc/lv_math.h"
19
20 /*********************
21 * DEFINES
22 *********************/
23 #if LV_INDEV_DEF_SCROLL_THROW <= 0
24 #warning "LV_INDEV_DRAG_THROW must be greater than 0"
25 #endif
26
27 /**********************
28 * TYPEDEFS
29 **********************/
30
31 /**********************
32 * STATIC PROTOTYPES
33 **********************/
34 static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data);
35 static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data);
36 static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);
37 static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);
38 static void indev_proc_press(_lv_indev_proc_t * proc);
39 static void indev_proc_release(_lv_indev_proc_t * proc);
40 static void indev_proc_reset_query_handler(lv_indev_t * indev);
41 static void indev_click_focus(_lv_indev_proc_t * proc);
42 static void indev_gesture(_lv_indev_proc_t * proc);
43 static bool indev_reset_check(_lv_indev_proc_t * proc);
44
45 /**********************
46 * STATIC VARIABLES
47 **********************/
48 static lv_indev_t * indev_act;
49 static lv_obj_t * indev_obj_act = NULL;
50
51 /**********************
52 * MACROS
53 **********************/
54 #if LV_LOG_TRACE_INDEV
55 #define INDEV_TRACE(...) LV_LOG_TRACE(__VA_ARGS__)
56 #else
57 #define INDEV_TRACE(...)
58 #endif
59
60 /**********************
61 * GLOBAL FUNCTIONS
62 **********************/
63
lv_indev_read_timer_cb(lv_timer_t * timer)64 void lv_indev_read_timer_cb(lv_timer_t * timer)
65 {
66 INDEV_TRACE("begin");
67
68 lv_indev_data_t data;
69
70 indev_act = timer->user_data;
71
72 /*Read and process all indevs*/
73 if(indev_act->driver->disp == NULL) return; /*Not assigned to any displays*/
74
75 /*Handle reset query before processing the point*/
76 indev_proc_reset_query_handler(indev_act);
77
78 if(indev_act->proc.disabled ||
79 indev_act->driver->disp->prev_scr != NULL) return; /*Input disabled or screen animation active*/
80 bool continue_reading;
81 do {
82 /*Read the data*/
83 _lv_indev_read(indev_act, &data);
84 continue_reading = data.continue_reading;
85
86 /*The active object might be deleted even in the read function*/
87 indev_proc_reset_query_handler(indev_act);
88 indev_obj_act = NULL;
89
90 indev_act->proc.state = data.state;
91
92 /*Save the last activity time*/
93 if(indev_act->proc.state == LV_INDEV_STATE_PRESSED) {
94 indev_act->driver->disp->last_activity_time = lv_tick_get();
95 }
96 else if(indev_act->driver->type == LV_INDEV_TYPE_ENCODER && data.enc_diff) {
97 indev_act->driver->disp->last_activity_time = lv_tick_get();
98 }
99
100 if(indev_act->driver->type == LV_INDEV_TYPE_POINTER) {
101 indev_pointer_proc(indev_act, &data);
102 }
103 else if(indev_act->driver->type == LV_INDEV_TYPE_KEYPAD) {
104 indev_keypad_proc(indev_act, &data);
105 }
106 else if(indev_act->driver->type == LV_INDEV_TYPE_ENCODER) {
107 indev_encoder_proc(indev_act, &data);
108 }
109 else if(indev_act->driver->type == LV_INDEV_TYPE_BUTTON) {
110 indev_button_proc(indev_act, &data);
111 }
112 /*Handle reset query if it happened in during processing*/
113 indev_proc_reset_query_handler(indev_act);
114 } while(continue_reading);
115
116 /*End of indev processing, so no act indev*/
117 indev_act = NULL;
118 indev_obj_act = NULL;
119
120 INDEV_TRACE("finished");
121 }
122
lv_indev_enable(lv_indev_t * indev,bool en)123 void lv_indev_enable(lv_indev_t * indev, bool en)
124 {
125 uint8_t enable = en ? 0 : 1;
126
127 if(indev) {
128 indev->proc.disabled = enable;
129 }
130 else {
131 lv_indev_t * i = lv_indev_get_next(NULL);
132 while(i) {
133 i->proc.disabled = enable;
134 i = lv_indev_get_next(i);
135 }
136 }
137 }
138
lv_indev_get_act(void)139 lv_indev_t * lv_indev_get_act(void)
140 {
141 return indev_act;
142 }
143
lv_indev_get_type(const lv_indev_t * indev)144 lv_indev_type_t lv_indev_get_type(const lv_indev_t * indev)
145 {
146 if(indev == NULL) return LV_INDEV_TYPE_NONE;
147
148 return indev->driver->type;
149 }
150
lv_indev_reset(lv_indev_t * indev,lv_obj_t * obj)151 void lv_indev_reset(lv_indev_t * indev, lv_obj_t * obj)
152 {
153 if(indev) {
154 indev->proc.reset_query = 1;
155 if(indev_act == indev) indev_obj_act = NULL;
156 if(indev->driver->type == LV_INDEV_TYPE_POINTER || indev->driver->type == LV_INDEV_TYPE_KEYPAD) {
157 if(obj == NULL || indev->proc.types.pointer.last_pressed == obj) {
158 indev->proc.types.pointer.last_pressed = NULL;
159 }
160 if(obj == NULL || indev->proc.types.pointer.act_obj == obj) {
161 indev->proc.types.pointer.act_obj = NULL;
162 }
163 if(obj == NULL || indev->proc.types.pointer.last_obj == obj) {
164 indev->proc.types.pointer.last_obj = NULL;
165 }
166 }
167 }
168 else {
169 lv_indev_t * i = lv_indev_get_next(NULL);
170 while(i) {
171 i->proc.reset_query = 1;
172 if(i->driver->type == LV_INDEV_TYPE_POINTER || i->driver->type == LV_INDEV_TYPE_KEYPAD) {
173 if(obj == NULL || i->proc.types.pointer.last_pressed == obj) {
174 i->proc.types.pointer.last_pressed = NULL;
175 }
176 if(obj == NULL || i->proc.types.pointer.act_obj == obj) {
177 i->proc.types.pointer.act_obj = NULL;
178 }
179 if(obj == NULL || i->proc.types.pointer.last_obj == obj) {
180 i->proc.types.pointer.last_obj = NULL;
181 }
182 }
183 i = lv_indev_get_next(i);
184 }
185 indev_obj_act = NULL;
186 }
187 }
188
lv_indev_reset_long_press(lv_indev_t * indev)189 void lv_indev_reset_long_press(lv_indev_t * indev)
190 {
191 indev->proc.long_pr_sent = 0;
192 indev->proc.longpr_rep_timestamp = lv_tick_get();
193 indev->proc.pr_timestamp = lv_tick_get();
194 }
195
lv_indev_set_cursor(lv_indev_t * indev,lv_obj_t * cur_obj)196 void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)
197 {
198 if(indev->driver->type != LV_INDEV_TYPE_POINTER) return;
199
200 indev->cursor = cur_obj;
201 lv_obj_set_parent(indev->cursor, lv_disp_get_layer_sys(indev->driver->disp));
202 lv_obj_set_pos(indev->cursor, indev->proc.types.pointer.act_point.x, indev->proc.types.pointer.act_point.y);
203 lv_obj_clear_flag(indev->cursor, LV_OBJ_FLAG_CLICKABLE);
204 lv_obj_add_flag(indev->cursor, LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_FLOATING);
205 }
206
lv_indev_set_group(lv_indev_t * indev,lv_group_t * group)207 void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)
208 {
209 if(indev->driver->type == LV_INDEV_TYPE_KEYPAD || indev->driver->type == LV_INDEV_TYPE_ENCODER) {
210 indev->group = group;
211 }
212 }
213
lv_indev_set_button_points(lv_indev_t * indev,const lv_point_t points[])214 void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t points[])
215 {
216 if(indev->driver->type == LV_INDEV_TYPE_BUTTON) {
217 indev->btn_points = points;
218 }
219 }
220
lv_indev_get_point(const lv_indev_t * indev,lv_point_t * point)221 void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)
222 {
223 if(indev == NULL) {
224 point->x = 0;
225 point->y = 0;
226 return;
227 }
228 if(indev->driver->type != LV_INDEV_TYPE_POINTER && indev->driver->type != LV_INDEV_TYPE_BUTTON) {
229 point->x = -1;
230 point->y = -1;
231 }
232 else {
233 point->x = indev->proc.types.pointer.act_point.x;
234 point->y = indev->proc.types.pointer.act_point.y;
235 }
236 }
237
lv_indev_get_gesture_dir(const lv_indev_t * indev)238 lv_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev)
239 {
240 return indev->proc.types.pointer.gesture_dir;
241 }
242
lv_indev_get_key(const lv_indev_t * indev)243 uint32_t lv_indev_get_key(const lv_indev_t * indev)
244 {
245 if(indev->driver->type != LV_INDEV_TYPE_KEYPAD)
246 return 0;
247 else
248 return indev->proc.types.keypad.last_key;
249 }
250
lv_indev_get_scroll_dir(const lv_indev_t * indev)251 lv_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev)
252 {
253 if(indev == NULL) return false;
254 if(indev->driver->type != LV_INDEV_TYPE_POINTER && indev->driver->type != LV_INDEV_TYPE_BUTTON) return false;
255 return indev->proc.types.pointer.scroll_dir;
256 }
257
lv_indev_get_scroll_obj(const lv_indev_t * indev)258 lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev)
259 {
260 if(indev == NULL) return NULL;
261 if(indev->driver->type != LV_INDEV_TYPE_POINTER && indev->driver->type != LV_INDEV_TYPE_BUTTON) return NULL;
262 return indev->proc.types.pointer.scroll_obj;
263 }
264
lv_indev_get_vect(const lv_indev_t * indev,lv_point_t * point)265 void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
266 {
267 point->x = 0;
268 point->y = 0;
269
270 if(indev == NULL) return;
271
272 if(indev->driver->type == LV_INDEV_TYPE_POINTER || indev->driver->type == LV_INDEV_TYPE_BUTTON) {
273 point->x = indev->proc.types.pointer.vect.x;
274 point->y = indev->proc.types.pointer.vect.y;
275 }
276 }
277
lv_indev_wait_release(lv_indev_t * indev)278 void lv_indev_wait_release(lv_indev_t * indev)
279 {
280 if(indev == NULL)return;
281 indev->proc.wait_until_release = 1;
282 }
283
lv_indev_get_obj_act(void)284 lv_obj_t * lv_indev_get_obj_act(void)
285 {
286 return indev_obj_act;
287 }
288
lv_indev_get_read_timer(lv_disp_t * indev)289 lv_timer_t * lv_indev_get_read_timer(lv_disp_t * indev)
290 {
291 if(!indev) {
292 LV_LOG_WARN("lv_indev_get_read_timer: indev was NULL");
293 return NULL;
294 }
295
296 return indev->refr_timer;
297 }
298
lv_indev_search_obj(lv_obj_t * obj,lv_point_t * point)299 lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
300 {
301 lv_obj_t * found_p = NULL;
302
303 /*If this obj is hidden the children are hidden too so return immediately*/
304 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return NULL;
305
306 lv_point_t p_trans = *point;
307 lv_obj_transform_point(obj, &p_trans, false, true);
308
309 bool hit_test_ok = lv_obj_hit_test(obj, &p_trans);
310
311 /*If the point is on this object or has overflow visible check its children too*/
312 if(_lv_area_is_point_on(&obj->coords, &p_trans, 0) || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
313 int32_t i;
314 uint32_t child_cnt = lv_obj_get_child_cnt(obj);
315
316 /*If a child matches use it*/
317 for(i = child_cnt - 1; i >= 0; i--) {
318 lv_obj_t * child = obj->spec_attr->children[i];
319 found_p = lv_indev_search_obj(child, &p_trans);
320 if(found_p) return found_p;
321 }
322 }
323
324 /*If not return earlier for a clicked child and this obj's hittest was ok use it
325 *else return NULL*/
326 if(hit_test_ok) return obj;
327 else return NULL;
328 }
329
330 /**********************
331 * STATIC FUNCTIONS
332 **********************/
333
334 /**
335 * Process a new point from LV_INDEV_TYPE_POINTER input device
336 * @param i pointer to an input device
337 * @param data pointer to the data read from the input device
338 */
indev_pointer_proc(lv_indev_t * i,lv_indev_data_t * data)339 static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
340 {
341 lv_disp_t * disp = i->driver->disp;
342 /*Save the raw points so they can be used again in _lv_indev_read*/
343 i->proc.types.pointer.last_raw_point.x = data->point.x;
344 i->proc.types.pointer.last_raw_point.y = data->point.y;
345
346 if(disp->driver->rotated == LV_DISP_ROT_180 || disp->driver->rotated == LV_DISP_ROT_270) {
347 data->point.x = disp->driver->hor_res - data->point.x - 1;
348 data->point.y = disp->driver->ver_res - data->point.y - 1;
349 }
350 if(disp->driver->rotated == LV_DISP_ROT_90 || disp->driver->rotated == LV_DISP_ROT_270) {
351 lv_coord_t tmp = data->point.y;
352 data->point.y = data->point.x;
353 data->point.x = disp->driver->ver_res - tmp - 1;
354 }
355
356 /*Simple sanity check*/
357 if(data->point.x < 0) {
358 LV_LOG_WARN("X is %d which is smaller than zero", (int)data->point.x);
359 }
360 if(data->point.x >= lv_disp_get_hor_res(i->driver->disp)) {
361 LV_LOG_WARN("X is %d which is greater than hor. res", (int)data->point.x);
362 }
363 if(data->point.y < 0) {
364 LV_LOG_WARN("Y is %d which is smaller than zero", (int)data->point.y);
365 }
366 if(data->point.y >= lv_disp_get_ver_res(i->driver->disp)) {
367 LV_LOG_WARN("Y is %d which is greater than ver. res", (int)data->point.y);
368 }
369
370 /*Move the cursor if set and moved*/
371 if(i->cursor != NULL &&
372 (i->proc.types.pointer.last_point.x != data->point.x || i->proc.types.pointer.last_point.y != data->point.y)) {
373 lv_obj_set_pos(i->cursor, data->point.x, data->point.y);
374 }
375
376 i->proc.types.pointer.act_point.x = data->point.x;
377 i->proc.types.pointer.act_point.y = data->point.y;
378
379 if(i->proc.state == LV_INDEV_STATE_PRESSED) {
380 indev_proc_press(&i->proc);
381 }
382 else {
383 indev_proc_release(&i->proc);
384 }
385
386 i->proc.types.pointer.last_point.x = i->proc.types.pointer.act_point.x;
387 i->proc.types.pointer.last_point.y = i->proc.types.pointer.act_point.y;
388 }
389
390 /**
391 * Process a new point from LV_INDEV_TYPE_KEYPAD input device
392 * @param i pointer to an input device
393 * @param data pointer to the data read from the input device
394 */
indev_keypad_proc(lv_indev_t * i,lv_indev_data_t * data)395 static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
396 {
397 if(data->state == LV_INDEV_STATE_PRESSED && i->proc.wait_until_release) return;
398
399 if(i->proc.wait_until_release) {
400 i->proc.wait_until_release = 0;
401 i->proc.pr_timestamp = 0;
402 i->proc.long_pr_sent = 0;
403 i->proc.types.keypad.last_state = LV_INDEV_STATE_RELEASED; /*To skip the processing of release*/
404 }
405
406 lv_group_t * g = i->group;
407 if(g == NULL) return;
408
409 indev_obj_act = lv_group_get_focused(g);
410 if(indev_obj_act == NULL) return;
411
412 bool dis = lv_obj_has_state(indev_obj_act, LV_STATE_DISABLED);
413
414 /*Save the last key to compare it with the current latter on RELEASE*/
415 uint32_t prev_key = i->proc.types.keypad.last_key;
416
417 /*Save the last key.
418 *It must be done here else `lv_indev_get_key` will return the last key in events*/
419 i->proc.types.keypad.last_key = data->key;
420
421 /*Save the previous state so we can detect state changes below and also set the last state now
422 *so if any event handler on the way returns `LV_RES_INV` the last state is remembered
423 *for the next time*/
424 uint32_t prev_state = i->proc.types.keypad.last_state;
425 i->proc.types.keypad.last_state = data->state;
426
427 /*Key press happened*/
428 if(data->state == LV_INDEV_STATE_PRESSED && prev_state == LV_INDEV_STATE_RELEASED) {
429 LV_LOG_INFO("%" LV_PRIu32 " key is pressed", data->key);
430 i->proc.pr_timestamp = lv_tick_get();
431
432 /*Move the focus on NEXT*/
433 if(data->key == LV_KEY_NEXT) {
434 lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
435 lv_group_focus_next(g);
436 if(indev_reset_check(&i->proc)) return;
437 }
438 /*Move the focus on PREV*/
439 else if(data->key == LV_KEY_PREV) {
440 lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
441 lv_group_focus_prev(g);
442 if(indev_reset_check(&i->proc)) return;
443 }
444 else if(!dis) {
445 /*Simulate a press on the object if ENTER was pressed*/
446 if(data->key == LV_KEY_ENTER) {
447 /*Send the ENTER as a normal KEY*/
448 lv_group_send_data(g, LV_KEY_ENTER);
449 if(indev_reset_check(&i->proc)) return;
450
451 if(!dis) lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
452 if(indev_reset_check(&i->proc)) return;
453 }
454 else if(data->key == LV_KEY_ESC) {
455 /*Send the ESC as a normal KEY*/
456 lv_group_send_data(g, LV_KEY_ESC);
457 if(indev_reset_check(&i->proc)) return;
458
459 lv_event_send(indev_obj_act, LV_EVENT_CANCEL, indev_act);
460 if(indev_reset_check(&i->proc)) return;
461 }
462 /*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/
463 else {
464 lv_group_send_data(g, data->key);
465 if(indev_reset_check(&i->proc)) return;
466 }
467 }
468 }
469 /*Pressing*/
470 else if(!dis && data->state == LV_INDEV_STATE_PRESSED && prev_state == LV_INDEV_STATE_PRESSED) {
471
472 if(data->key == LV_KEY_ENTER) {
473 lv_event_send(indev_obj_act, LV_EVENT_PRESSING, indev_act);
474 if(indev_reset_check(&i->proc)) return;
475 }
476
477 /*Long press time has elapsed?*/
478 if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver->long_press_time) {
479 i->proc.long_pr_sent = 1;
480 if(data->key == LV_KEY_ENTER) {
481 i->proc.longpr_rep_timestamp = lv_tick_get();
482 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
483 if(indev_reset_check(&i->proc)) return;
484 }
485 }
486 /*Long press repeated time has elapsed?*/
487 else if(i->proc.long_pr_sent != 0 &&
488 lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver->long_press_repeat_time) {
489
490 i->proc.longpr_rep_timestamp = lv_tick_get();
491
492 /*Send LONG_PRESS_REP on ENTER*/
493 if(data->key == LV_KEY_ENTER) {
494 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
495 if(indev_reset_check(&i->proc)) return;
496 }
497 /*Move the focus on NEXT again*/
498 else if(data->key == LV_KEY_NEXT) {
499 lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
500 lv_group_focus_next(g);
501 if(indev_reset_check(&i->proc)) return;
502 }
503 /*Move the focus on PREV again*/
504 else if(data->key == LV_KEY_PREV) {
505 lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
506 lv_group_focus_prev(g);
507 if(indev_reset_check(&i->proc)) return;
508 }
509 /*Just send other keys again to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT)*/
510 else {
511 lv_group_send_data(g, data->key);
512 if(indev_reset_check(&i->proc)) return;
513 }
514 }
515 }
516 /*Release happened*/
517 else if(!dis && data->state == LV_INDEV_STATE_RELEASED && prev_state == LV_INDEV_STATE_PRESSED) {
518 LV_LOG_INFO("%" LV_PRIu32 " key is released", data->key);
519 /*The user might clear the key when it was released. Always release the pressed key*/
520 data->key = prev_key;
521 if(data->key == LV_KEY_ENTER) {
522
523 lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
524 if(indev_reset_check(&i->proc)) return;
525
526 if(i->proc.long_pr_sent == 0) {
527 lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
528 if(indev_reset_check(&i->proc)) return;
529 }
530
531 lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
532 if(indev_reset_check(&i->proc)) return;
533
534 }
535 i->proc.pr_timestamp = 0;
536 i->proc.long_pr_sent = 0;
537 }
538 indev_obj_act = NULL;
539 }
540
541 /**
542 * Process a new point from LV_INDEV_TYPE_ENCODER input device
543 * @param i pointer to an input device
544 * @param data pointer to the data read from the input device
545 */
indev_encoder_proc(lv_indev_t * i,lv_indev_data_t * data)546 static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
547 {
548 if(data->state == LV_INDEV_STATE_PRESSED && i->proc.wait_until_release) return;
549
550 if(i->proc.wait_until_release) {
551 i->proc.wait_until_release = 0;
552 i->proc.pr_timestamp = 0;
553 i->proc.long_pr_sent = 0;
554 i->proc.types.keypad.last_state = LV_INDEV_STATE_RELEASED; /*To skip the processing of release*/
555 }
556
557 /*Save the last keys before anything else.
558 *They need to be already saved if the function returns for any reason*/
559 lv_indev_state_t last_state = i->proc.types.keypad.last_state;
560 i->proc.types.keypad.last_state = data->state;
561 i->proc.types.keypad.last_key = data->key;
562
563 lv_group_t * g = i->group;
564 if(g == NULL) return;
565
566 indev_obj_act = lv_group_get_focused(g);
567 if(indev_obj_act == NULL) return;
568
569 /*Process the steps they are valid only with released button*/
570 if(data->state != LV_INDEV_STATE_RELEASED) {
571 data->enc_diff = 0;
572 }
573
574 /*Refresh the focused object. It might change due to lv_group_focus_prev/next*/
575 indev_obj_act = lv_group_get_focused(g);
576 if(indev_obj_act == NULL) return;
577
578 /*Button press happened*/
579 if(data->state == LV_INDEV_STATE_PRESSED && last_state == LV_INDEV_STATE_RELEASED) {
580 LV_LOG_INFO("pressed");
581
582 i->proc.pr_timestamp = lv_tick_get();
583
584 if(data->key == LV_KEY_ENTER) {
585 bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
586 lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
587 if(lv_group_get_editing(g) == true || editable_or_scrollable == false) {
588 lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
589 if(indev_reset_check(&i->proc)) return;
590 }
591 }
592 else if(data->key == LV_KEY_LEFT) {
593 /*emulate encoder left*/
594 data->enc_diff--;
595 }
596 else if(data->key == LV_KEY_RIGHT) {
597 /*emulate encoder right*/
598 data->enc_diff++;
599 }
600 else if(data->key == LV_KEY_ESC) {
601 /*Send the ESC as a normal KEY*/
602 lv_group_send_data(g, LV_KEY_ESC);
603 if(indev_reset_check(&i->proc)) return;
604
605 lv_event_send(indev_obj_act, LV_EVENT_CANCEL, indev_act);
606 if(indev_reset_check(&i->proc)) return;
607 }
608 /*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/
609 else {
610 lv_group_send_data(g, data->key);
611 if(indev_reset_check(&i->proc)) return;
612 }
613 }
614 /*Pressing*/
615 else if(data->state == LV_INDEV_STATE_PRESSED && last_state == LV_INDEV_STATE_PRESSED) {
616 /*Long press*/
617 if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver->long_press_time) {
618
619 i->proc.long_pr_sent = 1;
620 i->proc.longpr_rep_timestamp = lv_tick_get();
621
622 if(data->key == LV_KEY_ENTER) {
623 bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
624 lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
625
626 /*On enter long press toggle edit mode.*/
627 if(editable_or_scrollable) {
628 /*Don't leave edit mode if there is only one object (nowhere to navigate)*/
629 if(lv_group_get_obj_count(g) > 1) {
630 LV_LOG_INFO("toggling edit mode");
631 lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/
632 lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED); /*Remove the pressed state manually*/
633 }
634 }
635 /*If not editable then just send a long press Call the ancestor's event handler*/
636 else {
637 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
638 if(indev_reset_check(&i->proc)) return;
639 }
640 }
641
642 i->proc.long_pr_sent = 1;
643 }
644 /*Long press repeated time has elapsed?*/
645 else if(i->proc.long_pr_sent != 0 && lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver->long_press_repeat_time) {
646
647 i->proc.longpr_rep_timestamp = lv_tick_get();
648
649 if(data->key == LV_KEY_ENTER) {
650 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
651 if(indev_reset_check(&i->proc)) return;
652 }
653 else if(data->key == LV_KEY_LEFT) {
654 /*emulate encoder left*/
655 data->enc_diff--;
656 }
657 else if(data->key == LV_KEY_RIGHT) {
658 /*emulate encoder right*/
659 data->enc_diff++;
660 }
661 else {
662 lv_group_send_data(g, data->key);
663 if(indev_reset_check(&i->proc)) return;
664 }
665
666 }
667
668 }
669 /*Release happened*/
670 else if(data->state == LV_INDEV_STATE_RELEASED && last_state == LV_INDEV_STATE_PRESSED) {
671 LV_LOG_INFO("released");
672
673 if(data->key == LV_KEY_ENTER) {
674 bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
675 lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
676
677 /*The button was released on a non-editable object. Just send enter*/
678 if(editable_or_scrollable == false) {
679 lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
680 if(indev_reset_check(&i->proc)) return;
681
682 if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
683 if(indev_reset_check(&i->proc)) return;
684
685 lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
686 if(indev_reset_check(&i->proc)) return;
687
688 }
689 /*An object is being edited and the button is released.*/
690 else if(lv_group_get_editing(g)) {
691 /*Ignore long pressed enter release because it comes from mode switch*/
692 if(!i->proc.long_pr_sent || lv_group_get_obj_count(g) <= 1) {
693 lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
694 if(indev_reset_check(&i->proc)) return;
695
696 lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
697 if(indev_reset_check(&i->proc)) return;
698
699 lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
700 if(indev_reset_check(&i->proc)) return;
701
702 lv_group_send_data(g, LV_KEY_ENTER);
703 if(indev_reset_check(&i->proc)) return;
704 }
705 else {
706 lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED); /*Remove the pressed state manually*/
707 }
708 }
709 /*If the focused object is editable and now in navigate mode then on enter switch edit
710 mode*/
711 else if(!i->proc.long_pr_sent) {
712 LV_LOG_INFO("entering edit mode");
713 lv_group_set_editing(g, true); /*Set edit mode*/
714 }
715 }
716
717 i->proc.pr_timestamp = 0;
718 i->proc.long_pr_sent = 0;
719 }
720 indev_obj_act = NULL;
721
722 /*if encoder steps or simulated steps via left/right keys*/
723 if(data->enc_diff != 0) {
724 /*In edit mode send LEFT/RIGHT keys*/
725 if(lv_group_get_editing(g)) {
726 LV_LOG_INFO("rotated by %+d (edit)", data->enc_diff);
727 int32_t s;
728 if(data->enc_diff < 0) {
729 for(s = 0; s < -data->enc_diff; s++) {
730 lv_group_send_data(g, LV_KEY_LEFT);
731 if(indev_reset_check(&i->proc)) return;
732 }
733 }
734 else if(data->enc_diff > 0) {
735 for(s = 0; s < data->enc_diff; s++) {
736 lv_group_send_data(g, LV_KEY_RIGHT);
737 if(indev_reset_check(&i->proc)) return;
738 }
739 }
740 }
741 /*In navigate mode focus on the next/prev objects*/
742 else {
743 LV_LOG_INFO("rotated by %+d (nav)", data->enc_diff);
744 int32_t s;
745 if(data->enc_diff < 0) {
746 for(s = 0; s < -data->enc_diff; s++) {
747 lv_group_focus_prev(g);
748 if(indev_reset_check(&i->proc)) return;
749 }
750 }
751 else if(data->enc_diff > 0) {
752 for(s = 0; s < data->enc_diff; s++) {
753 lv_group_focus_next(g);
754 if(indev_reset_check(&i->proc)) return;
755 }
756 }
757 }
758 }
759 }
760
761 /**
762 * Process new points from an input device. indev->state.pressed has to be set
763 * @param indev pointer to an input device state
764 * @param x x coordinate of the next point
765 * @param y y coordinate of the next point
766 */
indev_button_proc(lv_indev_t * i,lv_indev_data_t * data)767 static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
768 {
769 /*Die gracefully if i->btn_points is NULL*/
770 if(i->btn_points == NULL) {
771 LV_LOG_WARN("btn_points is NULL");
772 return;
773 }
774
775 lv_coord_t x = i->btn_points[data->btn_id].x;
776 lv_coord_t y = i->btn_points[data->btn_id].y;
777
778 static lv_indev_state_t prev_state = LV_INDEV_STATE_RELEASED;
779 if(prev_state != data->state) {
780 if(data->state == LV_INDEV_STATE_PRESSED) {
781 LV_LOG_INFO("button %" LV_PRIu32 " is pressed (x:%d y:%d)", data->btn_id, x, y);
782 }
783 else {
784 LV_LOG_INFO("button %" LV_PRIu32 " is released (x:%d y:%d)", data->btn_id, x, y);
785 }
786 }
787
788 /*If a new point comes always make a release*/
789 if(data->state == LV_INDEV_STATE_PRESSED) {
790 if(i->proc.types.pointer.last_point.x != x ||
791 i->proc.types.pointer.last_point.y != y) {
792 indev_proc_release(&i->proc);
793 }
794 }
795
796 if(indev_reset_check(&i->proc)) return;
797
798 /*Save the new points*/
799 i->proc.types.pointer.act_point.x = x;
800 i->proc.types.pointer.act_point.y = y;
801
802 if(data->state == LV_INDEV_STATE_PRESSED) indev_proc_press(&i->proc);
803 else indev_proc_release(&i->proc);
804
805 if(indev_reset_check(&i->proc)) return;
806
807 i->proc.types.pointer.last_point.x = i->proc.types.pointer.act_point.x;
808 i->proc.types.pointer.last_point.y = i->proc.types.pointer.act_point.y;
809 }
810
811 /**
812 * Process the pressed state of LV_INDEV_TYPE_POINTER input devices
813 * @param indev pointer to an input device 'proc'
814 * @return LV_RES_OK: no indev reset required; LV_RES_INV: indev reset is required
815 */
indev_proc_press(_lv_indev_proc_t * proc)816 static void indev_proc_press(_lv_indev_proc_t * proc)
817 {
818 LV_LOG_INFO("pressed at x:%d y:%d", proc->types.pointer.act_point.x, proc->types.pointer.act_point.y);
819 indev_obj_act = proc->types.pointer.act_obj;
820
821 if(proc->wait_until_release != 0) return;
822
823 lv_disp_t * disp = indev_act->driver->disp;
824 bool new_obj_searched = false;
825
826 /*If there is no last object then search*/
827 if(indev_obj_act == NULL) {
828 indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_sys(disp), &proc->types.pointer.act_point);
829 if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_top(disp),
830 &proc->types.pointer.act_point);
831 if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_scr_act(disp),
832 &proc->types.pointer.act_point);
833 new_obj_searched = true;
834 }
835 /*If there is last object but it is not scrolled and not protected also search*/
836 else if(proc->types.pointer.scroll_obj == NULL &&
837 lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_PRESS_LOCK) == false) {
838 indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_sys(disp), &proc->types.pointer.act_point);
839 if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_top(disp),
840 &proc->types.pointer.act_point);
841 if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_scr_act(disp),
842 &proc->types.pointer.act_point);
843 new_obj_searched = true;
844 }
845
846 /*The last object might have scroll throw. Stop it manually*/
847 if(new_obj_searched && proc->types.pointer.last_obj) {
848 proc->types.pointer.scroll_throw_vect.x = 0;
849 proc->types.pointer.scroll_throw_vect.y = 0;
850 _lv_indev_scroll_throw_handler(proc);
851 if(indev_reset_check(proc)) return;
852 }
853
854 /*If a new object was found reset some variables and send a pressed event handler*/
855 if(indev_obj_act != proc->types.pointer.act_obj) {
856 proc->types.pointer.last_point.x = proc->types.pointer.act_point.x;
857 proc->types.pointer.last_point.y = proc->types.pointer.act_point.y;
858
859 /*If a new object found the previous was lost, so send a Call the ancestor's event handler*/
860 if(proc->types.pointer.act_obj != NULL) {
861 /*Save the obj because in special cases `act_obj` can change in the Call the ancestor's event handler function*/
862 lv_obj_t * last_obj = proc->types.pointer.act_obj;
863
864 lv_event_send(last_obj, LV_EVENT_PRESS_LOST, indev_act);
865 if(indev_reset_check(proc)) return;
866 }
867
868 proc->types.pointer.act_obj = indev_obj_act; /*Save the pressed object*/
869 proc->types.pointer.last_obj = indev_obj_act;
870
871 if(indev_obj_act != NULL) {
872 /*Save the time when the obj pressed to count long press time.*/
873 proc->pr_timestamp = lv_tick_get();
874 proc->long_pr_sent = 0;
875 proc->types.pointer.scroll_sum.x = 0;
876 proc->types.pointer.scroll_sum.y = 0;
877 proc->types.pointer.scroll_dir = LV_DIR_NONE;
878 proc->types.pointer.gesture_dir = LV_DIR_NONE;
879 proc->types.pointer.gesture_sent = 0;
880 proc->types.pointer.gesture_sum.x = 0;
881 proc->types.pointer.gesture_sum.y = 0;
882 proc->types.pointer.vect.x = 0;
883 proc->types.pointer.vect.y = 0;
884
885 /*Call the ancestor's event handler about the press*/
886 lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
887 if(indev_reset_check(proc)) return;
888
889 if(indev_act->proc.wait_until_release) return;
890
891 /*Handle focus*/
892 indev_click_focus(&indev_act->proc);
893 if(indev_reset_check(proc)) return;
894
895 }
896 }
897
898 /*Calculate the vector and apply a low pass filter: new value = 0.5 * old_value + 0.5 * new_value*/
899 proc->types.pointer.vect.x = proc->types.pointer.act_point.x - proc->types.pointer.last_point.x;
900 proc->types.pointer.vect.y = proc->types.pointer.act_point.y - proc->types.pointer.last_point.y;
901
902 proc->types.pointer.scroll_throw_vect.x = (proc->types.pointer.scroll_throw_vect.x + proc->types.pointer.vect.x) / 2;
903 proc->types.pointer.scroll_throw_vect.y = (proc->types.pointer.scroll_throw_vect.y + proc->types.pointer.vect.y) / 2;
904
905 proc->types.pointer.scroll_throw_vect_ori = proc->types.pointer.scroll_throw_vect;
906
907 if(indev_obj_act) {
908 lv_event_send(indev_obj_act, LV_EVENT_PRESSING, indev_act);
909 if(indev_reset_check(proc)) return;
910
911 if(indev_act->proc.wait_until_release) return;
912
913 _lv_indev_scroll_handler(proc);
914 if(indev_reset_check(proc)) return;
915 indev_gesture(proc);
916 if(indev_reset_check(proc)) return;
917
918 /*If there is no scrolling then check for long press time*/
919 if(proc->types.pointer.scroll_obj == NULL && proc->long_pr_sent == 0) {
920 /*Call the ancestor's event handler about the long press if enough time elapsed*/
921 if(lv_tick_elaps(proc->pr_timestamp) > indev_act->driver->long_press_time) {
922 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
923 if(indev_reset_check(proc)) return;
924
925 /*Mark the Call the ancestor's event handler sending to do not send it again*/
926 proc->long_pr_sent = 1;
927
928 /*Save the long press time stamp for the long press repeat handler*/
929 proc->longpr_rep_timestamp = lv_tick_get();
930 }
931 }
932
933 /*Send long press repeated Call the ancestor's event handler*/
934 if(proc->types.pointer.scroll_obj == NULL && proc->long_pr_sent == 1) {
935 /*Call the ancestor's event handler about the long press repeat if enough time elapsed*/
936 if(lv_tick_elaps(proc->longpr_rep_timestamp) > indev_act->driver->long_press_repeat_time) {
937 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
938 if(indev_reset_check(proc)) return;
939 proc->longpr_rep_timestamp = lv_tick_get();
940 }
941 }
942 }
943 }
944
945 /**
946 * Process the released state of LV_INDEV_TYPE_POINTER input devices
947 * @param proc pointer to an input device 'proc'
948 */
indev_proc_release(_lv_indev_proc_t * proc)949 static void indev_proc_release(_lv_indev_proc_t * proc)
950 {
951 if(proc->wait_until_release != 0) {
952 lv_event_send(proc->types.pointer.act_obj, LV_EVENT_PRESS_LOST, indev_act);
953 if(indev_reset_check(proc)) return;
954
955 proc->types.pointer.act_obj = NULL;
956 proc->types.pointer.last_obj = NULL;
957 proc->pr_timestamp = 0;
958 proc->longpr_rep_timestamp = 0;
959 proc->wait_until_release = 0;
960 }
961 indev_obj_act = proc->types.pointer.act_obj;
962 lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj;
963
964 /*Forget the act obj and send a released Call the ancestor's event handler*/
965 if(indev_obj_act) {
966 LV_LOG_INFO("released");
967
968 /*Send RELEASE Call the ancestor's event handler and event*/
969 lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
970 if(indev_reset_check(proc)) return;
971
972 /*Send CLICK if no scrolling*/
973 if(scroll_obj == NULL) {
974 if(proc->long_pr_sent == 0) {
975 lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
976 if(indev_reset_check(proc)) return;
977 }
978
979 lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
980 if(indev_reset_check(proc)) return;
981 }
982
983 proc->types.pointer.act_obj = NULL;
984 proc->pr_timestamp = 0;
985 proc->longpr_rep_timestamp = 0;
986
987 /*Get the transformed vector with this object*/
988 if(scroll_obj) {
989 int16_t angle = 0;
990 int16_t zoom = 256;
991 lv_point_t pivot = { 0, 0 };
992 lv_obj_t * parent = scroll_obj;
993 while(parent) {
994 angle += lv_obj_get_style_transform_angle(parent, 0);
995 zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256);
996 parent = lv_obj_get_parent(parent);
997 }
998
999 if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) {
1000 angle = -angle;
1001 zoom = (256 * 256) / zoom;
1002 lv_point_transform(&proc->types.pointer.scroll_throw_vect, angle, zoom, &pivot);
1003 lv_point_transform(&proc->types.pointer.scroll_throw_vect_ori, angle, zoom, &pivot);
1004 }
1005 }
1006
1007 }
1008
1009 /*The reset can be set in the Call the ancestor's event handler function.
1010 * In case of reset query ignore the remaining parts.*/
1011 if(scroll_obj) {
1012 _lv_indev_scroll_throw_handler(proc);
1013 if(indev_reset_check(proc)) return;
1014 }
1015 }
1016
1017 /**
1018 * Process a new point from LV_INDEV_TYPE_BUTTON input device
1019 * @param i pointer to an input device
1020 * @param data pointer to the data read from the input device
1021 * Reset input device if a reset query has been sent to it
1022 * @param indev pointer to an input device
1023 */
indev_proc_reset_query_handler(lv_indev_t * indev)1024 static void indev_proc_reset_query_handler(lv_indev_t * indev)
1025 {
1026 if(indev->proc.reset_query) {
1027 indev->proc.types.pointer.act_obj = NULL;
1028 indev->proc.types.pointer.last_obj = NULL;
1029 indev->proc.types.pointer.scroll_obj = NULL;
1030 indev->proc.long_pr_sent = 0;
1031 indev->proc.pr_timestamp = 0;
1032 indev->proc.longpr_rep_timestamp = 0;
1033 indev->proc.types.pointer.scroll_sum.x = 0;
1034 indev->proc.types.pointer.scroll_sum.y = 0;
1035 indev->proc.types.pointer.scroll_dir = LV_DIR_NONE;
1036 indev->proc.types.pointer.scroll_throw_vect.x = 0;
1037 indev->proc.types.pointer.scroll_throw_vect.y = 0;
1038 indev->proc.types.pointer.gesture_sum.x = 0;
1039 indev->proc.types.pointer.gesture_sum.y = 0;
1040 indev->proc.reset_query = 0;
1041 indev_obj_act = NULL;
1042 }
1043 }
1044
1045 /**
1046 * Handle focus/defocus on click for POINTER input devices
1047 * @param proc pointer to the state of the indev
1048 */
indev_click_focus(_lv_indev_proc_t * proc)1049 static void indev_click_focus(_lv_indev_proc_t * proc)
1050 {
1051 /*Handle click focus*/
1052 if(lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_CLICK_FOCUSABLE) == false ||
1053 proc->types.pointer.last_pressed == indev_obj_act) {
1054 return;
1055 }
1056
1057 lv_group_t * g_act = lv_obj_get_group(indev_obj_act);
1058 lv_group_t * g_prev = proc->types.pointer.last_pressed ? lv_obj_get_group(proc->types.pointer.last_pressed) : NULL;
1059
1060 /*If both the last and act. obj. are in the same group (or have no group)*/
1061 if(g_act == g_prev) {
1062 /*The objects are in a group*/
1063 if(g_act) {
1064 lv_group_focus_obj(indev_obj_act);
1065 if(indev_reset_check(proc)) return;
1066 }
1067 /*The object are not in group*/
1068 else {
1069 if(proc->types.pointer.last_pressed) {
1070 lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, indev_act);
1071 if(indev_reset_check(proc)) return;
1072 }
1073
1074 lv_event_send(indev_obj_act, LV_EVENT_FOCUSED, indev_act);
1075 if(indev_reset_check(proc)) return;
1076 }
1077 }
1078 /*The object are not in the same group (in different groups or one has no group)*/
1079 else {
1080 /*If the prev. obj. is not in a group then defocus it.*/
1081 if(g_prev == NULL && proc->types.pointer.last_pressed) {
1082 lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, indev_act);
1083 if(indev_reset_check(proc)) return;
1084 }
1085 /*Focus on a non-group object*/
1086 else {
1087 if(proc->types.pointer.last_pressed) {
1088 /*If the prev. object also wasn't in a group defocus it*/
1089 if(g_prev == NULL) {
1090 lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, indev_act);
1091 if(indev_reset_check(proc)) return;
1092 }
1093 /*If the prev. object also was in a group at least "LEAVE" it instead of defocus*/
1094 else {
1095 lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_LEAVE, indev_act);
1096 if(indev_reset_check(proc)) return;
1097 }
1098 }
1099 }
1100
1101 /*Focus to the act. in its group*/
1102 if(g_act) {
1103 lv_group_focus_obj(indev_obj_act);
1104 if(indev_reset_check(proc)) return;
1105 }
1106 else {
1107 lv_event_send(indev_obj_act, LV_EVENT_FOCUSED, indev_act);
1108 if(indev_reset_check(proc)) return;
1109 }
1110 }
1111 proc->types.pointer.last_pressed = indev_obj_act;
1112 }
1113
1114 /**
1115 * Handle the gesture of indev_proc_p->types.pointer.act_obj
1116 * @param indev pointer to an input device state
1117 */
indev_gesture(_lv_indev_proc_t * proc)1118 void indev_gesture(_lv_indev_proc_t * proc)
1119 {
1120
1121 if(proc->types.pointer.scroll_obj) return;
1122 if(proc->types.pointer.gesture_sent) return;
1123
1124 lv_obj_t * gesture_obj = proc->types.pointer.act_obj;
1125
1126 /*If gesture parent is active check recursively the gesture attribute*/
1127 while(gesture_obj && lv_obj_has_flag(gesture_obj, LV_OBJ_FLAG_GESTURE_BUBBLE)) {
1128 gesture_obj = lv_obj_get_parent(gesture_obj);
1129 }
1130
1131 if(gesture_obj == NULL) return;
1132
1133 if((LV_ABS(proc->types.pointer.vect.x) < indev_act->driver->gesture_min_velocity) &&
1134 (LV_ABS(proc->types.pointer.vect.y) < indev_act->driver->gesture_min_velocity)) {
1135 proc->types.pointer.gesture_sum.x = 0;
1136 proc->types.pointer.gesture_sum.y = 0;
1137 }
1138
1139 /*Count the movement by gesture*/
1140 proc->types.pointer.gesture_sum.x += proc->types.pointer.vect.x;
1141 proc->types.pointer.gesture_sum.y += proc->types.pointer.vect.y;
1142
1143 if((LV_ABS(proc->types.pointer.gesture_sum.x) > indev_act->driver->gesture_limit) ||
1144 (LV_ABS(proc->types.pointer.gesture_sum.y) > indev_act->driver->gesture_limit)) {
1145
1146 proc->types.pointer.gesture_sent = 1;
1147
1148 if(LV_ABS(proc->types.pointer.gesture_sum.x) > LV_ABS(proc->types.pointer.gesture_sum.y)) {
1149 if(proc->types.pointer.gesture_sum.x > 0)
1150 proc->types.pointer.gesture_dir = LV_DIR_RIGHT;
1151 else
1152 proc->types.pointer.gesture_dir = LV_DIR_LEFT;
1153 }
1154 else {
1155 if(proc->types.pointer.gesture_sum.y > 0)
1156 proc->types.pointer.gesture_dir = LV_DIR_BOTTOM;
1157 else
1158 proc->types.pointer.gesture_dir = LV_DIR_TOP;
1159 }
1160
1161 lv_event_send(gesture_obj, LV_EVENT_GESTURE, indev_act);
1162 if(indev_reset_check(proc)) return;
1163 }
1164 }
1165
1166 /**
1167 * Checks if the reset_query flag has been set. If so, perform necessary global indev cleanup actions
1168 * @param proc pointer to an input device 'proc'
1169 * @return true if indev query should be immediately truncated.
1170 */
indev_reset_check(_lv_indev_proc_t * proc)1171 static bool indev_reset_check(_lv_indev_proc_t * proc)
1172 {
1173 if(proc->reset_query) {
1174 indev_obj_act = NULL;
1175 }
1176
1177 return proc->reset_query ? true : false;
1178 }
1179