feat(scale): update needles when scale is transformed (#9340)

This commit is contained in:
André Costa
2025-12-17 21:24:36 +01:00
committed by GitHub
parent 057fe71d7a
commit 127a3fd227
8 changed files with 112 additions and 1 deletions
+66
View File
@@ -71,6 +71,9 @@ static void scale_free_line_needle_points_cb(lv_event_t * e);
static bool scale_is_major_tick(lv_scale_t * scale, uint32_t tick_idx);
static lv_result_t update_needle(lv_scale_t * scale, lv_obj_t * needle, int32_t length, int32_t value);
static void needle_deleted_cb(lv_event_t * e);
#if LV_USE_OBSERVER
static void scale_section_min_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
static void scale_section_max_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
@@ -297,6 +300,8 @@ void lv_scale_set_line_needle_value(lv_obj_t * obj, lv_obj_t * needle_line, int3
needle_line_points[1].y = scale_height / 2 + needle_length_y;
lv_line_set_points_mutable(needle_line, needle_line_points, 2);
update_needle(scale, needle_line, needle_length, value);
}
void lv_scale_set_image_needle_value(lv_obj_t * obj, lv_obj_t * needle_img, int32_t value)
@@ -320,6 +325,7 @@ void lv_scale_set_image_needle_value(lv_obj_t * obj, lv_obj_t * needle_img, int3
}
lv_image_set_rotation(needle_img, (scale->rotation + angle) * 10);
update_needle(scale, needle_img, 0, value);
}
void lv_scale_set_text_src(lv_obj_t * obj, const char * txt_src[])
@@ -586,6 +592,7 @@ static void lv_scale_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
scale->draw_ticks_on_top = false;
scale->custom_label_cnt = 0;
scale->txt_src = NULL;
lv_array_init(&scale->needles, 0, sizeof(lv_scale_needle_t));
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
@@ -606,6 +613,13 @@ static void lv_scale_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
}
lv_ll_clear(&scale->section_ll);
size_t needle_count = lv_array_size(&scale->needles);
for(size_t i = 0; i < needle_count; ++i) {
lv_scale_needle_t * scale_needle = lv_array_at(&scale->needles, i);
lv_obj_remove_event_cb(scale_needle->obj, needle_deleted_cb);
}
lv_array_deinit(&scale->needles);
LV_TRACE_OBJ_CREATE("finished");
}
@@ -656,6 +670,18 @@ static void lv_scale_event(const lv_obj_class_t * class_p, lv_event_t * event)
/* NOTE: Extend scale draw size so the first tick label can be shown */
lv_event_set_ext_draw_size(event, 100);
}
else if(event_code == LV_EVENT_STYLE_CHANGED) {
size_t needle_count = lv_array_size(&scale->needles);
for(size_t i = 0; i < needle_count; ++i) {
lv_scale_needle_t * needle = lv_array_at(&scale->needles, i);
if(lv_obj_has_class(needle->obj, &lv_line_class)) {
lv_scale_set_line_needle_value(obj, needle->obj, needle->length, needle->value);
}
else {
lv_scale_set_image_needle_value(obj, needle->obj, needle->value);
}
}
}
else {
/* Nothing to do. Invalid event */
}
@@ -1761,6 +1787,46 @@ static bool scale_is_major_tick(lv_scale_t * scale, uint32_t tick_idx)
return scale->major_tick_every != 0 && tick_idx % scale->major_tick_every == 0;
}
static lv_result_t update_needle(lv_scale_t * scale, lv_obj_t * needle, int32_t length, int32_t value)
{
/* First try to find the needle in the haystack (scale's needle list) */
size_t needle_count = lv_array_size(&scale->needles);
for(size_t i = 0; i < needle_count; ++i) {
lv_scale_needle_t * scale_needle = lv_array_at(&scale->needles, i);
if(scale_needle->obj == needle) {
scale_needle->value = value;
scale_needle->length = length;
return LV_RESULT_OK;
}
}
/* Needle is not yet part of the haystack */
lv_scale_needle_t scale_needle = {.obj = needle, .length = length, .value = value};
lv_result_t res = lv_array_push_back(&scale->needles, &scale_needle);
if(res != LV_RESULT_OK) {
LV_LOG_WARN("Failed to attach needle to scale - not enough memory");
return LV_RESULT_INVALID;
}
lv_obj_add_event_cb(needle, needle_deleted_cb, LV_EVENT_DELETE, scale);
return LV_RESULT_OK;
}
static void needle_deleted_cb(lv_event_t * e)
{
lv_scale_t * scale = lv_event_get_user_data(e);
lv_obj_t * needle = lv_event_get_target_obj(e);
size_t needle_count = lv_array_size(&scale->needles);
for(size_t i = 0; i < needle_count; ++i) {
lv_scale_needle_t * scale_needle = lv_array_at(&scale->needles, i);
if(scale_needle->obj == needle) {
lv_array_remove(&scale->needles, i);
return;
}
}
}
#if LV_USE_OBSERVER
static void scale_section_min_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
+6
View File
@@ -55,6 +55,11 @@ struct _lv_scale_section_t {
uint32_t last_tick_idx_is_major : 1; /**< Internal (set during drawing): true if
* `last_tick_idx_in_section` represents a major tick. */
};
typedef struct {
lv_obj_t * obj;
int32_t value;
int32_t length;
} lv_scale_needle_t;
struct _lv_scale_t {
lv_obj_t obj; /**< Base Widget part of Scale */
@@ -77,6 +82,7 @@ struct _lv_scale_t {
int32_t custom_label_cnt; /**< Number of custom labels provided in `txt_src` */
int32_t last_tick_width; /**< Width of last tick in pixels */
int32_t first_tick_width; /**< Width of first tick in pixels */
lv_array_t needles; /**< Needle list of this scale */
};
+3 -1
View File
@@ -292,7 +292,9 @@ set(TEST_INCLUDE_DIRS
$<BUILD_INTERFACE:${LVGL_CONF_DIR}>
)
file(GLOB_RECURSE TEST_IMAGES_SRC ${LVGL_TEST_DIR}/test_images/*.c)
file(GLOB_RECURSE TEST_IMAGES_SRC
${LVGL_TEST_DIR}/test_images/*.c
${LVGL_TEST_DIR}/../examples/assets/*.c)
add_library(test_common
STATIC
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

+37
View File
@@ -542,4 +542,41 @@ void test_scale_set_line_needle_value(void)
);
}
void test_scale_needle_updates_when_style_changes(void)
{
lv_obj_t * scale = lv_scale_create(lv_screen_active());
lv_obj_align(scale, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_set_style_width(scale, 200, LV_PART_MAIN);
lv_obj_set_style_height(scale, 200, LV_PART_MAIN);
lv_scale_set_mode(scale, LV_SCALE_MODE_ROUND_INNER);
lv_scale_set_range(scale, 0, 100);
lv_scale_set_angle_range(scale, 270);
lv_scale_set_rotation(scale, 135);
lv_scale_set_total_tick_count(scale, 20);
lv_scale_set_major_tick_every(scale, 5);
lv_obj_t * needle_line = lv_line_create(scale);
lv_obj_set_style_line_width(needle_line, 6, LV_PART_MAIN);
lv_obj_set_style_line_rounded(needle_line, true, LV_PART_MAIN);
lv_scale_set_line_needle_value(scale, needle_line, 60, 26);
LV_IMAGE_DECLARE(img_hand);
lv_obj_t * needle_img = lv_image_create(scale);
lv_image_set_src(needle_img, &img_hand);
lv_scale_set_image_needle_value(scale, needle_img, 78);
lv_obj_align(needle_img, LV_ALIGN_CENTER, 47, -2);
lv_image_set_pivot(needle_img, 3, 4);
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/scale_7.png");
lv_obj_align(scale, LV_ALIGN_RIGHT_MID, 0, 0);
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/scale_8.png");
}
#endif