mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
fix(slider): improved drag direction prediction (#3874)
Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
parent
53dd646770
commit
83c384f6f7
@ -36,6 +36,8 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
|||||||
static void position_knob(lv_obj_t * obj, lv_area_t * knob_area, const lv_coord_t knob_size, const bool hor);
|
static void position_knob(lv_obj_t * obj, lv_area_t * knob_area, const lv_coord_t knob_size, const bool hor);
|
||||||
static void draw_knob(lv_event_t * e);
|
static void draw_knob(lv_event_t * e);
|
||||||
static bool is_slider_horizontal(lv_obj_t * obj);
|
static bool is_slider_horizontal(lv_obj_t * obj);
|
||||||
|
static void drag_start(lv_obj_t * obj);
|
||||||
|
static void update_knob_pos(lv_obj_t * obj, bool check_drag);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC VARIABLES
|
* STATIC VARIABLES
|
||||||
@ -126,134 +128,14 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(code == LV_EVENT_PRESSED) {
|
else if(code == LV_EVENT_PRESSED) {
|
||||||
lv_obj_invalidate(obj);
|
/*Save the pressed coordinates*/
|
||||||
|
lv_indev_get_point(lv_indev_get_act(), &slider->pressed_point);
|
||||||
lv_point_t p;
|
|
||||||
slider->dragging = true;
|
|
||||||
if(type == LV_SLIDER_MODE_NORMAL || type == LV_SLIDER_MODE_SYMMETRICAL) {
|
|
||||||
slider->value_to_set = &slider->bar.cur_value;
|
|
||||||
}
|
|
||||||
else if(type == LV_SLIDER_MODE_RANGE) {
|
|
||||||
lv_indev_get_point(lv_indev_get_act(), &p);
|
|
||||||
bool hor = lv_obj_get_width(obj) >= lv_obj_get_height(obj);
|
|
||||||
lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
|
|
||||||
|
|
||||||
lv_coord_t dist_left, dist_right;
|
|
||||||
if(hor) {
|
|
||||||
if((base_dir != LV_BASE_DIR_RTL && p.x > slider->right_knob_area.x2) || (base_dir == LV_BASE_DIR_RTL &&
|
|
||||||
p.x < slider->right_knob_area.x1)) {
|
|
||||||
slider->value_to_set = &slider->bar.cur_value;
|
|
||||||
}
|
|
||||||
else if((base_dir != LV_BASE_DIR_RTL && p.x < slider->left_knob_area.x1) || (base_dir == LV_BASE_DIR_RTL &&
|
|
||||||
p.x > slider->left_knob_area.x2)) {
|
|
||||||
slider->value_to_set = &slider->bar.start_value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/*Calculate the distance from each knob*/
|
|
||||||
dist_left = LV_ABS((slider->left_knob_area.x1 + (slider->left_knob_area.x2 - slider->left_knob_area.x1) / 2) - p.x);
|
|
||||||
dist_right = LV_ABS((slider->right_knob_area.x1 + (slider->right_knob_area.x2 - slider->right_knob_area.x1) / 2) - p.x);
|
|
||||||
|
|
||||||
/*Use whichever one is closer*/
|
|
||||||
if(dist_right < dist_left) {
|
|
||||||
slider->value_to_set = &slider->bar.cur_value;
|
|
||||||
slider->left_knob_focus = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
slider->value_to_set = &slider->bar.start_value;
|
|
||||||
slider->left_knob_focus = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(p.y < slider->right_knob_area.y1) {
|
|
||||||
slider->value_to_set = &slider->bar.cur_value;
|
|
||||||
}
|
|
||||||
else if(p.y > slider->left_knob_area.y2) {
|
|
||||||
slider->value_to_set = &slider->bar.start_value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/*Calculate the distance from each knob*/
|
|
||||||
dist_left = LV_ABS((slider->left_knob_area.y1 + (slider->left_knob_area.y2 - slider->left_knob_area.y1) / 2) - p.y);
|
|
||||||
dist_right = LV_ABS((slider->right_knob_area.y1 + (slider->right_knob_area.y2 - slider->right_knob_area.y1) / 2) - p.y);
|
|
||||||
|
|
||||||
/*Use whichever one is closer*/
|
|
||||||
if(dist_right < dist_left) {
|
|
||||||
slider->value_to_set = &slider->bar.cur_value;
|
|
||||||
slider->left_knob_focus = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
slider->value_to_set = &slider->bar.start_value;
|
|
||||||
slider->left_knob_focus = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(code == LV_EVENT_PRESSING && slider->value_to_set != NULL) {
|
else if(code == LV_EVENT_PRESSING) {
|
||||||
lv_indev_t * indev = lv_indev_get_act();
|
update_knob_pos(obj, true);
|
||||||
if(lv_indev_get_type(indev) != LV_INDEV_TYPE_POINTER) return;
|
|
||||||
if(lv_indev_get_scroll_obj(indev) != NULL) return;
|
|
||||||
|
|
||||||
lv_point_t p;
|
|
||||||
lv_indev_get_point(indev, &p);
|
|
||||||
int32_t new_value = 0;
|
|
||||||
|
|
||||||
const int32_t range = slider->bar.max_value - slider->bar.min_value;
|
|
||||||
bool is_hor = is_slider_horizontal(obj);
|
|
||||||
if(is_hor) {
|
|
||||||
const lv_coord_t bg_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
|
|
||||||
const lv_coord_t bg_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
|
|
||||||
const lv_coord_t w = lv_obj_get_width(obj);
|
|
||||||
const lv_coord_t indic_w = w - bg_left - bg_right;
|
|
||||||
|
|
||||||
if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
|
|
||||||
/*Make the point relative to the indicator*/
|
|
||||||
new_value = (obj->coords.x2 - bg_right) - p.x;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/*Make the point relative to the indicator*/
|
|
||||||
new_value = p.x - (obj->coords.x1 + bg_left);
|
|
||||||
}
|
|
||||||
if(indic_w) {
|
|
||||||
new_value = (new_value * range + indic_w / 2) / indic_w;
|
|
||||||
new_value += slider->bar.min_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const lv_coord_t bg_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
|
|
||||||
const lv_coord_t bg_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
|
|
||||||
const lv_coord_t h = lv_obj_get_height(obj);
|
|
||||||
const lv_coord_t indic_h = h - bg_bottom - bg_top;
|
|
||||||
|
|
||||||
/*Make the point relative to the indicator*/
|
|
||||||
new_value = p.y - (obj->coords.y2 + bg_bottom);
|
|
||||||
new_value = (-new_value * range + indic_h / 2) / indic_h;
|
|
||||||
new_value += slider->bar.min_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t real_max_value = slider->bar.max_value;
|
|
||||||
int32_t real_min_value = slider->bar.min_value;
|
|
||||||
/*Figure out the min. and max. for this mode*/
|
|
||||||
if(slider->value_to_set == &slider->bar.start_value) {
|
|
||||||
real_max_value = slider->bar.cur_value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
real_min_value = slider->bar.start_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_value = LV_CLAMP(real_min_value, new_value, real_max_value);
|
|
||||||
if(*slider->value_to_set != new_value) {
|
|
||||||
*slider->value_to_set = new_value;
|
|
||||||
if(is_hor) lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_VER);
|
|
||||||
else lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR);
|
|
||||||
|
|
||||||
lv_obj_invalidate(obj);
|
|
||||||
res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL);
|
|
||||||
if(res != LV_RES_OK) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(code == LV_EVENT_RELEASED || code == LV_EVENT_PRESS_LOST) {
|
else if(code == LV_EVENT_RELEASED || code == LV_EVENT_PRESS_LOST) {
|
||||||
|
update_knob_pos(obj, false);
|
||||||
slider->dragging = false;
|
slider->dragging = false;
|
||||||
slider->value_to_set = NULL;
|
slider->value_to_set = NULL;
|
||||||
|
|
||||||
@ -281,7 +163,6 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
|||||||
if(is_slider_horizontal(obj)) lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_VER);
|
if(is_slider_horizontal(obj)) lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_VER);
|
||||||
else lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR);
|
else lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(code == LV_EVENT_FOCUSED) {
|
else if(code == LV_EVENT_FOCUSED) {
|
||||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||||
@ -290,7 +171,6 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(code == LV_EVENT_SIZE_CHANGED) {
|
else if(code == LV_EVENT_SIZE_CHANGED) {
|
||||||
|
|
||||||
if(is_slider_horizontal(obj)) {
|
if(is_slider_horizontal(obj)) {
|
||||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_VER);
|
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_VER);
|
||||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR);
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR);
|
||||||
@ -460,4 +340,155 @@ static bool is_slider_horizontal(lv_obj_t * obj)
|
|||||||
return lv_obj_get_width(obj) >= lv_obj_get_height(obj);
|
return lv_obj_get_width(obj) >= lv_obj_get_height(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drag_start(lv_obj_t * obj)
|
||||||
|
{
|
||||||
|
lv_slider_t * slider = (lv_slider_t *)obj;
|
||||||
|
lv_slider_mode_t mode = lv_slider_get_mode(obj);
|
||||||
|
lv_point_t p;
|
||||||
|
slider->dragging = true;
|
||||||
|
if(mode == LV_SLIDER_MODE_NORMAL || mode == LV_SLIDER_MODE_SYMMETRICAL) {
|
||||||
|
slider->value_to_set = &slider->bar.cur_value;
|
||||||
|
}
|
||||||
|
else if(mode == LV_SLIDER_MODE_RANGE) {
|
||||||
|
lv_indev_get_point(lv_indev_get_act(), &p);
|
||||||
|
bool hor = is_slider_horizontal(obj);
|
||||||
|
lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
|
||||||
|
|
||||||
|
lv_coord_t dist_left, dist_right;
|
||||||
|
if(hor) {
|
||||||
|
if((base_dir != LV_BASE_DIR_RTL && p.x > slider->right_knob_area.x2) || (base_dir == LV_BASE_DIR_RTL &&
|
||||||
|
p.x < slider->right_knob_area.x1)) {
|
||||||
|
slider->value_to_set = &slider->bar.cur_value;
|
||||||
|
}
|
||||||
|
else if((base_dir != LV_BASE_DIR_RTL && p.x < slider->left_knob_area.x1) || (base_dir == LV_BASE_DIR_RTL &&
|
||||||
|
p.x > slider->left_knob_area.x2)) {
|
||||||
|
slider->value_to_set = &slider->bar.start_value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*Calculate the distance from each knob*/
|
||||||
|
dist_left = LV_ABS((slider->left_knob_area.x1 + (slider->left_knob_area.x2 - slider->left_knob_area.x1) / 2) - p.x);
|
||||||
|
dist_right = LV_ABS((slider->right_knob_area.x1 + (slider->right_knob_area.x2 - slider->right_knob_area.x1) / 2) - p.x);
|
||||||
|
|
||||||
|
/*Use whichever one is closer*/
|
||||||
|
if(dist_right < dist_left) {
|
||||||
|
slider->value_to_set = &slider->bar.cur_value;
|
||||||
|
slider->left_knob_focus = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
slider->value_to_set = &slider->bar.start_value;
|
||||||
|
slider->left_knob_focus = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(p.y < slider->right_knob_area.y1) {
|
||||||
|
slider->value_to_set = &slider->bar.cur_value;
|
||||||
|
}
|
||||||
|
else if(p.y > slider->left_knob_area.y2) {
|
||||||
|
slider->value_to_set = &slider->bar.start_value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*Calculate the distance from each knob*/
|
||||||
|
dist_left = LV_ABS((slider->left_knob_area.y1 + (slider->left_knob_area.y2 - slider->left_knob_area.y1) / 2) - p.y);
|
||||||
|
dist_right = LV_ABS((slider->right_knob_area.y1 + (slider->right_knob_area.y2 - slider->right_knob_area.y1) / 2) - p.y);
|
||||||
|
|
||||||
|
/*Use whichever one is closer*/
|
||||||
|
if(dist_right < dist_left) {
|
||||||
|
slider->value_to_set = &slider->bar.cur_value;
|
||||||
|
slider->left_knob_focus = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
slider->value_to_set = &slider->bar.start_value;
|
||||||
|
slider->left_knob_focus = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_knob_pos(lv_obj_t * obj, bool check_drag)
|
||||||
|
{
|
||||||
|
lv_slider_t * slider = (lv_slider_t *)obj;
|
||||||
|
lv_indev_t * indev = lv_indev_get_act();
|
||||||
|
if(lv_indev_get_type(indev) != LV_INDEV_TYPE_POINTER)
|
||||||
|
return;
|
||||||
|
if(lv_indev_get_scroll_obj(indev) != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lv_point_t p;
|
||||||
|
lv_indev_get_point(indev, &p);
|
||||||
|
bool is_hor = is_slider_horizontal(obj);
|
||||||
|
|
||||||
|
if(check_drag && !slider->dragging) {
|
||||||
|
lv_coord_t ofs = is_hor ? (p.x - slider->pressed_point.x) : (p.y - slider->pressed_point.y);
|
||||||
|
|
||||||
|
/*Stop processing when offset is below scroll_limit*/
|
||||||
|
if(LV_ABS(ofs) < indev->driver->scroll_limit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!slider->value_to_set) {
|
||||||
|
/*Ready to start drag*/
|
||||||
|
drag_start(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t new_value = 0;
|
||||||
|
const int32_t range = slider->bar.max_value - slider->bar.min_value;
|
||||||
|
if(is_hor) {
|
||||||
|
const lv_coord_t bg_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
|
||||||
|
const lv_coord_t bg_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
|
||||||
|
const lv_coord_t w = lv_obj_get_width(obj);
|
||||||
|
const lv_coord_t indic_w = w - bg_left - bg_right;
|
||||||
|
|
||||||
|
if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
|
||||||
|
/*Make the point relative to the indicator*/
|
||||||
|
new_value = (obj->coords.x2 - bg_right) - p.x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*Make the point relative to the indicator*/
|
||||||
|
new_value = p.x - (obj->coords.x1 + bg_left);
|
||||||
|
}
|
||||||
|
if(indic_w) {
|
||||||
|
new_value = (new_value * range + indic_w / 2) / indic_w;
|
||||||
|
new_value += slider->bar.min_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const lv_coord_t bg_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
|
||||||
|
const lv_coord_t bg_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
|
||||||
|
const lv_coord_t h = lv_obj_get_height(obj);
|
||||||
|
const lv_coord_t indic_h = h - bg_bottom - bg_top;
|
||||||
|
|
||||||
|
/*Make the point relative to the indicator*/
|
||||||
|
new_value = p.y - (obj->coords.y2 + bg_bottom);
|
||||||
|
new_value = (-new_value * range + indic_h / 2) / indic_h;
|
||||||
|
new_value += slider->bar.min_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t real_max_value = slider->bar.max_value;
|
||||||
|
int32_t real_min_value = slider->bar.min_value;
|
||||||
|
/*Figure out the min. and max. for this mode*/
|
||||||
|
if(slider->value_to_set == &slider->bar.start_value) {
|
||||||
|
real_max_value = slider->bar.cur_value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
real_min_value = slider->bar.start_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_value = LV_CLAMP(real_min_value, new_value, real_max_value);
|
||||||
|
if(*slider->value_to_set != new_value) {
|
||||||
|
*slider->value_to_set = new_value;
|
||||||
|
if(is_hor)
|
||||||
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_VER);
|
||||||
|
else
|
||||||
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR);
|
||||||
|
|
||||||
|
lv_obj_invalidate(obj);
|
||||||
|
lv_res_t res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
|
if(res != LV_RES_OK)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -42,6 +42,7 @@ typedef struct {
|
|||||||
lv_bar_t bar; /*Add the ancestor's type first*/
|
lv_bar_t bar; /*Add the ancestor's type first*/
|
||||||
lv_area_t left_knob_area;
|
lv_area_t left_knob_area;
|
||||||
lv_area_t right_knob_area;
|
lv_area_t right_knob_area;
|
||||||
|
lv_point_t pressed_point;
|
||||||
int32_t * value_to_set; /*Which bar value to set*/
|
int32_t * value_to_set; /*Which bar value to set*/
|
||||||
uint8_t dragging : 1; /*1: the slider is being dragged*/
|
uint8_t dragging : 1; /*1: the slider is being dragged*/
|
||||||
uint8_t left_knob_focus : 1; /*1: with encoder now the right knob can be adjusted*/
|
uint8_t left_knob_focus : 1; /*1: with encoder now the right knob can be adjusted*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user