mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-21 06:53:01 +08:00
scroll: add animation and elastic scroll
This commit is contained in:
parent
e7648f1c00
commit
b091b676fe
@ -1245,15 +1245,20 @@ static void indev_click_focus(lv_indev_proc_t * proc)
|
||||
*/
|
||||
static void indev_drag(lv_indev_proc_t * proc)
|
||||
{
|
||||
lv_obj_t * drag_obj = get_dragged_obj(proc->types.pointer.act_obj);
|
||||
bool drag_just_started = false;
|
||||
|
||||
if(drag_obj == NULL) return;
|
||||
bool scrollable = true;
|
||||
|
||||
if(lv_obj_get_drag(drag_obj) == false) return;
|
||||
/*Get which object to drad/scroll*/
|
||||
lv_obj_t * target_obj = get_dragged_obj(proc->types.pointer.act_obj);
|
||||
if(target_obj == NULL) return;
|
||||
|
||||
lv_drag_dir_t dirs = LV_DRAG_DIR_VER; //scrollable ? lv_obj_get_scroll_dir(target_obj) : lv_obj_get_drag_dir(target_obj);
|
||||
|
||||
lv_drag_dir_t allowed_dirs = lv_obj_get_drag_dir(drag_obj);
|
||||
bool just_started = false;
|
||||
|
||||
/*Get the coordinates of the object and modify them*/
|
||||
lv_coord_t act_x = lv_obj_get_x(target_obj);
|
||||
lv_coord_t act_y = lv_obj_get_y(target_obj);
|
||||
|
||||
/*Count the movement by drag*/
|
||||
if(proc->types.pointer.drag_limit_out == 0) {
|
||||
@ -1263,15 +1268,15 @@ static void indev_drag(lv_indev_proc_t * proc)
|
||||
/*Enough move?*/
|
||||
bool hor_en = false;
|
||||
bool ver_en = false;
|
||||
if(allowed_dirs == LV_DRAG_DIR_HOR || allowed_dirs == LV_DRAG_DIR_BOTH) {
|
||||
if(dirs == LV_DRAG_DIR_HOR || dirs == LV_DRAG_DIR_BOTH) {
|
||||
hor_en = true;
|
||||
}
|
||||
|
||||
if(allowed_dirs == LV_DRAG_DIR_VER || allowed_dirs == LV_DRAG_DIR_BOTH) {
|
||||
if(dirs == LV_DRAG_DIR_VER || dirs == LV_DRAG_DIR_BOTH) {
|
||||
ver_en = true;
|
||||
}
|
||||
|
||||
if(allowed_dirs == LV_DRAG_DIR_ONE) {
|
||||
if(dirs == LV_DRAG_DIR_ONE) {
|
||||
if(LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y)) {
|
||||
hor_en = true;
|
||||
}
|
||||
@ -1284,102 +1289,77 @@ static void indev_drag(lv_indev_proc_t * proc)
|
||||
if((hor_en && LV_MATH_ABS(proc->types.pointer.drag_sum.x) >= indev_act->driver.drag_limit) ||
|
||||
(ver_en && LV_MATH_ABS(proc->types.pointer.drag_sum.y) >= indev_act->driver.drag_limit)) {
|
||||
proc->types.pointer.drag_limit_out = 1;
|
||||
drag_just_started = true;
|
||||
just_started = true;
|
||||
if(dirs == LV_DRAG_DIR_ONE) {
|
||||
proc->types.pointer.drag_dir = hor_en ? LV_DRAG_DIR_HOR : LV_DRAG_DIR_VER;
|
||||
} else {
|
||||
proc->types.pointer.drag_dir = dirs;
|
||||
}
|
||||
|
||||
/*The was no move due to drag limit. Compensate it now.*/
|
||||
if(!hor_en) proc->types.pointer.drag_sum.x = 0;
|
||||
if(!ver_en) proc->types.pointer.drag_sum.y = 0;
|
||||
|
||||
act_x += proc->types.pointer.drag_sum.x;
|
||||
act_y += proc->types.pointer.drag_sum.y;
|
||||
}
|
||||
}
|
||||
|
||||
/*If the drag limit is exceeded handle the dragging*/
|
||||
if(proc->types.pointer.drag_limit_out != 0) {
|
||||
/*Set new position if the vector is not zero*/
|
||||
/*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 prev_x = drag_obj->coords.x1;
|
||||
lv_coord_t prev_y = drag_obj->coords.y1;
|
||||
lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));
|
||||
lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));
|
||||
lv_coord_t prev_x = target_obj->coords.x1;
|
||||
lv_coord_t prev_y = target_obj->coords.y1;
|
||||
|
||||
/*Get the coordinates of the object and modify them*/
|
||||
lv_coord_t act_x = lv_obj_get_x(drag_obj);
|
||||
lv_coord_t act_y = lv_obj_get_y(drag_obj);
|
||||
|
||||
if(allowed_dirs == LV_DRAG_DIR_BOTH) {
|
||||
if(drag_just_started) {
|
||||
proc->types.pointer.drag_dir = LV_DRAG_DIR_BOTH;
|
||||
act_x += proc->types.pointer.drag_sum.x;
|
||||
act_y += proc->types.pointer.drag_sum.y;
|
||||
}
|
||||
}
|
||||
else if(allowed_dirs == LV_DRAG_DIR_HOR) {
|
||||
if(drag_just_started) {
|
||||
proc->types.pointer.drag_dir = LV_DRAG_DIR_HOR;
|
||||
proc->types.pointer.drag_sum.y = 0;
|
||||
act_x += proc->types.pointer.drag_sum.x;
|
||||
}
|
||||
}
|
||||
else if(allowed_dirs == LV_DRAG_DIR_VER) {
|
||||
if(drag_just_started) {
|
||||
proc->types.pointer.drag_dir = LV_DRAG_DIR_VER;
|
||||
proc->types.pointer.drag_sum.x = 0;
|
||||
act_y += proc->types.pointer.drag_sum.y;
|
||||
}
|
||||
}
|
||||
else if(allowed_dirs == LV_DRAG_DIR_ONE) {
|
||||
if(drag_just_started) {
|
||||
if(LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y)) {
|
||||
proc->types.pointer.drag_dir = LV_DRAG_DIR_HOR;
|
||||
proc->types.pointer.drag_sum.y = 0;
|
||||
act_x += proc->types.pointer.drag_sum.x;
|
||||
}
|
||||
else {
|
||||
proc->types.pointer.drag_dir = LV_DRAG_DIR_VER;
|
||||
proc->types.pointer.drag_sum.x = 0;
|
||||
act_y += proc->types.pointer.drag_sum.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Move the object*/
|
||||
if(allowed_dirs == LV_DRAG_DIR_HOR ||
|
||||
allowed_dirs == LV_DRAG_DIR_BOTH ||
|
||||
(allowed_dirs == LV_DRAG_DIR_ONE &&
|
||||
LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y))) {
|
||||
act_x += proc->types.pointer.vect.x;
|
||||
}
|
||||
if(allowed_dirs == LV_DRAG_DIR_VER ||
|
||||
allowed_dirs == LV_DRAG_DIR_BOTH ||
|
||||
(allowed_dirs == LV_DRAG_DIR_ONE &&
|
||||
LV_MATH_ABS(proc->types.pointer.drag_sum.x) < LV_MATH_ABS(proc->types.pointer.drag_sum.y))) {
|
||||
act_y += proc->types.pointer.vect.y;
|
||||
}
|
||||
/*Move the object. `drag_sum` is zerod out for *disabled direction*/
|
||||
if(proc->types.pointer.drag_sum.x) act_x += proc->types.pointer.vect.x;
|
||||
if(proc->types.pointer.drag_sum.y) act_y += proc->types.pointer.vect.y;
|
||||
|
||||
uint16_t inv_buf_size =
|
||||
lv_disp_get_inv_buf_size(indev_act->driver.disp); /*Get the number of currently invalidated areas*/
|
||||
|
||||
lv_obj_set_pos(drag_obj, act_x, act_y);
|
||||
proc->types.pointer.drag_in_prog = 1;
|
||||
|
||||
/*If the object didn't moved then clear the invalidated areas*/
|
||||
if(drag_obj->coords.x1 == prev_x && drag_obj->coords.y1 == prev_y) {
|
||||
/*In a special case if the object is moved on a page and
|
||||
* the scrollable has fit == true and the object is dragged of the page then
|
||||
* while its coordinate is not changing only the parent's size is reduced */
|
||||
lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));
|
||||
lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));
|
||||
if(act_par_w == prev_par_w && act_par_h == prev_par_h) {
|
||||
uint16_t new_inv_buf_size = lv_disp_get_inv_buf_size(indev_act->driver.disp);
|
||||
_lv_disp_pop_from_inv_buf(indev_act->driver.disp, new_inv_buf_size - inv_buf_size);
|
||||
if(scrollable) {
|
||||
lv_area_t child_box;
|
||||
lv_obj_get_children_box(target_obj, &child_box);
|
||||
lv_coord_t diff_y = proc->types.pointer.vect.y;
|
||||
if(target_obj->scroll.y > 0 && diff_y > 0) {
|
||||
diff_y = diff_y / 2;
|
||||
}
|
||||
if(child_box.y2 < target_obj->coords.y2 && diff_y < 0) {
|
||||
diff_y = diff_y / 2;
|
||||
}
|
||||
|
||||
lv_obj_scroll_by(target_obj, 0, diff_y, LV_ANIM_OFF);
|
||||
} else {
|
||||
lv_obj_set_pos(target_obj, act_x, act_y);
|
||||
}
|
||||
|
||||
/*Set the drag in progress flag*/
|
||||
/*Send the drag begin signal on first move*/
|
||||
if(drag_just_started) {
|
||||
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
|
||||
if(indev_reset_check(proc)) return;
|
||||
|
||||
lv_event_send(drag_obj, LV_EVENT_DRAG_BEGIN, NULL);
|
||||
if(indev_reset_check(proc)) return;
|
||||
}
|
||||
proc->types.pointer.drag_in_prog = 1;
|
||||
//
|
||||
// /*If the object didn't moved then clear the invalidated areas*/
|
||||
// if(target_obj->coords.x1 == prev_x && target_obj->coords.y1 == prev_y) {
|
||||
// /*In a special case if the object is moved on a page and
|
||||
// * the scrollable has fit == true and the object is dragged of the page then
|
||||
// * while its coordinate is not changing only the parent's size is reduced */
|
||||
// lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(target_obj));
|
||||
// lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(target_obj));
|
||||
// if(act_par_w == prev_par_w && act_par_h == prev_par_h) {
|
||||
// uint16_t new_inv_buf_size = lv_disp_get_inv_buf_size(indev_act->driver.disp);
|
||||
// _lv_disp_pop_from_inv_buf(indev_act->driver.disp, new_inv_buf_size - inv_buf_size);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /*Set the drag in progress flag*/
|
||||
// /*Send the drag begin signal on first move*/
|
||||
// if(just_started) {
|
||||
// target_obj->signal_cb(target_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
|
||||
// if(indev_reset_check(proc)) return;
|
||||
//
|
||||
// lv_event_send(target_obj, LV_EVENT_DRAG_BEGIN, NULL);
|
||||
// if(indev_reset_check(proc)) return;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@ -1466,12 +1446,16 @@ static void indev_drag_throw(lv_indev_proc_t * proc)
|
||||
*/
|
||||
static lv_obj_t * get_dragged_obj(lv_obj_t * obj)
|
||||
{
|
||||
|
||||
return obj;
|
||||
|
||||
if(obj == NULL) return NULL;
|
||||
lv_obj_t * drag_obj = obj;
|
||||
while(lv_obj_get_drag_parent(drag_obj) != false && drag_obj != NULL) {
|
||||
drag_obj = lv_obj_get_parent(drag_obj);
|
||||
}
|
||||
|
||||
if(lv_obj_get_drag(drag_obj) == false) return NULL;
|
||||
return drag_obj;
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,8 @@ static void trans_anim_start_cb(lv_anim_t * a);
|
||||
static void trans_anim_ready_cb(lv_anim_t * a);
|
||||
static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v);
|
||||
static void fade_in_anim_ready(lv_anim_t * a);
|
||||
static void scroll_anim_x_cb(lv_obj_t * obj, lv_anim_value_t v);
|
||||
static void scroll_anim_y_cb(lv_obj_t * obj, lv_anim_value_t v);
|
||||
#endif
|
||||
static void lv_event_mark_deleted(lv_obj_t * obj);
|
||||
static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find);
|
||||
@ -1074,6 +1076,7 @@ void lv_obj_scroll_by_raw(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
|
||||
obj->scroll.y += y;
|
||||
|
||||
refresh_children_position(obj, x, y);
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
/**
|
||||
* Moves all children with horizontally or vertically.
|
||||
@ -1084,10 +1087,37 @@ void lv_obj_scroll_by_raw(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
|
||||
*/
|
||||
void lv_obj_scroll_by(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_anim_enable_t anim_en)
|
||||
{
|
||||
obj->scroll.x += x;
|
||||
obj->scroll.y += y;
|
||||
|
||||
refresh_children_position(obj, x, y);
|
||||
if(x == 0 && y == 0) return;
|
||||
|
||||
if(anim_en == LV_ANIM_ON) {
|
||||
lv_disp_t * d = lv_obj_get_disp(obj);
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_var(&a, obj);
|
||||
|
||||
if(x) {
|
||||
lv_anim_set_time(&a, lv_anim_speed_to_time(lv_disp_get_hor_res(d), 0, y));
|
||||
lv_anim_set_values(&a, obj->scroll.x, obj->scroll.x + x);
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) scroll_anim_x_cb);
|
||||
lv_anim_start(&a);
|
||||
}
|
||||
|
||||
|
||||
if(y) {
|
||||
lv_anim_set_time(&a, lv_anim_speed_to_time(lv_disp_get_ver_res(d), 0, y));
|
||||
lv_anim_set_values(&a, obj->scroll.y, obj->scroll.y + y);
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) scroll_anim_y_cb);
|
||||
lv_anim_start(&a);
|
||||
}
|
||||
|
||||
} else {
|
||||
lv_obj_scroll_by_raw(obj, x, y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1118,7 +1148,7 @@ void lv_obj_scroll_to_x(lv_obj_t * obj, lv_coord_t x, lv_anim_enable_t anim_en)
|
||||
*/
|
||||
void lv_obj_scroll_to_y(lv_obj_t * obj, lv_coord_t y, lv_anim_enable_t anim_en)
|
||||
{
|
||||
// refresh_children_position(obj, x, y);
|
||||
lv_obj_scroll_by(obj, 0, y - obj->scroll.y, anim_en);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2125,6 +2155,37 @@ void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p)
|
||||
lv_area_copy(cords_p, &obj->coords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bounding which includes all the the children.
|
||||
* `margin` of the children also taken into account and makes the box larger (if positive)
|
||||
* @param obj pointer to an object
|
||||
* @param coords pointer to an area to store the coordinates
|
||||
* @return LV_RES_INV: `obj` has no children and `coords` can't be set; `LV_RES_OK`: success
|
||||
*/
|
||||
lv_res_t lv_obj_get_children_box(const lv_obj_t * obj, lv_area_t * coords)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
|
||||
|
||||
coords->x1 = LV_COORD_MAX;
|
||||
coords->y1 = LV_COORD_MAX;
|
||||
coords->x2 = LV_COORD_MIN;
|
||||
coords->y2 = LV_COORD_MIN;
|
||||
|
||||
lv_obj_t * child = lv_obj_get_child(obj, NULL);
|
||||
if(child == NULL) return LV_RES_INV;
|
||||
|
||||
while(child) {
|
||||
coords->x1 = LV_MATH_MIN(coords->x1, child->coords.x1 - lv_obj_get_style_margin_left(child, LV_OBJ_PART_MAIN));
|
||||
coords->y1 = LV_MATH_MIN(coords->y1, child->coords.y1 - lv_obj_get_style_margin_top(child, LV_OBJ_PART_MAIN));
|
||||
coords->x2 = LV_MATH_MAX(coords->x2, child->coords.x2 + lv_obj_get_style_margin_right(child, LV_OBJ_PART_MAIN));
|
||||
coords->y2 = LV_MATH_MAX(coords->y2, child->coords.y2 + lv_obj_get_style_margin_bottom(child, LV_OBJ_PART_MAIN));
|
||||
|
||||
child = lv_obj_get_child(obj, child);
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce area retried by `lv_obj_get_coords()` the get graphically usable area of an object.
|
||||
* (Without the size of the border or other extra graphical elements)
|
||||
@ -2761,6 +2822,18 @@ lv_drag_dir_t lv_obj_get_drag_dir(const lv_obj_t * obj)
|
||||
return obj->drag_dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the directions an object can be scrolled
|
||||
* @param obj pointer to an object
|
||||
* @return bitwise OR of allowed directions an object can be dragged in
|
||||
*/
|
||||
lv_drag_dir_t lv_obj_get_scroll_dir(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, LV_OBJX_NAME);
|
||||
|
||||
return obj->scroll_dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the drag throw enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
@ -3738,6 +3811,17 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param)
|
||||
/*Return 'invalid' if the child change signal is not enabled*/
|
||||
if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV;
|
||||
}
|
||||
else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED) {
|
||||
|
||||
lv_area_t child_box;
|
||||
lv_obj_get_children_box(obj, &child_box);
|
||||
if(obj->scroll.y > 0) {
|
||||
lv_obj_scroll_to_y(obj, 0, LV_ANIM_ON);
|
||||
}
|
||||
else if(child_box.y2 < obj->coords.y2) {
|
||||
lv_obj_scroll_by(obj, 0, -(child_box.y2 - obj->coords.y2), LV_ANIM_ON);
|
||||
}
|
||||
}
|
||||
else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
|
||||
lv_coord_t d = lv_obj_get_draw_rect_ext_pad_size(obj, LV_OBJ_PART_MAIN);
|
||||
obj->ext_draw_pad = LV_MATH_MAX(obj->ext_draw_pad, d);
|
||||
@ -4278,6 +4362,15 @@ static void fade_in_anim_ready(lv_anim_t * a)
|
||||
lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
|
||||
}
|
||||
|
||||
|
||||
static void scroll_anim_x_cb(lv_obj_t * obj, lv_anim_value_t v)
|
||||
{
|
||||
}
|
||||
|
||||
static void scroll_anim_y_cb(lv_obj_t * obj, lv_anim_value_t v)
|
||||
{
|
||||
lv_obj_scroll_by_raw(obj, 0, v - obj->scroll.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void lv_event_mark_deleted(lv_obj_t * obj)
|
||||
|
@ -228,7 +228,8 @@ typedef struct _lv_obj_t {
|
||||
uint8_t gesture_parent : 1; /**< 1: Parent will be gesture instead*/
|
||||
uint8_t focus_parent : 1; /**< 1: Parent will be focused instead*/
|
||||
|
||||
lv_drag_dir_t drag_dir : 3; /**< Which directions the object can be dragged in */
|
||||
lv_drag_dir_t drag_dir : 3; /**< In which directions the object can be dragged */
|
||||
lv_drag_dir_t scroll_dir : 3; /**< In which directions the object can be scrolled */
|
||||
lv_bidi_dir_t base_dir : 2; /**< Base direction of texts related to this object */
|
||||
|
||||
#if LV_USE_GROUP != 0
|
||||
@ -1223,6 +1224,13 @@ bool lv_obj_get_drag(const lv_obj_t * obj);
|
||||
*/
|
||||
lv_drag_dir_t lv_obj_get_drag_dir(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the directions an object can be scrolled
|
||||
* @param obj pointer to an object
|
||||
* @return bitwise OR of allowed directions an object can be dragged in
|
||||
*/
|
||||
lv_drag_dir_t lv_obj_get_scroll_dir(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the drag throw enable attribute of an object
|
||||
* @param obj pointer to an object
|
||||
|
Loading…
x
Reference in New Issue
Block a user