diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index a491c0996..4e78de2ca 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -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; } diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 8f454d2c5..c39ddc647 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -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) diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 112959fe1..b26543ca1 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -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