From d96a2c890c3ffccad8485c82327ffed281aa075f Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 13 Oct 2020 16:35:00 +0200 Subject: [PATCH] indev scroll clean up --- src/lv_core/lv_indev.c | 2 +- src/lv_core/lv_indev_scroll.c | 331 +++++++++++++++++----------------- 2 files changed, 171 insertions(+), 162 deletions(-) diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 94055b903..a9ca7e463 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -211,7 +211,7 @@ void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj) indev->cursor = cur_obj; lv_obj_set_parent(indev->cursor, lv_disp_get_layer_sys(indev->driver.disp)); lv_obj_set_pos(indev->cursor, indev->proc.types.pointer.act_point.x, indev->proc.types.pointer.act_point.y); - lv_obj_add_flag(indev->cursor, LV_OBJ_FLAG_CLICKABLE); + lv_obj_clear_flag(indev->cursor, LV_OBJ_FLAG_CLICKABLE); } #if LV_USE_GROUP diff --git a/src/lv_core/lv_indev_scroll.c b/src/lv_core/lv_indev_scroll.c index 11469f4e2..c9cd02ee2 100644 --- a/src/lv_core/lv_indev_scroll.c +++ b/src/lv_core/lv_indev_scroll.c @@ -21,7 +21,8 @@ /********************** * STATIC PROTOTYPES **********************/ - +static lv_obj_t * find_scroll_obj(lv_indev_proc_t * proc); +static void init_scroll_limits(lv_indev_proc_t * proc); static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs); static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs); static void scroll_limit_diff(lv_indev_proc_t * proc, lv_coord_t * diff_x, lv_coord_t * diff_y); @@ -47,174 +48,24 @@ static lv_coord_t elastic_diff(lv_obj_t * obj, lv_coord_t diff, lv_coord_t scrol */ void _lv_scroll_handler(lv_indev_proc_t * proc) { - lv_obj_t * scroll_candidate_obj = NULL; - lv_scroll_dir_t dirs_candidate = LV_SCROLL_DIR_NONE; - - lv_indev_t * indev_act = lv_indev_get_act(); - lv_coord_t scroll_limit = indev_act->driver.scroll_limit; - + lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; /*If there is no scroll object yet try to find one*/ - if(proc->types.pointer.scroll_obj == NULL) { + if(scroll_obj == NULL) { proc->types.pointer.scroll_sum.x += proc->types.pointer.vect.x; proc->types.pointer.scroll_sum.y += proc->types.pointer.vect.y; - proc->types.pointer.scroll_obj = proc->types.pointer.act_obj; + scroll_obj = find_scroll_obj(proc); + if(scroll_obj == NULL) return; - /* Go until find an scrollable object in the current direction - * More precisely: - * 1. Check the pressed object and all of its ancestors and try to find an object which is scrollable - * 2. Scrollable means it has some content out of it's area - * 3. If an object can be scrolled into the current direction then use it ("real match"") - * 4. If can be scrolled on the current axis (hor/ver) save it as candidate (at least show an elastic scroll effect) - * 5. Use the last candidate. Always the "deepest" parent or the object from point 3 */ - while(proc->types.pointer.scroll_obj) { - if(lv_obj_has_flag(proc->types.pointer.scroll_obj, LV_OBJ_FLAG_SCROLLABLE) == false) { - proc->types.pointer.scroll_obj = lv_obj_get_parent(proc->types.pointer.scroll_obj); - continue; - } + init_scroll_limits(proc); - /*Decide if it's a horizontal or vertical scroll*/ - bool hor_en = false; - bool ver_en = false; - if(LV_MATH_ABS(proc->types.pointer.scroll_sum.x) > LV_MATH_ABS(proc->types.pointer.scroll_sum.y)) { - hor_en = true; - } - else { - ver_en = true; - } - - /*Consider both up-down or left/right scrollable according to the current direction*/ - bool up_en = ver_en; - bool down_en = ver_en; - bool left_en = hor_en; - bool right_en = hor_en; - - /*The object might have disabled some directions.*/ - lv_dir_t scroll_dir = proc->types.pointer.scroll_obj->scroll_dir; - if((scroll_dir & LV_DIR_LEFT) == 0) left_en = false; - if((scroll_dir & LV_DIR_RIGHT) == 0) right_en = false; - if((scroll_dir & LV_DIR_TOP) == 0) up_en = false; - if((scroll_dir & LV_DIR_BOTTOM) == 0) down_en = false; - - /*The object is scrollable to a direction if its content overflow in that direction. */ - lv_coord_t st = lv_obj_get_scroll_top(proc->types.pointer.scroll_obj); - lv_coord_t sb = lv_obj_get_scroll_bottom(proc->types.pointer.scroll_obj); - lv_coord_t sl = lv_obj_get_scroll_left(proc->types.pointer.scroll_obj); - lv_coord_t sr = lv_obj_get_scroll_right(proc->types.pointer.scroll_obj); - - /* If this object is scrollable into the current scroll direction then save it as a candidate. - * It's important only to be scrollable on the current axis (hor/ver) because if the scroll - * is propagated to this object it can show at least elastic scroll effect. - * But if not hor/ver scrollable do not scroll it at all (so it's not a good candidate) */ - if((st > 0 || sb > 0) && - ((up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || - (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit))) - { - scroll_candidate_obj = proc->types.pointer.scroll_obj; - dirs_candidate = LV_SCROLL_DIR_VER; - } - - if((sl > 0 || sr > 0) && - ((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || - (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit))) - { - scroll_candidate_obj = proc->types.pointer.scroll_obj; - dirs_candidate = LV_SCROLL_DIR_HOR; - } - - if(st <= 0) up_en = false; - if(sb <= 0) down_en = false; - if(sl <= 0) left_en = false; - if(sr <= 0) right_en = false; - - /*If the object really can be scrolled into the current direction the use it. */ - if((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || - (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit) || - (up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || - (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit)) - { - proc->types.pointer.scroll_dir = hor_en ? LV_SCROLL_DIR_HOR : LV_SCROLL_DIR_VER; - break; - } - - /*Try the parent */ - proc->types.pointer.scroll_obj = lv_obj_get_parent(proc->types.pointer.scroll_obj); - } - - /*Use the last candidate*/ - if(proc->types.pointer.scroll_obj == NULL) { - if(scroll_candidate_obj) { - proc->types.pointer.scroll_dir = dirs_candidate; - proc->types.pointer.scroll_obj = scroll_candidate_obj; - } else { - return; - } - } - - proc->types.pointer.scroll_sum.x = 0; - proc->types.pointer.scroll_sum.y = 0; - - lv_obj_t * obj = proc->types.pointer.scroll_obj; - /*If there no STOP allow scrolling anywhere*/ - if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_STOP) == false) { - lv_area_set(&proc->types.pointer.scroll_area, LV_COORD_MIN, LV_COORD_MIN, LV_COORD_MAX, LV_COORD_MAX); - } - /*With STOP limit the scrolling to the perv and next snap point*/ - else { - switch(obj->snap_align_y) { - case LV_SCROLL_SNAP_ALIGN_START: - proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, obj->coords.y1 + 1, LV_COORD_MAX, 0); - proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, obj->coords.y1 - 1, 0); - break; - case LV_SCROLL_SNAP_ALIGN_END: - proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, obj->coords.y2, LV_COORD_MAX, 0); - proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, obj->coords.y2, 0); - break; - case LV_SCROLL_SNAP_ALIGN_CENTER: { - lv_coord_t y_mid = obj->coords.y1 + lv_area_get_height(&obj->coords) / 2; - proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, y_mid + 1, LV_COORD_MAX, 0); - proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, y_mid - 1, 0); - break; - } - default: - proc->types.pointer.scroll_area.y1 = LV_COORD_MIN; - proc->types.pointer.scroll_area.y2 = LV_COORD_MAX; - break; - } - - switch(obj->snap_align_x) { - case LV_SCROLL_SNAP_ALIGN_START: - proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, obj->coords.x1, LV_COORD_MAX, 0); - proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, obj->coords.x1, 0); - break; - case LV_SCROLL_SNAP_ALIGN_END: - proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, obj->coords.x2, LV_COORD_MAX, 0); - proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, obj->coords.x2, 0); - break; - case LV_SCROLL_SNAP_ALIGN_CENTER: { - lv_coord_t x_mid = obj->coords.x1 + lv_area_get_width(&obj->coords) / 2; - proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, x_mid + 1, LV_COORD_MAX, 0); - proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, x_mid - 1, 0); - break; - } - default: - proc->types.pointer.scroll_area.x1 = LV_COORD_MIN; - proc->types.pointer.scroll_area.x2 = LV_COORD_MAX; - break; - } - } - - lv_signal_send(obj, LV_SIGNAL_SCROLL_BEGIN, indev_act); + lv_indev_t * indev_act = lv_indev_get_act(); + lv_signal_send(scroll_obj, LV_SIGNAL_SCROLL_BEGIN, indev_act); if(proc->reset_query) return; - lv_event_send(obj, LV_EVENT_SCROLL_BEGIN, indev_act); + lv_event_send(scroll_obj, LV_EVENT_SCROLL_BEGIN, indev_act); if(proc->reset_query) return; - } - /*If there is no scroll object there is nothing to do*/ - lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; - if(scroll_obj == NULL) return; - /*Set new position or scroll if the vector is not zero*/ if(proc->types.pointer.vect.x != 0 || proc->types.pointer.vect.y != 0) { lv_coord_t diff_x = 0; @@ -305,13 +156,12 @@ void _lv_scroll_throw_handler(lv_indev_proc_t * proc) else { lv_coord_t diff_x = scroll_throw_predict_x(proc); proc->types.pointer.scroll_throw_vect.x = 0; - scroll_limit_diff(proc, NULL, &diff_x); + scroll_limit_diff(proc, &diff_x, NULL); lv_coord_t x = find_snap_point_x(scroll_obj, LV_COORD_MIN, LV_COORD_MAX, diff_x); lv_obj_scroll_by(scroll_obj, x + diff_x, 0, LV_ANIM_ON); } } - /*Check if the scroll has finished */ if(proc->types.pointer.scroll_throw_vect.x == 0 && proc->types.pointer.scroll_throw_vect.y == 0) { /*Revert if scrolled in*/ @@ -388,6 +238,165 @@ lv_coord_t _lv_scroll_throw_predict(lv_indev_t * indev, lv_dir_t dir) * STATIC FUNCTIONS **********************/ +static lv_obj_t * find_scroll_obj(lv_indev_proc_t * proc) +{ + lv_obj_t * obj_candidate = NULL; + lv_dir_t dir_candidate = LV_DIR_NONE; + lv_indev_t * indev_act = lv_indev_get_act(); + lv_coord_t scroll_limit = indev_act->driver.scroll_limit; + + /* Go until find an scrollable object in the current direction + * More precisely: + * 1. Check the pressed object and all of its ancestors and try to find an object which is scrollable + * 2. Scrollable means it has some content out of it's area + * 3. If an object can be scrolled into the current direction then use it ("real match"") + * 4. If can be scrolled on the current axis (hor/ver) save it as candidate (at least show an elastic scroll effect) + * 5. Use the last candidate. Always the "deepest" parent or the object from point 3 */ + lv_obj_t * obj_act = proc->types.pointer.act_obj; + while(obj_act) { + if(lv_obj_has_flag(obj_act, LV_OBJ_FLAG_SCROLLABLE) == false) { + obj_act = lv_obj_get_parent(obj_act); + continue; + } + + /*Decide if it's a horizontal or vertical scroll*/ + bool hor_en = false; + bool ver_en = false; + if(LV_MATH_ABS(proc->types.pointer.scroll_sum.x) > LV_MATH_ABS(proc->types.pointer.scroll_sum.y)) { + hor_en = true; + } + else { + ver_en = true; + } + + /*Consider both up-down or left/right scrollable according to the current direction*/ + bool up_en = ver_en; + bool down_en = ver_en; + bool left_en = hor_en; + bool right_en = hor_en; + + /*The object might have disabled some directions.*/ + lv_dir_t scroll_dir = obj_act->scroll_dir; + if((scroll_dir & LV_DIR_LEFT) == 0) left_en = false; + if((scroll_dir & LV_DIR_RIGHT) == 0) right_en = false; + if((scroll_dir & LV_DIR_TOP) == 0) up_en = false; + if((scroll_dir & LV_DIR_BOTTOM) == 0) down_en = false; + + /*The object is scrollable to a direction if its content overflow in that direction. */ + lv_coord_t st = lv_obj_get_scroll_top(obj_act); + lv_coord_t sb = lv_obj_get_scroll_bottom(obj_act); + lv_coord_t sl = lv_obj_get_scroll_left(obj_act); + lv_coord_t sr = lv_obj_get_scroll_right(obj_act); + + /* If this object is scrollable into the current scroll direction then save it as a candidate. + * It's important only to be scrollable on the current axis (hor/ver) because if the scroll + * is propagated to this object it can show at least elastic scroll effect. + * But if not hor/ver scrollable do not scroll it at all (so it's not a good candidate) */ + if((st > 0 || sb > 0) && + ((up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || + (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit))) + { + obj_candidate = obj_act; + dir_candidate = LV_SCROLL_DIR_VER; + } + + if((sl > 0 || sr > 0) && + ((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || + (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit))) + { + obj_candidate = obj_act; + dir_candidate = LV_SCROLL_DIR_HOR; + } + + if(st <= 0) up_en = false; + if(sb <= 0) down_en = false; + if(sl <= 0) left_en = false; + if(sr <= 0) right_en = false; + + /*If the object really can be scrolled into the current direction the use it. */ + if((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || + (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit) || + (up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || + (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit)) + { + proc->types.pointer.scroll_dir = hor_en ? LV_SCROLL_DIR_HOR : LV_SCROLL_DIR_VER; + break; + } + + /*Try the parent */ + obj_act = lv_obj_get_parent(obj_act); + } + + /*Use the last candidate*/ + if(obj_candidate) { + proc->types.pointer.scroll_dir = dir_candidate; + proc->types.pointer.scroll_obj = obj_candidate; + proc->types.pointer.scroll_sum.x = 0; + proc->types.pointer.scroll_sum.y = 0; + } + + return obj_candidate; +} + +static void init_scroll_limits(lv_indev_proc_t * proc) +{ + lv_obj_t * obj = proc->types.pointer.scroll_obj; + /*If there no STOP allow scrolling anywhere*/ + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_STOP) == false) { + lv_area_set(&proc->types.pointer.scroll_area, LV_COORD_MIN, LV_COORD_MIN, LV_COORD_MAX, LV_COORD_MAX); + } + /*With STOP limit the scrolling to the perv and next snap point*/ + else { + switch(obj->snap_align_y) { + case LV_SCROLL_SNAP_ALIGN_START: + proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, obj->coords.y1 + 1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, obj->coords.y1 - 1, 0); + break; + case LV_SCROLL_SNAP_ALIGN_END: + proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, obj->coords.y2, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, obj->coords.y2, 0); + break; + case LV_SCROLL_SNAP_ALIGN_CENTER: { + lv_coord_t y_mid = obj->coords.y1 + lv_area_get_height(&obj->coords) / 2; + proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, y_mid + 1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, y_mid - 1, 0); + break; + } + default: + proc->types.pointer.scroll_area.y1 = LV_COORD_MIN; + proc->types.pointer.scroll_area.y2 = LV_COORD_MAX; + break; + } + + switch(obj->snap_align_x) { + case LV_SCROLL_SNAP_ALIGN_START: + proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, obj->coords.x1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, obj->coords.x1, 0); + break; + case LV_SCROLL_SNAP_ALIGN_END: + proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, obj->coords.x2, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, obj->coords.x2, 0); + break; + case LV_SCROLL_SNAP_ALIGN_CENTER: { + lv_coord_t x_mid = obj->coords.x1 + lv_area_get_width(&obj->coords) / 2; + proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, x_mid + 1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, x_mid - 1, 0); + break; + } + default: + proc->types.pointer.scroll_area.x1 = LV_COORD_MIN; + proc->types.pointer.scroll_area.x2 = LV_COORD_MAX; + break; + } + } + + /*Allow scrolling on the edges. It will be reverted to the edge due to snapping anyway*/ + if(proc->types.pointer.scroll_area.x1 == 0) proc->types.pointer.scroll_area.x1 = LV_COORD_MIN; + if(proc->types.pointer.scroll_area.x2 == 0) proc->types.pointer.scroll_area.x2 = LV_COORD_MAX; + if(proc->types.pointer.scroll_area.y1 == 0) proc->types.pointer.scroll_area.y1 = LV_COORD_MIN; + if(proc->types.pointer.scroll_area.y2 == 0) proc->types.pointer.scroll_area.y2 = LV_COORD_MAX; +} + static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs) { if(obj->snap_align_x == LV_SCROLL_SNAP_ALIGN_NONE) return 0;