fix(scroll): varius fixes on lv_obj_scroll_to_view and snapping

This commit is contained in:
Gabor Kiss-Vamosi
2021-02-27 10:56:46 +01:00
parent 8f48cf5cc7
commit 950124f5a0
6 changed files with 131 additions and 69 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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)