diff --git a/src/widgets/scale/lv_scale.c b/src/widgets/scale/lv_scale.c index a9a8f08e2d..ca07e9a40c 100644 --- a/src/widgets/scale/lv_scale.c +++ b/src/widgets/scale/lv_scale.c @@ -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) diff --git a/src/widgets/scale/lv_scale_private.h b/src/widgets/scale/lv_scale_private.h index 76f65383c5..ba4ef9d837 100644 --- a/src/widgets/scale/lv_scale_private.h +++ b/src/widgets/scale/lv_scale_private.h @@ -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 */ }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f5d84500ce..ebba0a7785 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -292,7 +292,9 @@ set(TEST_INCLUDE_DIRS $ ) -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 diff --git a/tests/ref_imgs/widgets/scale_7.png b/tests/ref_imgs/widgets/scale_7.png new file mode 100644 index 0000000000..62cb034c9c Binary files /dev/null and b/tests/ref_imgs/widgets/scale_7.png differ diff --git a/tests/ref_imgs/widgets/scale_8.png b/tests/ref_imgs/widgets/scale_8.png new file mode 100644 index 0000000000..ed1bb9ad8f Binary files /dev/null and b/tests/ref_imgs/widgets/scale_8.png differ diff --git a/tests/ref_imgs_vg_lite/widgets/scale_7.png b/tests/ref_imgs_vg_lite/widgets/scale_7.png new file mode 100644 index 0000000000..94a183d968 Binary files /dev/null and b/tests/ref_imgs_vg_lite/widgets/scale_7.png differ diff --git a/tests/ref_imgs_vg_lite/widgets/scale_8.png b/tests/ref_imgs_vg_lite/widgets/scale_8.png new file mode 100644 index 0000000000..2e76865392 Binary files /dev/null and b/tests/ref_imgs_vg_lite/widgets/scale_8.png differ diff --git a/tests/src/test_cases/widgets/test_scale.c b/tests/src/test_cases/widgets/test_scale.c index c5c1ff6e5a..1844deb70a 100644 --- a/tests/src/test_cases/widgets/test_scale.c +++ b/tests/src/test_cases/widgets/test_scale.c @@ -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