From a7c4fc410ae45cdf7d83055821646cc7e51c4299 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 10 Nov 2020 21:53:42 +0100 Subject: [PATCH] fix(arc): fix and improve arc dragging It was difficult to handle the pressed angle on the arc when it crossed the 360 degree boundery. The solution is to handle the angle relative to the bg_start_angle. This way no angle can be larger than 360. The other issue was the case when a smaller than min. or larger than max. angle was pressed. It is handled by introducing 'min_close' flag which stores which end is closer on the last valid press and prefer this end in uncleary situation. --- CHANGELOG.md | 1 + src/lv_widgets/lv_arc.c | 33 ++++++++++++++++++++++++++++----- src/lv_widgets/lv_arc.h | 1 + 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c44e2338f..5d46635a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Bugfixes - fix(draw_triangle): fix polygon/triangle drawing when the order of points is counter-clockwise - fix(btnmatrix): fix setting the same map with modified pointers +- fix(arc) fix and improve arc dragging ## v7.7.1 (04.11.2020) ### Bugfixes diff --git a/src/lv_widgets/lv_arc.c b/src/lv_widgets/lv_arc.c index 67d2dc71e..4378fec87 100644 --- a/src/lv_widgets/lv_arc.c +++ b/src/lv_widgets/lv_arc.c @@ -85,6 +85,7 @@ lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy) ext->arc_angle_end = 270; ext->type = LV_ARC_TYPE_NORMAL; ext->cur_value = -1; + ext->min_close = 1; ext->min_value = 0; ext->max_value = 100; ext->dragging = false; @@ -751,6 +752,9 @@ static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param) /*It must be in "dragging" mode to turn the arc*/ if(ext->dragging == false) return res; + /*No angle can be determined if exactly the middle of the arc is being pressed*/ + if(p.x == 0 && p.y == 0) return res; + /*Calculate the angle of the pressed point*/ int16_t angle; int16_t bg_end = ext->bg_angle_end; @@ -758,13 +762,30 @@ static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param) bg_end = ext->bg_angle_end + 360; } - angle = 360 - _lv_atan2(p.x, p.y) + 90; /*Some transformation is required*/ + + angle = _lv_atan2(p.y, p.x); angle -= ext->rotation_angle; - if(angle < ext->bg_angle_start) angle = ext->bg_angle_start; - if(angle > bg_end) angle = bg_end; + angle -= ext->bg_angle_start; /*Make the angle relative to the start angle*/ + if(angle < 0) angle += 360; + + int16_t deg_range = bg_end - ext->bg_angle_start; + + int16_t last_angle_rel = ext->last_angle - ext->bg_angle_start; + int16_t delta_angle = angle - last_angle_rel; + + /* Do not allow big jumps. + * It's mainly to avoid jumping to the opposite end if the "dead" range between min. an max. is crossed. + * Check which and was closer on the last valid press (ext->min_close) and prefer that end */ + if(LV_MATH_ABS(delta_angle) > 180) { + if(ext->min_close) angle = 0; + else angle = deg_range; + } else { + if(angle < deg_range / 2) ext->min_close = 1; + else ext->min_close = 0; + } /*Calculate the slew rate limited angle based on change rate (degrees/sec)*/ - int16_t delta_angle = angle - ext->last_angle; + delta_angle = angle - last_angle_rel; uint32_t delta_tick = lv_tick_elaps(ext->last_tick); int16_t delta_angle_max = (ext->chg_rate * delta_tick) / 1000; @@ -775,13 +796,15 @@ static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param) delta_angle = -delta_angle_max; } - angle = ext->last_angle + delta_angle; /*Apply the limited angle change*/ + angle = last_angle_rel + delta_angle; /*Apply the limited angle change*/ /*Rounding for symmetry*/ int32_t round = ((bg_end - ext->bg_angle_start) * 8) / (ext->max_value - ext->min_value); round = (round + 4) >> 4; angle += round; + angle += ext->bg_angle_start; /*Make the angle absolute again*/ + /*Set the new value*/ int16_t old_value = ext->cur_value; int16_t new_value = _lv_map(angle, ext->bg_angle_start, bg_end, ext->min_value, ext->max_value); diff --git a/src/lv_widgets/lv_arc.h b/src/lv_widgets/lv_arc.h index 9f45184d3..55494a8d7 100644 --- a/src/lv_widgets/lv_arc.h +++ b/src/lv_widgets/lv_arc.h @@ -51,6 +51,7 @@ typedef struct { uint16_t dragging : 1; uint16_t type : 2; uint16_t adjustable : 1; + uint16_t min_close : 1; /*1: the last pressed angle was closer to minimum end*/ uint16_t chg_rate; /*Drag angle rate of change of the arc (degrees/sec)*/ uint32_t last_tick; /*Last dragging event timestamp of the arc*/ int16_t last_angle; /*Last dragging angle of the arc*/