diff --git a/examples/scroll/lv_example_scroll_2.c b/examples/scroll/lv_example_scroll_2.c index f4c2bd0d5f..5dde48f5d5 100644 --- a/examples/scroll/lv_example_scroll_2.c +++ b/examples/scroll/lv_example_scroll_2.c @@ -20,12 +20,11 @@ void lv_example_scroll_2(void) lv_obj_set_size(panel, 280, 150); lv_obj_set_scroll_snap_x(panel, LV_SCROLL_SNAP_CENTER); lv_obj_set_layout(panel, &lv_flex_queue); - lv_obj_center(panel); + lv_obj_center(panel); uint32_t i; for(i = 0; i < 10; i++) { lv_obj_t * btn = lv_btn_create(panel, NULL); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_SCROLL_ON_FOCUS); /* It does similar thing than snapping so disable it.*/ lv_obj_set_size(btn, 150, 100); lv_obj_t * label = lv_label_create(btn, NULL); diff --git a/examples/widgets/tabview/lv_example_tabview_1.c b/examples/widgets/tabview/lv_example_tabview_1.c index 3a233a3cd3..9471291eef 100644 --- a/examples/widgets/tabview/lv_example_tabview_1.c +++ b/examples/widgets/tabview/lv_example_tabview_1.c @@ -35,5 +35,8 @@ void lv_example_tabview_1(void) label = lv_label_create(tab3, NULL); lv_label_set_text(label, "Third tab"); + + lv_obj_scroll_to_view_recursive(label, 1); + } #endif diff --git a/src/lv_core/lv_indev_scroll.c b/src/lv_core/lv_indev_scroll.c index c071096f67..f1ea3b6de6 100644 --- a/src/lv_core/lv_indev_scroll.c +++ b/src/lv_core/lv_indev_scroll.c @@ -28,7 +28,7 @@ static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coo static void scroll_limit_diff(lv_indev_proc_t * proc, lv_coord_t * diff_x, lv_coord_t * diff_y); static lv_coord_t scroll_throw_predict_y(lv_indev_proc_t * proc); static lv_coord_t scroll_throw_predict_x(lv_indev_proc_t * proc); -static lv_coord_t elastic_diff(lv_obj_t * obj, lv_coord_t diff, lv_coord_t scroll_start, lv_coord_t scroll_end, lv_dir_t dir); +static lv_coord_t elastic_diff(lv_obj_t * scroll_obj, lv_coord_t diff, lv_coord_t scroll_start, lv_coord_t scroll_end, lv_dir_t dir); /********************** * STATIC VARIABLES @@ -420,6 +420,9 @@ static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coo lv_coord_t dist = LV_COORD_MAX; + lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); + lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); + uint32_t i; for(i = 0; i < lv_obj_get_child_cnt(obj); i++) { lv_obj_t * child = lv_obj_get_child(obj, i); @@ -429,15 +432,15 @@ static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coo switch(align) { case LV_SCROLL_SNAP_START: x_child = child->coords.x1; - x_parent = obj->coords.x1; + x_parent = obj->coords.x1 + pad_left; break; case LV_SCROLL_SNAP_END: x_child = child->coords.x2; - x_parent = obj->coords.x2; + x_parent = obj->coords.x2 - pad_right; break; case LV_SCROLL_SNAP_CENTER: x_child = child->coords.x1 + lv_area_get_width(&child->coords) / 2; - x_parent = obj->coords.x1 + lv_area_get_width(&obj->coords) / 2; + x_parent = obj->coords.x1 + pad_left + (lv_area_get_width(&obj->coords) - pad_left - pad_right) / 2; } x_child += ofs; @@ -467,6 +470,9 @@ static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coo lv_coord_t dist = LV_COORD_MAX; + lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); + lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); + uint32_t i; for(i = 0; i < lv_obj_get_child_cnt(obj); i++) { lv_obj_t * child = lv_obj_get_child(obj, i); @@ -476,15 +482,15 @@ static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coo switch(align) { case LV_SCROLL_SNAP_START: y_child = child->coords.y1; - y_parent = obj->coords.y1; + y_parent = obj->coords.y1 + pad_top; break; case LV_SCROLL_SNAP_END: y_child = child->coords.y2; - y_parent = obj->coords.y2; + y_parent = obj->coords.y2 - pad_bottom; break; case LV_SCROLL_SNAP_CENTER: y_child = child->coords.y1 + lv_area_get_height(&child->coords) / 2; - y_parent = obj->coords.y1 + lv_area_get_height(&obj->coords) / 2; + y_parent = obj->coords.y1 + pad_top + (lv_area_get_height(&obj->coords) - pad_top - pad_bottom) / 2; } y_child += ofs; @@ -554,52 +560,58 @@ static lv_coord_t scroll_throw_predict_x(lv_indev_proc_t * proc) return move; } -static lv_coord_t elastic_diff(lv_obj_t * obj, lv_coord_t diff, lv_coord_t scroll_start, lv_coord_t scroll_end, lv_dir_t dir) +static lv_coord_t elastic_diff(lv_obj_t * scroll_obj, lv_coord_t diff, lv_coord_t scroll_start, lv_coord_t scroll_end, lv_dir_t dir) { - if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_ELASTIC)) { + if(lv_obj_has_flag(scroll_obj, LV_OBJ_FLAG_SCROLL_ELASTIC)) { /* If there is snapping in the current direction don't use the elastic factor because * it's natural that the first and last items are scrolled (snapped) in. */ lv_scroll_snap_t snap; - snap = dir == LV_DIR_HOR ? lv_obj_get_scroll_snap_x(obj) : lv_obj_get_scroll_snap_y(obj); + snap = dir == LV_DIR_HOR ? lv_obj_get_scroll_snap_x(scroll_obj) : lv_obj_get_scroll_snap_y(scroll_obj); lv_obj_t * act_obj = lv_indev_get_obj_act(); - lv_coord_t scroll_obj_point = 0; + lv_coord_t snap_point = 0; lv_coord_t act_obj_point = 0; if(dir == LV_DIR_HOR) { + lv_coord_t pad_left = lv_obj_get_style_pad_left(scroll_obj, LV_PART_MAIN); + lv_coord_t pad_right = lv_obj_get_style_pad_right(scroll_obj, LV_PART_MAIN); + switch(snap) { case LV_SCROLL_SNAP_CENTER: - scroll_obj_point = lv_area_get_width(&obj->coords) / 2 + obj->coords.x1; + snap_point = pad_left + (lv_area_get_width(&scroll_obj->coords) - pad_left - pad_right) / 2 + scroll_obj->coords.x1; act_obj_point = lv_area_get_width(&act_obj->coords) / 2 + act_obj->coords.x1; break; case LV_SCROLL_SNAP_START: - scroll_obj_point = obj->coords.x1; + snap_point = scroll_obj->coords.x1 + pad_left; act_obj_point = act_obj->coords.x1; break; case LV_SCROLL_SNAP_END: - scroll_obj_point = obj->coords.x2; + snap_point = scroll_obj->coords.x2 - pad_right; act_obj_point = act_obj->coords.x2; break; } } else { + lv_coord_t pad_top = lv_obj_get_style_pad_top(scroll_obj, LV_PART_MAIN); + lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(scroll_obj, LV_PART_MAIN); + switch(snap) { case LV_SCROLL_SNAP_CENTER: - scroll_obj_point = lv_area_get_height(&obj->coords) / 2 + obj->coords.y1; + snap_point = pad_top + (lv_area_get_height(&scroll_obj->coords) - pad_top - pad_bottom) / 2 + scroll_obj->coords.y1; act_obj_point = lv_area_get_height(&act_obj->coords) / 2 + act_obj->coords.y1; break; case LV_SCROLL_SNAP_START: - scroll_obj_point = obj->coords.y1; + snap_point = scroll_obj->coords.y1 + pad_top; act_obj_point = act_obj->coords.y1; break; case LV_SCROLL_SNAP_END: - scroll_obj_point = obj->coords.y2; + snap_point = scroll_obj->coords.y2 - pad_bottom; act_obj_point = act_obj->coords.y2; break; } } if(scroll_end < 0) { - if(snap != LV_SCROLL_SNAP_NONE && act_obj_point > scroll_obj_point) return diff; + if(snap != LV_SCROLL_SNAP_NONE && act_obj_point > snap_point) return diff; /*Rounding*/ if(diff < 0) diff -= ELASTIC_SLOWNESS_FACTOR / 2; @@ -607,7 +619,7 @@ static lv_coord_t elastic_diff(lv_obj_t * obj, lv_coord_t diff, lv_coord_t scrol return diff / ELASTIC_SLOWNESS_FACTOR; } else if(scroll_start < 0) { - if(snap != LV_SCROLL_SNAP_NONE && act_obj_point < scroll_obj_point) return diff; + if(snap != LV_SCROLL_SNAP_NONE && act_obj_point < snap_point) return diff; /*Rounding*/ if(diff < 0) diff -= ELASTIC_SLOWNESS_FACTOR / 2; diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 905c3db106..7c90fa8877 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -903,12 +903,8 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) } } else if(sign == LV_SIGNAL_FOCUS) { - lv_obj_t * parent = lv_obj_get_parent(obj); - lv_obj_t * child = obj; - while(parent && lv_obj_has_flag(child, LV_OBJ_FLAG_SCROLL_ON_FOCUS)) { - lv_obj_scroll_to_view(child, LV_ANIM_ON); - child = parent; - parent = lv_obj_get_parent(parent); + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS)) { + lv_obj_scroll_to_view_recursive(obj, LV_ANIM_ON); } bool editing = false; diff --git a/src/lv_core/lv_obj_scroll.c b/src/lv_core/lv_obj_scroll.c index a02e0a279a..b4188dc123 100644 --- a/src/lv_core/lv_obj_scroll.c +++ b/src/lv_core/lv_obj_scroll.c @@ -36,6 +36,7 @@ static void scroll_by_raw(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); static void scroll_x_anim(void * obj, int32_t v); static void scroll_y_anim(void * obj, int32_t v); static void scroll_anim_ready_cb(lv_anim_t * a); +static void scroll_area_into_view(const lv_area_t * area, lv_obj_t * child, lv_point_t * scroll_value, lv_anim_enable_t anim_en); /********************** * STATIC VARIABLES @@ -335,50 +336,18 @@ void lv_obj_scroll_to_y(lv_obj_t * obj, lv_coord_t y, lv_anim_enable_t anim_en) void lv_obj_scroll_to_view(lv_obj_t * obj, lv_anim_enable_t anim_en) { - lv_obj_t * parent = lv_obj_get_parent(obj); - - lv_dir_t scroll_dir = lv_obj_get_scroll_dir(parent); - - - - lv_coord_t y_scroll = 0; - lv_coord_t ptop = lv_obj_get_style_pad_top(parent, LV_PART_MAIN); - lv_coord_t pbottom = lv_obj_get_style_pad_bottom(parent, LV_PART_MAIN); - lv_coord_t top_diff = parent->coords.y1 + ptop - obj->coords.y1; - lv_coord_t bottom_diff = -(parent->coords.y2 - pbottom - obj->coords.y2); - if((top_diff > 0 || bottom_diff > 0)) { - if(LV_ABS(top_diff) < LV_ABS(bottom_diff)) y_scroll = top_diff; - else y_scroll = -bottom_diff; - } - - lv_coord_t x_scroll = 0; - lv_coord_t pleft = lv_obj_get_style_pad_left(parent, LV_PART_MAIN); - lv_coord_t pright = lv_obj_get_style_pad_right(parent, LV_PART_MAIN); - lv_coord_t left_diff = parent->coords.x1 + pleft - obj->coords.x1; - lv_coord_t right_diff = -(parent->coords.x2 - pright - obj->coords.x2); - if((left_diff > 0 || right_diff > 0)) { - if(LV_ABS(left_diff) < LV_ABS(right_diff)) x_scroll = left_diff; - else x_scroll = -right_diff; - } - - /* Remove any pending scroll animations.*/ - lv_anim_del(parent, scroll_x_anim); - lv_anim_del(parent, scroll_y_anim); - - if((scroll_dir & LV_DIR_LEFT) == 0 && x_scroll < 0) x_scroll = 0; - if((scroll_dir & LV_DIR_RIGHT) == 0 && x_scroll > 0) x_scroll = 0; - if((scroll_dir & LV_DIR_TOP) == 0 && y_scroll < 0) y_scroll = 0; - if((scroll_dir & LV_DIR_BOTTOM) == 0 && y_scroll > 0) y_scroll = 0; - - lv_obj_scroll_by(parent, x_scroll, y_scroll, anim_en); + lv_point_t p = {0, 0}; + scroll_area_into_view(&obj->coords, obj, &p, anim_en); } void lv_obj_scroll_to_view_recursive(lv_obj_t * obj, lv_anim_enable_t anim_en) { - lv_obj_t * parent = lv_obj_get_parent(obj); + lv_point_t p = {0, 0}; + lv_obj_t * child = obj; + lv_obj_t * parent = lv_obj_get_parent(child); while(parent) { - lv_obj_scroll_to_view(obj, anim_en); - obj = parent; + scroll_area_into_view(&obj->coords, child, &p, anim_en); + child = parent; parent = lv_obj_get_parent(parent); } } @@ -575,3 +544,89 @@ static void scroll_anim_ready_cb(lv_anim_t * a) lv_event_send(a->var, LV_EVENT_SCROLL_END, NULL); } + +static void scroll_area_into_view(const lv_area_t * area, lv_obj_t * child, lv_point_t * scroll_value, lv_anim_enable_t anim_en) +{ + lv_obj_t * parent = lv_obj_get_parent(child); + lv_dir_t scroll_dir = lv_obj_get_scroll_dir(parent); + lv_coord_t snap_goal = 0; + lv_coord_t act = 0; + const lv_area_t * area_tmp; + + lv_coord_t y_scroll = 0; + lv_scroll_snap_t snap_y = lv_obj_get_scroll_snap_y(parent); + if(snap_y != LV_SCROLL_SNAP_NONE) area_tmp = &child->coords; + else area_tmp = area; + + lv_coord_t ptop = lv_obj_get_style_pad_top(parent, LV_PART_MAIN); + lv_coord_t pbottom = lv_obj_get_style_pad_bottom(parent, LV_PART_MAIN); + lv_coord_t top_diff = parent->coords.y1 + ptop - area_tmp->y1 - scroll_value->y; + lv_coord_t bottom_diff = -(parent->coords.y2 - pbottom - area_tmp->y2 - scroll_value->y); + if((top_diff > 0 && bottom_diff > 0)) y_scroll = 0; + else if(top_diff > 0) y_scroll = top_diff; + else if(bottom_diff > 0) y_scroll = -bottom_diff; + + lv_coord_t parent_h = lv_obj_get_height(parent) - ptop - pbottom; + switch(snap_y) { + case LV_SCROLL_SNAP_START: + snap_goal = parent->coords.y1 + ptop; + act = area_tmp->y1 + y_scroll; + y_scroll += snap_goal - act; + break; + case LV_SCROLL_SNAP_END: + snap_goal = parent->coords.y2 - pbottom; + act = area_tmp->y2 + y_scroll; + y_scroll += snap_goal - act; + break; + case LV_SCROLL_SNAP_CENTER: + snap_goal = parent->coords.y1 + ptop + parent_h / 2; + act = lv_area_get_height(area_tmp) / 2 + area_tmp->y1 + y_scroll; + y_scroll += snap_goal - act; + break; + } + + lv_coord_t x_scroll = 0; + lv_scroll_snap_t snap_x = lv_obj_get_scroll_snap_x(parent); + if(snap_x != LV_SCROLL_SNAP_NONE) area_tmp = &child->coords; + else area_tmp = area; + + lv_coord_t pleft = lv_obj_get_style_pad_left(parent, LV_PART_MAIN); + lv_coord_t pright = lv_obj_get_style_pad_right(parent, LV_PART_MAIN); + lv_coord_t left_diff = parent->coords.x1 + pleft - area_tmp->x1 - scroll_value->x; + lv_coord_t right_diff = -(parent->coords.x2 - pright - area_tmp->x2- scroll_value->x); + if((left_diff > 0 && right_diff > 0)) x_scroll = 0; + else if(left_diff > 0) x_scroll = left_diff; + else if(right_diff > 0) x_scroll = -right_diff; + + lv_coord_t parent_w = lv_obj_get_width(parent) - pleft - pright; + switch(snap_x) { + case LV_SCROLL_SNAP_START: + snap_goal = parent->coords.x1 + pleft; + act = area_tmp->x1 + x_scroll; + x_scroll += snap_goal - act; + break; + case LV_SCROLL_SNAP_END: + snap_goal = parent->coords.x2 - pright; + act = area_tmp->x2 + x_scroll; + x_scroll += snap_goal - act; + break; + case LV_SCROLL_SNAP_CENTER: + snap_goal = parent->coords.x1 + pleft + parent_w / 2; + act = lv_area_get_width(area_tmp) / 2 + area_tmp->x1 + x_scroll; + x_scroll += snap_goal - act; + break; + } + + /* Remove any pending scroll animations.*/ + lv_anim_del(parent, scroll_x_anim); + lv_anim_del(parent, scroll_y_anim); + + if((scroll_dir & LV_DIR_LEFT) == 0 && x_scroll < 0) x_scroll = 0; + if((scroll_dir & LV_DIR_RIGHT) == 0 && x_scroll > 0) x_scroll = 0; + if((scroll_dir & LV_DIR_TOP) == 0 && y_scroll < 0) y_scroll = 0; + if((scroll_dir & LV_DIR_BOTTOM) == 0 && y_scroll > 0) y_scroll = 0; + + scroll_value->x += anim_en == LV_ANIM_OFF ? 0 : x_scroll; + scroll_value->y += anim_en == LV_ANIM_OFF ? 0 : y_scroll; + lv_obj_scroll_by(parent, x_scroll, y_scroll, anim_en); +} diff --git a/tests/build.py b/tests/build.py index c843b64854..fcd9f39c4b 100755 --- a/tests/build.py +++ b/tests/build.py @@ -202,6 +202,3 @@ build("Minimal config monochrome", minimal_monochrome) build("Minimal config, 16 bit color depth", minimal_16bit) build("Minimal config, 16 bit color depth swapped", minimal_16bit_swap) build("Full config, 32 bit color depth", full_32bit) -#build("All objects, minimal features", all_obj_minimal_features) -#build("All objects, all common features", all_obj_all_features) -#build("All objects, with advanced features", advanced_features)