From 886305347d180e4cab2390b49c8df0f917dfd473 Mon Sep 17 00:00:00 2001 From: Andy Everitt <38423143+AndyEveritt@users.noreply.github.com> Date: Sat, 13 Sep 2025 08:42:14 +0300 Subject: [PATCH] feat(style): add `lv_style_merge` and appropriate tests (#8680) --- src/misc/lv_style.c | 23 +++++++-- src/misc/lv_style.h | 13 +++++ tests/src/test_cases/test_style.c | 81 +++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/misc/lv_style.c b/src/misc/lv_style.c index fa77b026f7..d7c2122520 100644 --- a/src/misc/lv_style.c +++ b/src/misc/lv_style.c @@ -210,10 +210,27 @@ void lv_style_copy(lv_style_t * dst, const lv_style_t * src) lv_style_reset(dst); - /*Source is empty*/ - if(src->values_and_props == NULL) return; - if(src->prop_cnt == 0) return; + lv_style_merge(dst, src); +} +void lv_style_merge(lv_style_t * dst, const lv_style_t * src) +{ + if(lv_style_is_const(dst)) { + LV_LOG_WARN("The destination can not be a constant style"); + return; + } + + /*Source is empty*/ + if(src->values_and_props == NULL) { + LV_LOG_TRACE("Source style is empty"); + return; + } + if(src->prop_cnt == 0) { + LV_LOG_TRACE("Source style has no properties"); + return; + } + + /* Merge the styles */ int32_t i; if(lv_style_is_const(src)) { lv_style_const_prop_t * props_and_values = (lv_style_const_prop_t *)src->values_and_props; diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h index 087bbb8bae..46646ee6d3 100644 --- a/src/misc/lv_style.h +++ b/src/misc/lv_style.h @@ -363,6 +363,19 @@ void lv_style_reset(lv_style_t * style); */ void lv_style_copy(lv_style_t * dst, const lv_style_t * src); +/** + * Copy all properties of a style to an other without resetting the dst style. + * It has the same effect as calling the same `lv_set_style_...` + * functions on both styles. + * It means new memory will be allocated to store the properties in + * the destination style. + * After the copy the destination style is fully independent of the source + * and source can removed without affecting the destination style. + * @param dst the destination to copy into (cannot be a constant style) + * @param src the source style to copy from. + */ +void lv_style_merge(lv_style_t * dst, const lv_style_t * src); + /** * Check if a style is constant diff --git a/tests/src/test_cases/test_style.c b/tests/src/test_cases/test_style.c index eaa65e565b..c2de69e339 100644 --- a/tests/src/test_cases/test_style.c +++ b/tests/src/test_cases/test_style.c @@ -118,6 +118,87 @@ void test_style_replacement(void) lv_style_reset(&style_blue); } +void test_style_copy(void) +{ + lv_style_t style1; + lv_style_t style2; + lv_style_t copied_style; + + const lv_color_t copied_bg_color = lv_color_hex(0x0000ff); + const lv_color_t copied_border_color = lv_color_hex(0x00ff00); + const lv_color_t copied_outline_color = lv_color_hex(0xffff00); + + lv_style_init(&style1); + lv_style_set_bg_color(&style1, lv_color_hex(0xff0000)); // this should get overwritten + lv_style_set_outline_color(&style1, copied_outline_color); + + lv_style_init(&style2); + lv_style_set_bg_color(&style2, copied_bg_color); + lv_style_set_border_color(&style2, copied_border_color); + + lv_style_init(&copied_style); + lv_style_copy(&copied_style, &style1); + lv_style_copy(&copied_style, &style2); // This should reset `copied_style` then duplicate the properties of `style2` + + lv_style_value_t value; + + TEST_ASSERT_TRUE(lv_style_get_prop(&copied_style, LV_STYLE_BG_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(copied_bg_color, value.color); + TEST_ASSERT_TRUE(lv_style_get_prop(&copied_style, LV_STYLE_BORDER_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(copied_border_color, value.color); + TEST_ASSERT_TRUE(lv_style_get_prop(&copied_style, LV_STYLE_OUTLINE_COLOR, &value) == LV_STYLE_RES_NOT_FOUND); + + /* Changing the original style should not impact the style that copied it */ + lv_style_set_bg_color(&style2, lv_color_hex(0x00ff00)); + TEST_ASSERT_TRUE(lv_style_get_prop(&copied_style, LV_STYLE_BG_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(copied_bg_color, value.color); + + lv_style_reset(&style1); + lv_style_reset(&style2); + lv_style_reset(&copied_style); +} + +void test_style_merge(void) +{ + lv_style_t style1; + lv_style_t style2; + lv_style_t merged_style; + + const lv_color_t merged_bg_color = lv_color_hex(0x0000ff); + const lv_color_t merged_border_color = lv_color_hex(0x00ff00); + const lv_color_t merged_outline_color = lv_color_hex(0xffff00); + + lv_style_init(&style1); + lv_style_set_bg_color(&style1, lv_color_hex(0xff0000)); // this should get overwritten + lv_style_set_outline_color(&style1, merged_outline_color); + + lv_style_init(&style2); + lv_style_set_bg_color(&style2, merged_bg_color); + lv_style_set_border_color(&style2, merged_border_color); + + lv_style_init(&merged_style); + lv_style_merge(&merged_style, &style1); + lv_style_merge(&merged_style, &style2); + + lv_style_value_t value; + + TEST_ASSERT_TRUE(lv_style_get_prop(&merged_style, LV_STYLE_BG_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(merged_bg_color, value.color); + TEST_ASSERT_TRUE(lv_style_get_prop(&merged_style, LV_STYLE_BORDER_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(merged_border_color, value.color); + TEST_ASSERT_TRUE(lv_style_get_prop(&merged_style, LV_STYLE_OUTLINE_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(merged_outline_color, value.color); + + /* Changing the original style should not impact the style that copied it */ + lv_style_set_bg_color(&style2, lv_color_hex(0x00ff00)); + TEST_ASSERT_TRUE(lv_style_get_prop(&merged_style, LV_STYLE_BG_COLOR, &value) == LV_STYLE_RES_FOUND); + TEST_ASSERT_EQUAL_COLOR(merged_bg_color, value.color); + + lv_style_reset(&style1); + lv_style_reset(&style2); + lv_style_reset(&merged_style); +} + void test_style_has_prop(void) { lv_style_t style;