From 71df208074baa0fa6a87e48996746270e2ad1664 Mon Sep 17 00:00:00 2001 From: Neo Xu Date: Fri, 31 May 2024 10:49:19 +0800 Subject: [PATCH] feat(property): add style selector support for property API (#6275) Signed-off-by: Xu Xingliang --- docs/others/obj_property.rst | 6 +- src/core/lv_obj_property.c | 36 ++++++--- src/core/lv_obj_property.h | 78 ++++++++++++++----- tests/CMakeLists.txt | 7 ++ tests/src/lv_test_conf_full.h | 1 - .../test_cases/widgets/test_obj_property.c | 24 ++++++ 6 files changed, 121 insertions(+), 31 deletions(-) diff --git a/docs/others/obj_property.rst b/docs/others/obj_property.rst index ed5ba4260..45d780e39 100644 --- a/docs/others/obj_property.rst +++ b/docs/others/obj_property.rst @@ -24,7 +24,11 @@ Two APIs are provided to get/set widget properties. It can be enabled by setting int32_t num; /**< Number integer number (opacity, enums, booleans or "normal" numbers)*/ const void * ptr; /**< Constant pointers (font, cone text, etc)*/ lv_color_t color; /**< Colors*/ - lv_style_value_t _style; /**< A place holder for style value which is same as property value.*/ + lv_value_precise_t precise; /**< float or int for precise value*/ + struct { + lv_style_value_t style; /**< Make sure it's the first element in struct. */ + uint32_t selector; /**< Style selector, lv_part_t | lv_state_t */ + }; }; } lv_property_t; diff --git a/src/core/lv_obj_property.c b/src/core/lv_obj_property.c index 20a2d25c1..d616c3bf9 100644 --- a/src/core/lv_obj_property.c +++ b/src/core/lv_obj_property.c @@ -53,12 +53,12 @@ lv_result_t lv_obj_set_property(lv_obj_t * obj, const lv_property_t * value) LV_ASSERT(obj && value); if(value->id == LV_PROPERTY_ID_INVALID) { - LV_LOG_WARN("invalid property id set to %p\n", obj); + LV_LOG_WARN("Invalid property id set to %p", obj); return LV_RESULT_INVALID; } if(value->id < LV_PROPERTY_ID_START) { - lv_obj_set_local_style_prop(obj, value->id, value->_style, 0); + lv_obj_set_local_style_prop(obj, value->id, value->style, value->selector); return LV_RESULT_OK; } @@ -83,25 +83,43 @@ lv_property_t lv_obj_get_property(lv_obj_t * obj, lv_prop_id_t id) lv_property_t value; if(id == LV_PROPERTY_ID_INVALID) { - LV_LOG_WARN("invalid property id to get from %p\n", obj); - value.id = 0; + LV_LOG_WARN("Invalid property id to get from %p", obj); + value.id = LV_PROPERTY_ID_INVALID; value.num = 0; return value; } if(id < LV_PROPERTY_ID_START) { - lv_obj_get_local_style_prop(obj, id, &value._style, 0); + lv_obj_get_local_style_prop(obj, id, &value.style, 0); value.id = id; + value.selector = 0; return value; } result = obj_property(obj, id, &value, false); if(result != LV_RESULT_OK) - value.id = 0; + value.id = LV_PROPERTY_ID_INVALID; return value; } +lv_property_t lv_obj_get_style_property(lv_obj_t * obj, lv_prop_id_t id, uint32_t selector) +{ + lv_property_t value; + + if(id == LV_PROPERTY_ID_INVALID || id >= LV_PROPERTY_ID_START) { + LV_LOG_WARN("invalid style property id %d", id); + value.id = LV_PROPERTY_ID_INVALID; + value.num = 0; + return value; + } + + lv_obj_get_local_style_prop(obj, id, &value.style, selector); + value.id = id; + value.selector = selector; + return value; +} + static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set) { const lv_property_ops_t * properties; @@ -139,7 +157,7 @@ static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * /*id matched but we got null pointer to functions*/ if(set ? prop->setter == NULL : prop->getter == NULL) { - LV_LOG_WARN("null %s provided, id: %d\n", set ? "setter" : "getter", id); + LV_LOG_WARN("NULL %s provided, id: %d", set ? "setter" : "getter", id); return LV_RESULT_INVALID; } @@ -161,7 +179,7 @@ static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * else value->color = ((lv_property_get_color_t)(prop->getter))(obj); break; default: - LV_LOG_WARN("unknown property id: 0x%08x\n", prop->id); + LV_LOG_WARN("Unknown property id: 0x%08x", prop->id); return LV_RESULT_INVALID; break; } @@ -172,7 +190,7 @@ static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * /*If no setter found, try base class then*/ } - LV_LOG_WARN("unknown property id: 0x%08x\n", id); + LV_LOG_WARN("Unknown property id: 0x%08x", id); return LV_RESULT_INVALID; } diff --git a/src/core/lv_obj_property.h b/src/core/lv_obj_property.h index ca3754ab3..215023630 100644 --- a/src/core/lv_obj_property.h +++ b/src/core/lv_obj_property.h @@ -30,10 +30,6 @@ extern "C" { #define LV_PROPERTY_TYPE_POINTER 4 /*void * pointer*/ #define LV_PROPERTY_TYPE_IMGSRC 5 /*Special pointer for image*/ -/********************** - * TYPEDEFS - **********************/ - #define LV_PROPERTY_ID(clz, name, type, index) LV_PROPERTY_## clz ##_##name = (LV_PROPERTY_## clz ##_START + (index)) | ((type) << 28) #define LV_PROPERTY_ID_TYPE(id) ((id) >> 28) @@ -42,25 +38,28 @@ extern "C" { /*Set properties from an array of lv_property_t*/ #define LV_OBJ_SET_PROPERTY_ARRAY(obj, array) lv_obj_set_properties(obj, array, sizeof(array)/sizeof(array[0])) +/********************** + * TYPEDEFS + **********************/ + /** * Group of predefined widget ID start value. */ enum { - LV_PROPERTY_ID_INVALID = 0, + LV_PROPERTY_ID_INVALID = 0, /*ID 0 to 0xff are style ID, check lv_style_prop_t*/ - LV_PROPERTY_ID_START = 0x100, /*ID little than 0xff is style ID*/ + LV_PROPERTY_ID_START = 0x100, /*ID little than 0xff is style ID*/ - /* lv_obj.c */ - LV_PROPERTY_OBJ_START = 1000, + /*Define the property ID for every widget here. */ + LV_PROPERTY_OBJ_START = 0x100, /* lv_obj.c */ + LV_PROPERTY_IMAGE_START = 0x200, /* lv_image.c */ - /* lv_image.c */ - LV_PROPERTY_IMAGE_START = 1100, + /*Special ID, use it to extend ID and make sure it's unique and compile time determinant*/ + LV_PROPERTY_ID_BUILTIN_LAST = 0x10000000, - /*Special ID*/ - LV_PROPERTY_ID_BUILTIN_LAST, /*Use it to extend ID and make sure it's unique and compile time determinant*/ - - LV_PROPERTY_ID_ANY = 0x7ffffffe, /*Special ID used by lvgl to intercept all setter/getter call.*/ + /*Special ID used by lvgl to intercept all setter/getter call.*/ + LV_PROPERTY_ID_ANY = 0x7ffffffe, }; typedef uint32_t lv_prop_id_t; @@ -72,7 +71,30 @@ typedef struct { const void * ptr; /**< Constant pointers (font, cone text, etc)*/ lv_color_t color; /**< Colors*/ lv_value_precise_t precise; /**< float or int for precise value*/ - lv_style_value_t _style; /**< A place holder for style value which is same as property value.*/ + struct { + /** + * Note that place struct member `style` at first place is intended. + * `style` shares same memory with `num`, `ptr`, `color`. + * So we set the style value directly without using `prop.style.num`. + * + * E.g. + * + * static const lv_property_t obj_pos_x = { + * .id = LV_STYLE_X, + * .num = 123, + * .selector = LV_STATE_PRESSED, + * } + * + * instead of: + * static const lv_property_t obj_pos_x = { + * .id = LV_STYLE_X, + * .style.num = 123, // note this line. + * .selector = LV_STATE_PRESSED, + * } + */ + lv_style_value_t style; /**< Make sure it's the first element in struct. */ + uint32_t selector; /**< Style selector, lv_part_t | lv_state_t */ + }; }; } lv_property_t; @@ -92,14 +114,20 @@ typedef struct { *====================*/ /** - * Set widget property value. + * Set widget property. * @param obj pointer to an object - * @param id ID of which property * @param value The property value to set * @return return LV_RESULT_OK if success */ lv_result_t lv_obj_set_property(lv_obj_t * obj, const lv_property_t * value); +/** + * Set multiple widget properties. Helper `LV_OBJ_SET_PROPERTY_ARRAY` can be used for constant property array. + * @param obj pointer to an object + * @param value The property value array to set + * @param count The count of the property value array + * @return return LV_RESULT_OK if success + */ lv_result_t lv_obj_set_properties(lv_obj_t * obj, const lv_property_t * value, uint32_t count); /*===================== @@ -107,14 +135,24 @@ lv_result_t lv_obj_set_properties(lv_obj_t * obj, const lv_property_t * value, u *====================*/ /** - * Read property value from object + * Read property value from object. + * If id is a style property, the style selector is default to 0. * @param obj pointer to an object - * @param id ID of which property + * @param id ID of which property to read * @param value pointer to a buffer to store the value - * @return ? to be discussed, LV_RESULT_OK or LV_RESULT_INVALID + * @return return the property value read. The returned property ID is set to `LV_PROPERTY_ID_INVALID` if failed. */ lv_property_t lv_obj_get_property(lv_obj_t * obj, lv_prop_id_t id); +/** + * Read a style property value from object + * @param obj pointer to an object + * @param id ID of style property + * @param selector selector for the style property. + * @return return the property value read. The returned property ID is set to `LV_PROPERTY_ID_INVALID` if failed. + */ +lv_property_t lv_obj_get_style_property(lv_obj_t * obj, lv_prop_id_t id, uint32_t selector); + /********************** * MACROS **********************/ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a1a3a8e8d..02d71a3da 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -90,6 +90,7 @@ set(LVGL_TEST_OPTIONS_TEST_SYSHEAP set(LVGL_TEST_OPTIONS_TEST_DEFHEAP -DLV_TEST_OPTION=5 + -DLV_USE_OBJ_PROPERTY=1 # add obj property test and disable pedantic -DLVGL_CI_USING_DEF_HEAP -fsanitize=address -fsanitize=leak @@ -194,6 +195,12 @@ list(APPEND COMPILE_OPTIONS ${BUILD_TARGET_DEF} ) +# LV_USE_OBJ_PROPERTY is enabled in option OPTIONS_TEST_DEFHEAP +# It relies on C11 anonymous struct/union support, thus disable warnings. +if(OPTIONS_TEST_DEFHEAP) + list(REMOVE_ITEM COMPILE_OPTIONS -pedantic-errors -Wpedantic) +endif() + filter_compiler_options(C LVGL_C_COMPILE_OPTIONS ${COMPILE_OPTIONS}) if(NOT (CMAKE_C_COMPILER_ID STREQUAL "MSVC")) diff --git a/tests/src/lv_test_conf_full.h b/tests/src/lv_test_conf_full.h index 7769f57d5..0b995dba1 100644 --- a/tests/src/lv_test_conf_full.h +++ b/tests/src/lv_test_conf_full.h @@ -110,7 +110,6 @@ #define LV_USE_OBJ_ID 1 #define LV_USE_OBJ_ID_BUILTIN 1 -#define LV_USE_OBJ_PROPERTY 0 #define LV_CACHE_DEF_SIZE (10 * 1024 * 1024) diff --git a/tests/src/test_cases/widgets/test_obj_property.c b/tests/src/test_cases/widgets/test_obj_property.c index 960f605ca..4200ba65a 100644 --- a/tests/src/test_cases/widgets/test_obj_property.c +++ b/tests/src/test_cases/widgets/test_obj_property.c @@ -94,6 +94,30 @@ void test_obj_property_set_get_should_match(void) #endif } +void test_obj_property_style_selector(void) +{ +#if LV_USE_OBJ_PROPERTY + lv_obj_t * obj = lv_obj_create(lv_screen_active()); + lv_property_t prop = { }; + + /* Style property with default selector(0) should work */ + prop.id = LV_STYLE_X; + prop.num = 0xaabb; /* `num` shares same memory with `prop.style.value.num` */ + /* selector is initialed to zero when prop is defined. */ + TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK); + TEST_ASSERT_EQUAL_UINT32(0xaabb, lv_obj_get_style_x(obj, 0)); + TEST_ASSERT_EQUAL_UINT32(0xaabb, lv_obj_get_style_property(obj, LV_STYLE_X, 0).num); + + lv_style_selector_t selector = LV_PART_MAIN | LV_STATE_PRESSED; + prop.id = LV_STYLE_X; + prop.num = 0x1122; + prop.selector = selector; + TEST_ASSERT_TRUE(lv_obj_set_property(obj, &prop) == LV_RESULT_OK); + TEST_ASSERT_EQUAL_UINT32(0x1122, lv_obj_get_style_x(obj, selector)); + TEST_ASSERT_EQUAL_UINT32(0x1122, lv_obj_get_style_property(obj, LV_STYLE_X, selector).num); +#endif +} + void test_obj_property_flag(void) { #if LV_USE_OBJ_PROPERTY