From a76bb70a79dfa5b841328f07ede0907c700a039a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 27 Apr 2022 14:24:45 +0200 Subject: [PATCH] feat(arc): add lv_arc_align_obj_to_angle and lv_arc_rotate_obj_to_angle --- examples/widgets/arc/lv_example_arc_1.c | 21 ++++++- src/widgets/lv_arc.c | 82 ++++++++++++++++++++++--- src/widgets/lv_arc.h | 80 ++++++++++++++---------- 3 files changed, 140 insertions(+), 43 deletions(-) diff --git a/examples/widgets/arc/lv_example_arc_1.c b/examples/widgets/arc/lv_example_arc_1.c index c725d2c32..e1ff4e868 100644 --- a/examples/widgets/arc/lv_example_arc_1.c +++ b/examples/widgets/arc/lv_example_arc_1.c @@ -2,15 +2,34 @@ #if LV_USE_ARC && LV_BUILD_EXAMPLES +static void value_changed_event_cb(lv_event_t * e); + void lv_example_arc_1(void) { + lv_obj_t * label = lv_label_create(lv_scr_act()); + /*Create an Arc*/ lv_obj_t * arc = lv_arc_create(lv_scr_act()); lv_obj_set_size(arc, 150, 150); lv_arc_set_rotation(arc, 135); lv_arc_set_bg_angles(arc, 0, 270); - lv_arc_set_value(arc, 40); + lv_arc_set_value(arc, 10); lv_obj_center(arc); + lv_obj_add_event_cb(arc, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, label); + + /*Manually update the label for the first time*/ + lv_event_send(arc, LV_EVENT_VALUE_CHANGED, NULL); +} + +static void value_changed_event_cb(lv_event_t * e) +{ + lv_obj_t * arc = lv_event_get_target(e); + lv_obj_t * label = lv_event_get_user_data(e); + + lv_label_set_text_fmt(label, "%d%%", lv_arc_get_value(arc)); + + /*Rotate the label to the current position of the arc*/ + lv_arc_rotate_obj_to_angle(arc, label, 25); } #endif diff --git a/src/widgets/lv_arc.c b/src/widgets/lv_arc.c index 99ffb1f15..98abad586 100644 --- a/src/widgets/lv_arc.c +++ b/src/widgets/lv_arc.c @@ -35,7 +35,8 @@ static void lv_arc_draw(lv_event_t * e); static void lv_arc_event(const lv_obj_class_t * class_p, lv_event_t * e); static void inv_arc_area(lv_obj_t * arc, uint16_t start_angle, uint16_t end_angle, lv_part_t part); static void inv_knob_area(lv_obj_t * obj); -static void get_center(lv_obj_t * obj, lv_point_t * center, lv_coord_t * arc_r); +static void get_center(const lv_obj_t * obj, lv_point_t * center, lv_coord_t * arc_r); +static lv_coord_t get_angle(const lv_obj_t * obj); static void get_knob_area(lv_obj_t * arc, const lv_point_t * center, lv_coord_t r, lv_area_t * knob_area); static void value_update(lv_obj_t * arc); @@ -317,6 +318,60 @@ lv_arc_mode_t lv_arc_get_mode(const lv_obj_t * obj) return ((lv_arc_t *) obj)->type; } +/*===================== + * Other functions + *====================*/ + + +void lv_arc_align_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_align, lv_coord_t r_offset) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + LV_ASSERT_NULL(obj_to_align); + + lv_obj_update_layout(obj); + + lv_point_t center; + lv_coord_t arc_r; + get_center(obj, ¢er, &arc_r); + lv_coord_t indic_width = lv_obj_get_style_arc_width(obj, LV_PART_INDICATOR); + lv_coord_t indic_width_half = indic_width / 2; + arc_r -= indic_width_half; + arc_r += r_offset; + + uint16_t angle = get_angle(obj); + lv_coord_t knob_x = (arc_r * lv_trigo_sin(angle + 90)) >> LV_TRIGO_SHIFT; + lv_coord_t knob_y = (arc_r * lv_trigo_sin(angle)) >> LV_TRIGO_SHIFT; + lv_obj_align_to(obj_to_align, obj, LV_ALIGN_CENTER, knob_x, knob_y); +} + +void lv_arc_rotate_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_rotate, lv_coord_t r_offset) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + LV_ASSERT_NULL(obj_to_rotate); + + lv_obj_update_layout(obj); + + lv_point_t center; + lv_coord_t arc_r; + get_center(obj, ¢er, &arc_r); + lv_coord_t indic_width = lv_obj_get_style_arc_width(obj, LV_PART_INDICATOR); + lv_coord_t indic_width_half = indic_width / 2; + arc_r -= indic_width_half; + + arc_r += r_offset; + lv_obj_align_to(obj_to_rotate, obj, LV_ALIGN_CENTER, 0, -arc_r); + + lv_obj_update_layout(obj); + + uint16_t angle = get_angle(obj); + lv_coord_t pivot_x = obj_to_rotate->coords.x1 - center.x; + lv_coord_t pivot_y = obj_to_rotate->coords.y1 - center.y; + lv_obj_set_style_transform_pivot_x(obj_to_rotate, -pivot_x, 0); + lv_obj_set_style_transform_pivot_y(obj_to_rotate, -pivot_y, 0); + lv_obj_set_style_transform_angle(obj_to_rotate, angle * 10 + 900, 0); +} + + /********************** * STATIC FUNCTIONS **********************/ @@ -345,7 +400,7 @@ static void lv_arc_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) arc->last_angle = arc->indic_angle_end; lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE); - lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN); + lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN | LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_ext_click_area(obj, LV_DPI_DEF / 10); @@ -675,7 +730,7 @@ static void inv_knob_area(lv_obj_t * obj) lv_obj_invalidate_area(obj, &a); } -static void get_center(lv_obj_t * obj, lv_point_t * center, lv_coord_t * arc_r) +static void get_center(const lv_obj_t * obj, lv_point_t * center, lv_coord_t * arc_r) { lv_coord_t left_bg = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); lv_coord_t right_bg = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); @@ -691,15 +746,9 @@ static void get_center(lv_obj_t * obj, lv_point_t * center, lv_coord_t * arc_r) if(arc_r) *arc_r = r; } -static void get_knob_area(lv_obj_t * obj, const lv_point_t * center, lv_coord_t r, lv_area_t * knob_area) +static lv_coord_t get_angle(const lv_obj_t * obj) { - LV_ASSERT_OBJ(obj, MY_CLASS); lv_arc_t * arc = (lv_arc_t *)obj; - - lv_coord_t indic_width = lv_obj_get_style_arc_width(obj, LV_PART_INDICATOR); - lv_coord_t indic_width_half = indic_width / 2; - r -= indic_width_half; - uint16_t angle = arc->rotation; if(arc->type == LV_ARC_MODE_NORMAL) { angle += arc->indic_angle_end; @@ -712,6 +761,18 @@ static void get_knob_area(lv_obj_t * obj, const lv_point_t * center, lv_coord_t if(arc->value < range_midpoint) angle += arc->indic_angle_start; else angle += arc->indic_angle_end; } + + return angle; +} + + +static void get_knob_area(lv_obj_t * obj, const lv_point_t * center, lv_coord_t r, lv_area_t * knob_area) +{ + lv_coord_t indic_width = lv_obj_get_style_arc_width(obj, LV_PART_INDICATOR); + lv_coord_t indic_width_half = indic_width / 2; + r -= indic_width_half; + + lv_coord_t angle = get_angle(obj); lv_coord_t knob_x = (r * lv_trigo_sin(angle + 90)) >> LV_TRIGO_SHIFT; lv_coord_t knob_y = (r * lv_trigo_sin(angle)) >> LV_TRIGO_SHIFT; @@ -765,6 +826,7 @@ static void value_update(lv_obj_t * obj) case LV_ARC_MODE_NORMAL: angle = lv_map(arc->value, arc->min_value, arc->max_value, arc->bg_angle_start, bg_end); lv_arc_set_angles(obj, arc->bg_angle_start, angle); + break; default: LV_LOG_WARN("Invalid mode: %d", arc->type); diff --git a/src/widgets/lv_arc.h b/src/widgets/lv_arc.h index 8ec39a4aa..fd53fc15c 100644 --- a/src/widgets/lv_arc.h +++ b/src/widgets/lv_arc.h @@ -85,83 +85,83 @@ lv_obj_t * lv_arc_create(lv_obj_t * parent); /** * Set the start angle of an arc. 0 deg: right, 90 bottom, etc. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param start the start angle */ -void lv_arc_set_start_angle(lv_obj_t * arc, uint16_t start); +void lv_arc_set_start_angle(lv_obj_t * obj, uint16_t start); /** * Set the end angle of an arc. 0 deg: right, 90 bottom, etc. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param end the end angle */ -void lv_arc_set_end_angle(lv_obj_t * arc, uint16_t end); +void lv_arc_set_end_angle(lv_obj_t * obj, uint16_t end); /** * Set the start and end angles - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param start the start angle * @param end the end angle */ -void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end); +void lv_arc_set_angles(lv_obj_t * obj, uint16_t start, uint16_t end); /** * Set the start angle of an arc background. 0 deg: right, 90 bottom, etc. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param start the start angle */ -void lv_arc_set_bg_start_angle(lv_obj_t * arc, uint16_t start); +void lv_arc_set_bg_start_angle(lv_obj_t * obj, uint16_t start); /** * Set the start angle of an arc background. 0 deg: right, 90 bottom etc. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param end the end angle */ -void lv_arc_set_bg_end_angle(lv_obj_t * arc, uint16_t end); +void lv_arc_set_bg_end_angle(lv_obj_t * obj, uint16_t end); /** * Set the start and end angles of the arc background - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param start the start angle * @param end the end angle */ -void lv_arc_set_bg_angles(lv_obj_t * arc, uint16_t start, uint16_t end); +void lv_arc_set_bg_angles(lv_obj_t * obj, uint16_t start, uint16_t end); /** * Set the rotation for the whole arc - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param rotation rotation angle */ -void lv_arc_set_rotation(lv_obj_t * arc, uint16_t rotation); +void lv_arc_set_rotation(lv_obj_t * obj, uint16_t rotation); /** * Set the type of arc. - * @param arc pointer to arc object + * @param obj pointer to arc object * @param mode arc's mode */ -void lv_arc_set_mode(lv_obj_t * arc, lv_arc_mode_t type); +void lv_arc_set_mode(lv_obj_t * obj, lv_arc_mode_t type); /** * Set a new value on the arc - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param value new value */ -void lv_arc_set_value(lv_obj_t * arc, int16_t value); +void lv_arc_set_value(lv_obj_t * obj, int16_t value); /** * Set minimum and the maximum values of an arc - * @param arc pointer to the arc object + * @param obj pointer to the arc object * @param min minimum value * @param max maximum value */ -void lv_arc_set_range(lv_obj_t * arc, int16_t min, int16_t max); +void lv_arc_set_range(lv_obj_t * obj, int16_t min, int16_t max); /** * Set a change rate to limit the speed how fast the arc should reach the pressed point. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @param rate the change rate */ -void lv_arc_set_change_rate(lv_obj_t * arc, uint16_t rate); +void lv_arc_set_change_rate(lv_obj_t * obj, uint16_t rate); /*===================== * Getter functions @@ -169,56 +169,56 @@ void lv_arc_set_change_rate(lv_obj_t * arc, uint16_t rate); /** * Get the start angle of an arc. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @return the start angle [0..360] */ uint16_t lv_arc_get_angle_start(lv_obj_t * obj); /** * Get the end angle of an arc. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @return the end angle [0..360] */ uint16_t lv_arc_get_angle_end(lv_obj_t * obj); /** * Get the start angle of an arc background. - * @param arc pointer to an arc object - * @return the start angle [0..360] + * @param obj pointer to an arc object + * @return the start angle [0..360] */ uint16_t lv_arc_get_bg_angle_start(lv_obj_t * obj); /** * Get the end angle of an arc background. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @return the end angle [0..360] */ uint16_t lv_arc_get_bg_angle_end(lv_obj_t * obj); /** * Get the value of an arc - * @param arc pointer to an arc object - * @return the value of the arc + * @param obj pointer to an arc object + * @return the value of the arc */ int16_t lv_arc_get_value(const lv_obj_t * obj); /** * Get the minimum value of an arc - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @return the minimum value of the arc */ int16_t lv_arc_get_min_value(const lv_obj_t * obj); /** * Get the maximum value of an arc - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @return the maximum value of the arc */ int16_t lv_arc_get_max_value(const lv_obj_t * obj); /** * Get whether the arc is type or not. - * @param arc pointer to an arc object + * @param obj pointer to an arc object * @return arc's mode */ lv_arc_mode_t lv_arc_get_mode(const lv_obj_t * obj); @@ -227,6 +227,22 @@ lv_arc_mode_t lv_arc_get_mode(const lv_obj_t * obj); * Other functions *====================*/ +/** + * Align an object to the current position of the arc (knob) + * @param obj pointer to an arc object + * @param obj_to_align pointer to an object to align + * @param r_offset consider the radius larger with this value (< 0: for smaller radius) + */ +void lv_arc_align_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_align, lv_coord_t r_offset); + +/** + * Rotate an object to the current position of the arc (knob) + * @param obj pointer to an arc object + * @param obj_to_align pointer to an object to rotate + * @param r_offset consider the radius larger with this value (< 0: for smaller radius) + */ +void lv_arc_rotate_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_rotate, lv_coord_t r_offset); + /********************** * MACROS **********************/