mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
fix(scroll): handle scroll chain with snapping too (#7491)
This commit is contained in:
parent
20bfb4855b
commit
51a3d93852
@ -30,6 +30,7 @@ static int32_t find_snap_point_y(const lv_obj_t * obj, int32_t min, int32_t max,
|
|||||||
static void scroll_limit_diff(lv_indev_t * indev, int32_t * diff_x, int32_t * diff_y);
|
static void scroll_limit_diff(lv_indev_t * indev, int32_t * diff_x, int32_t * diff_y);
|
||||||
static int32_t elastic_diff(lv_obj_t * scroll_obj, int32_t diff, int32_t scroll_start, int32_t scroll_end,
|
static int32_t elastic_diff(lv_obj_t * scroll_obj, int32_t diff, int32_t scroll_start, int32_t scroll_end,
|
||||||
lv_dir_t dir);
|
lv_dir_t dir);
|
||||||
|
static void has_more_snap_points(lv_obj_t * scroll_obj, lv_dir_t dir, bool * has_start_snap, bool * has_end_snap);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC VARIABLES
|
* STATIC VARIABLES
|
||||||
@ -345,58 +346,43 @@ lv_obj_t * lv_indev_find_scroll_obj(lv_indev_t * indev)
|
|||||||
if((scroll_dir & LV_DIR_TOP) == 0) up_en = false;
|
if((scroll_dir & LV_DIR_TOP) == 0) up_en = false;
|
||||||
if((scroll_dir & LV_DIR_BOTTOM) == 0) down_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.
|
|
||||||
*If there are at least 2 snapable children always assume
|
|
||||||
*scrolling to allow scrolling to the other child*/
|
|
||||||
uint32_t snap_cnt = 0;
|
|
||||||
|
|
||||||
/*Horizontal scroll*/
|
/*Horizontal scroll*/
|
||||||
int32_t sl = 0;
|
int32_t sl = 0;
|
||||||
int32_t sr = 0;
|
int32_t sr = 0;
|
||||||
lv_scroll_snap_t snap_x = lv_obj_get_scroll_snap_x(obj_act);
|
lv_scroll_snap_t snap_x = lv_obj_get_scroll_snap_x(obj_act);
|
||||||
if(snap_x != LV_SCROLL_SNAP_NONE) {
|
if(snap_x == LV_SCROLL_SNAP_NONE) {
|
||||||
uint32_t child_cnt = lv_obj_get_child_count(obj_act);
|
|
||||||
uint32_t i;
|
|
||||||
for(i = 0; i < child_cnt; i++) {
|
|
||||||
if(lv_obj_has_flag(lv_obj_get_child(obj_act, i), LV_OBJ_FLAG_SNAPPABLE)) {
|
|
||||||
snap_cnt++;
|
|
||||||
if(snap_cnt == 2) {
|
|
||||||
sl = 1; /*Assume scrolling*/
|
|
||||||
sr = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(snap_x == LV_SCROLL_SNAP_NONE || snap_cnt < 2) {
|
|
||||||
sl = lv_obj_get_scroll_left(obj_act);
|
sl = lv_obj_get_scroll_left(obj_act);
|
||||||
sr = lv_obj_get_scroll_right(obj_act);
|
sr = lv_obj_get_scroll_right(obj_act);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
bool has_start_snap;
|
||||||
|
bool has_end_snap;
|
||||||
|
has_more_snap_points(obj_act, LV_DIR_HOR, &has_start_snap, &has_end_snap);
|
||||||
|
|
||||||
|
/*Assume scrolling is there are more snap point
|
||||||
|
*Assumed scroll in if there are NO more nap points*/
|
||||||
|
sl = has_start_snap ? 1 : -1;
|
||||||
|
sr = has_end_snap ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*Vertical scroll*/
|
/*Vertical scroll*/
|
||||||
snap_cnt = 0;
|
|
||||||
int32_t st = 0;
|
int32_t st = 0;
|
||||||
int32_t sb = 0;
|
int32_t sb = 0;
|
||||||
lv_scroll_snap_t snap_y = lv_obj_get_scroll_snap_y(obj_act);
|
lv_scroll_snap_t snap_y = lv_obj_get_scroll_snap_y(obj_act);
|
||||||
if(snap_y != LV_SCROLL_SNAP_NONE) {
|
if(snap_y == LV_SCROLL_SNAP_NONE) {
|
||||||
uint32_t child_cnt = lv_obj_get_child_count(obj_act);
|
|
||||||
uint32_t i;
|
|
||||||
for(i = 0; i < child_cnt; i++) {
|
|
||||||
if(lv_obj_has_flag(lv_obj_get_child(obj_act, i), LV_OBJ_FLAG_SNAPPABLE)) {
|
|
||||||
snap_cnt++;
|
|
||||||
if(snap_cnt == 2) {
|
|
||||||
st = 1; /*Assume scrolling*/
|
|
||||||
sb = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(snap_y == LV_SCROLL_SNAP_NONE || snap_cnt < 2) {
|
|
||||||
st = lv_obj_get_scroll_top(obj_act);
|
st = lv_obj_get_scroll_top(obj_act);
|
||||||
sb = lv_obj_get_scroll_bottom(obj_act);
|
sb = lv_obj_get_scroll_bottom(obj_act);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
bool has_start_snap;
|
||||||
|
bool has_end_snap;
|
||||||
|
has_more_snap_points(obj_act, LV_DIR_VER, &has_start_snap, &has_end_snap);
|
||||||
|
|
||||||
|
/*Assume scrolling is there are more snap point
|
||||||
|
*Assumed scroll in if there are NO more nap points*/
|
||||||
|
st = has_start_snap ? 1 : -1;
|
||||||
|
sb = has_end_snap ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*If this object is scrollable into the current scroll direction then save it as a candidate.
|
/*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
|
*It's important only to be scrollable on the current axis (hor/ver) because if the scroll
|
||||||
@ -671,80 +657,31 @@ static int32_t elastic_diff(lv_obj_t * scroll_obj, int32_t diff, int32_t scroll_
|
|||||||
}
|
}
|
||||||
/*Handle elastic scrolling*/
|
/*Handle elastic scrolling*/
|
||||||
else {
|
else {
|
||||||
/*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;
|
lv_scroll_snap_t snap;
|
||||||
snap = dir == LV_DIR_HOR ? lv_obj_get_scroll_snap_x(scroll_obj) : lv_obj_get_scroll_snap_y(scroll_obj);
|
snap = dir == LV_DIR_HOR ? lv_obj_get_scroll_snap_x(scroll_obj) : lv_obj_get_scroll_snap_y(scroll_obj);
|
||||||
|
|
||||||
bool no_more_start_snap = false;
|
/*Without snapping just scale down the diff when scrolled out*/
|
||||||
bool no_more_end_snap = false;
|
|
||||||
|
|
||||||
/*Without snapping just scale down the diff is scrolled out*/
|
|
||||||
if(snap == LV_SCROLL_SNAP_NONE) {
|
if(snap == LV_SCROLL_SNAP_NONE) {
|
||||||
if(scroll_end < 0 || scroll_start < 0) {
|
if(scroll_end < 0 || scroll_start < 0) {
|
||||||
/*Rounding*/
|
/*Rounding*/
|
||||||
if(diff < 0) diff -= ELASTIC_SLOWNESS_FACTOR / 2;
|
if(diff < 0) diff -= ELASTIC_SLOWNESS_FACTOR / 2;
|
||||||
if(diff > 0) diff += ELASTIC_SLOWNESS_FACTOR / 2;
|
if(diff > 0) diff += ELASTIC_SLOWNESS_FACTOR / 2;
|
||||||
diff = diff / ELASTIC_SLOWNESS_FACTOR;
|
return diff / ELASTIC_SLOWNESS_FACTOR;
|
||||||
}
|
|
||||||
}
|
|
||||||
/*With snapping the widget is scrolled out if there are no more snap points*/
|
|
||||||
else {
|
|
||||||
if(dir == LV_DIR_HOR) {
|
|
||||||
int32_t x = 0;
|
|
||||||
switch(snap) {
|
|
||||||
case LV_SCROLL_SNAP_CENTER: {
|
|
||||||
int32_t pad_left = lv_obj_get_style_pad_left(scroll_obj, 0);
|
|
||||||
int32_t pad_right = lv_obj_get_style_pad_right(scroll_obj, 0);
|
|
||||||
x = scroll_obj->coords.x1;
|
|
||||||
x += (lv_area_get_width(&scroll_obj->coords) - pad_left - pad_right) / 2;
|
|
||||||
x += pad_left;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LV_SCROLL_SNAP_START:
|
|
||||||
x = scroll_obj->coords.x1 + lv_obj_get_style_pad_left(scroll_obj, 0);
|
|
||||||
break;
|
|
||||||
case LV_SCROLL_SNAP_END:
|
|
||||||
x = scroll_obj->coords.x2 - lv_obj_get_style_pad_right(scroll_obj, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int32_t d;
|
|
||||||
d = find_snap_point_x(scroll_obj, x + 1, LV_COORD_MAX, 0);
|
|
||||||
if(d == LV_COORD_MAX) no_more_end_snap = true;
|
|
||||||
d = find_snap_point_x(scroll_obj, LV_COORD_MIN, x, 0);
|
|
||||||
if(d == LV_COORD_MAX) no_more_start_snap = true;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int32_t y = 0;
|
return diff;
|
||||||
switch(snap) {
|
|
||||||
case LV_SCROLL_SNAP_CENTER: {
|
|
||||||
int32_t pad_top = lv_obj_get_style_pad_top(scroll_obj, 0);
|
|
||||||
int32_t pad_bottom = lv_obj_get_style_pad_bottom(scroll_obj, 0);
|
|
||||||
y = scroll_obj->coords.y1;
|
|
||||||
y += (lv_area_get_height(&scroll_obj->coords) - pad_top - pad_bottom) / 2;
|
|
||||||
y += pad_top;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LV_SCROLL_SNAP_START:
|
|
||||||
y = scroll_obj->coords.y1 + lv_obj_get_style_pad_top(scroll_obj, 0);
|
|
||||||
break;
|
|
||||||
case LV_SCROLL_SNAP_END:
|
|
||||||
y = scroll_obj->coords.y2 - lv_obj_get_style_pad_bottom(scroll_obj, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int32_t d;
|
|
||||||
d = find_snap_point_y(scroll_obj, y, LV_COORD_MAX, 0);
|
|
||||||
if(d == LV_COORD_MAX) no_more_end_snap = true;
|
|
||||||
d = find_snap_point_y(scroll_obj, LV_COORD_MIN, y, 0);
|
|
||||||
if(d == LV_COORD_MAX) no_more_start_snap = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(no_more_start_snap || no_more_end_snap) {
|
/*With snapping the widget is scrolled out if there are no more snap points
|
||||||
|
*at least in one direction (start or end)*/
|
||||||
|
bool has_start_snap;
|
||||||
|
bool has_end_snap;
|
||||||
|
has_more_snap_points(scroll_obj, dir, &has_start_snap, &has_end_snap);
|
||||||
|
|
||||||
|
if(!has_start_snap || !has_end_snap) {
|
||||||
|
/*Rounding*/
|
||||||
if(diff < 0) diff -= ELASTIC_SLOWNESS_FACTOR / 2;
|
if(diff < 0) diff -= ELASTIC_SLOWNESS_FACTOR / 2;
|
||||||
if(diff > 0) diff += ELASTIC_SLOWNESS_FACTOR / 2;
|
if(diff > 0) diff += ELASTIC_SLOWNESS_FACTOR / 2;
|
||||||
return diff / ELASTIC_SLOWNESS_FACTOR;
|
return diff / ELASTIC_SLOWNESS_FACTOR;
|
||||||
@ -756,3 +693,76 @@ static int32_t elastic_diff(lv_obj_t * scroll_obj, int32_t diff, int32_t scroll_
|
|||||||
|
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell is there are more snap point in a given direction considering snap position.
|
||||||
|
* There is a snap point if there is a snapanble object in the given direction
|
||||||
|
* @param scroll_obj the object on which snap points should be found
|
||||||
|
* @param dir LV_DIR_HOR or LV_DIR_VER
|
||||||
|
* @param has_start_snap true: there is snap point in the start direction (top or left depending on dir)
|
||||||
|
* @param has_end_snap true: there is snap point in the end direction (bottom or right depending on dir)
|
||||||
|
* @note snap points will be searched relative to the
|
||||||
|
* center point in case of LV_SCROLL_SNAP_CENTER
|
||||||
|
* start point (top or left) in case of LV_SCROLL_SNAP_START
|
||||||
|
* end point (bottom or right) in case of LV_SCROLL_SNAP_END
|
||||||
|
*/
|
||||||
|
static void has_more_snap_points(lv_obj_t * scroll_obj, lv_dir_t dir, bool * has_start_snap, bool * has_end_snap)
|
||||||
|
{
|
||||||
|
*has_start_snap = true;
|
||||||
|
*has_end_snap = true;
|
||||||
|
lv_scroll_snap_t snap;
|
||||||
|
snap = dir == LV_DIR_HOR ? lv_obj_get_scroll_snap_x(scroll_obj) : lv_obj_get_scroll_snap_y(scroll_obj);
|
||||||
|
|
||||||
|
if(dir == LV_DIR_HOR) {
|
||||||
|
int32_t x = 0;
|
||||||
|
switch(snap) {
|
||||||
|
case LV_SCROLL_SNAP_CENTER: {
|
||||||
|
int32_t pad_left = lv_obj_get_style_pad_left(scroll_obj, 0);
|
||||||
|
int32_t pad_right = lv_obj_get_style_pad_right(scroll_obj, 0);
|
||||||
|
x = scroll_obj->coords.x1;
|
||||||
|
x += (lv_area_get_width(&scroll_obj->coords) - pad_left - pad_right) / 2;
|
||||||
|
x += pad_left;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LV_SCROLL_SNAP_START:
|
||||||
|
x = scroll_obj->coords.x1 + lv_obj_get_style_pad_left(scroll_obj, 0);
|
||||||
|
break;
|
||||||
|
case LV_SCROLL_SNAP_END:
|
||||||
|
x = scroll_obj->coords.x2 - lv_obj_get_style_pad_right(scroll_obj, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int32_t d;
|
||||||
|
d = find_snap_point_x(scroll_obj, x + 1, LV_COORD_MAX, 0);
|
||||||
|
if(d == LV_COORD_MAX) *has_end_snap = false;
|
||||||
|
d = find_snap_point_x(scroll_obj, LV_COORD_MIN, x - 1, 0);
|
||||||
|
if(d == LV_COORD_MAX) *has_start_snap = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int32_t y = 0;
|
||||||
|
switch(snap) {
|
||||||
|
case LV_SCROLL_SNAP_CENTER: {
|
||||||
|
int32_t pad_top = lv_obj_get_style_pad_top(scroll_obj, 0);
|
||||||
|
int32_t pad_bottom = lv_obj_get_style_pad_bottom(scroll_obj, 0);
|
||||||
|
y = scroll_obj->coords.y1;
|
||||||
|
y += (lv_area_get_height(&scroll_obj->coords) - pad_top - pad_bottom) / 2;
|
||||||
|
y += pad_top;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LV_SCROLL_SNAP_START:
|
||||||
|
y = scroll_obj->coords.y1 + lv_obj_get_style_pad_top(scroll_obj, 0);
|
||||||
|
break;
|
||||||
|
case LV_SCROLL_SNAP_END:
|
||||||
|
y = scroll_obj->coords.y2 - lv_obj_get_style_pad_bottom(scroll_obj, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int32_t d;
|
||||||
|
d = find_snap_point_y(scroll_obj, y + 1, LV_COORD_MAX, 0);
|
||||||
|
if(d == LV_COORD_MAX) *has_end_snap = false;
|
||||||
|
d = find_snap_point_y(scroll_obj, LV_COORD_MIN, y - 1, 0);
|
||||||
|
if(d == LV_COORD_MAX) *has_start_snap = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user