fix(scroll): varius fixes on lv_obj_scroll_to_view and snapping
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user