diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c index ce01d5304..b68e26182 100644 --- a/src/core/lv_obj_style.c +++ b/src/core/lv_obj_style.c @@ -50,7 +50,8 @@ typedef enum { **********************/ static lv_style_t * get_local_style(lv_obj_t * obj, lv_style_selector_t selector); static _lv_obj_style_t * get_trans_style(lv_obj_t * obj, uint32_t part); -static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, lv_style_value_t * v); +static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop, + lv_style_value_t * v); static void report_style_change_core(void * style, lv_obj_t * obj); static void refresh_children_style(lv_obj_t * obj); static bool trans_delete(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit); @@ -62,6 +63,8 @@ static void full_cache_refresh(lv_obj_t * obj, lv_part_t part); static void fade_anim_cb(void * obj, int32_t v); static void fade_in_anim_ready(lv_anim_t * a); static bool style_has_flag(const lv_style_t * style, uint32_t flag); +static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop, + lv_style_value_t * value_act); /********************** * STATIC VARIABLES @@ -390,72 +393,29 @@ lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_ { LV_ASSERT_NULL(obj) + lv_style_selector_t selector = part | obj->state; lv_style_value_t value_act = { .ptr = NULL }; lv_style_res_t found; - /*The happy path*/ -#if LV_OBJ_STYLE_CACHE - const uint32_t prop_shifted = STYLE_PROP_SHIFTED(prop); - if((part == LV_PART_MAIN ? obj->style_main_prop_is_set : obj->style_other_prop_is_set) & prop_shifted) -#endif - { - found = get_prop_core(obj, part, prop, &value_act); - if(found == LV_STYLE_RES_FOUND) return value_act; - } - - extern const uint8_t _lv_style_builtin_prop_flag_lookup_table[]; - bool inheritable = false; - if(prop < _LV_STYLE_NUM_BUILT_IN_PROPS) { - inheritable = _lv_style_builtin_prop_flag_lookup_table[prop] & LV_STYLE_PROP_FLAG_INHERITABLE; - } - else { - if(_style_custom_prop_flag_lookup_table != NULL) { - inheritable = _style_custom_prop_flag_lookup_table[prop - _LV_STYLE_NUM_BUILT_IN_PROPS] & - LV_STYLE_PROP_FLAG_INHERITABLE; - } - } - - if(inheritable) { - /*If not found, check the `MAIN` style first, if already on the MAIN part go to the parent*/ - if(part != LV_PART_MAIN) part = LV_PART_MAIN; - else obj = obj->parent; - - while(obj) { -#if LV_OBJ_STYLE_CACHE - if(obj->style_main_prop_is_set & prop_shifted) -#endif - { - found = get_prop_core(obj, part, prop, &value_act); - if(found == LV_STYLE_RES_FOUND) return value_act; - } - /*Check the parent too.*/ - obj = obj->parent; - } - } - else { - /*Get the width and height from the class. - * WIDTH and HEIGHT are not inherited so add them in the `else` to skip checking them for inherited properties */ - if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) { - const lv_obj_class_t * cls = obj->class_p; - while(cls) { - if(prop == LV_STYLE_WIDTH) { - if(cls->width_def != 0) return (lv_style_value_t) { - .num = cls->width_def - }; - } - else { - if(cls->height_def != 0) return (lv_style_value_t) { - .num = cls->height_def - }; - } - cls = cls->base_class; - } - } - } + found = get_selector_style_prop(obj, selector, prop, &value_act); + if(found == LV_STYLE_RES_FOUND) return value_act; return lv_style_prop_get_default_inlined(prop); } +bool lv_obj_has_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop) +{ + LV_ASSERT_NULL(obj) + + lv_style_value_t value_act = { .ptr = NULL }; + lv_style_res_t found; + + found = get_selector_style_prop(obj, selector, prop, &value_act); + if(found == LV_STYLE_RES_FOUND) return true; + + return false; +} + void lv_obj_set_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value, lv_style_selector_t selector) { @@ -786,11 +746,13 @@ static _lv_obj_style_t * get_trans_style(lv_obj_t * obj, lv_style_selector_t se return &obj->styles[0]; } -static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, lv_style_value_t * v) +static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop, + lv_style_value_t * v) { const uint32_t group = (uint32_t)1 << _lv_style_get_prop_group(prop); - const lv_state_t state = obj->state; + const lv_part_t part = lv_obj_style_get_selector_part(selector); + const lv_state_t state = lv_obj_style_get_selector_state(selector); const lv_state_t state_inv = ~state; const bool skip_trans = obj->skip_trans; int32_t weight = -1; @@ -1140,3 +1102,75 @@ static bool style_has_flag(const lv_style_t * style, uint32_t flag) } return false; } + +static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop, + lv_style_value_t * value_act) +{ + lv_style_res_t found; + lv_part_t part = lv_obj_style_get_selector_part(selector); + + /*The happy path*/ +#if LV_OBJ_STYLE_CACHE + const uint32_t prop_shifted = STYLE_PROP_SHIFTED(prop); + if((part == LV_PART_MAIN ? obj->style_main_prop_is_set : obj->style_other_prop_is_set) & prop_shifted) +#endif + { + found = get_prop_core(obj, selector, prop, value_act); + if(found == LV_STYLE_RES_FOUND) return LV_STYLE_RES_FOUND; + } + + extern const uint8_t _lv_style_builtin_prop_flag_lookup_table[]; + bool inheritable = false; + if(prop < _LV_STYLE_NUM_BUILT_IN_PROPS) { + inheritable = _lv_style_builtin_prop_flag_lookup_table[prop] & LV_STYLE_PROP_FLAG_INHERITABLE; + } + else { + if(_style_custom_prop_flag_lookup_table != NULL) { + inheritable = _style_custom_prop_flag_lookup_table[prop - _LV_STYLE_NUM_BUILT_IN_PROPS] & + LV_STYLE_PROP_FLAG_INHERITABLE; + } + } + + if(inheritable) { + /*If not found, check the `MAIN` style first, if already on the MAIN part go to the parent*/ + if(part != LV_PART_MAIN) part = LV_PART_MAIN; + else obj = obj->parent; + + while(obj) { +#if LV_OBJ_STYLE_CACHE + if(obj->style_main_prop_is_set & prop_shifted) +#endif + { + selector = part | obj->state; + found = get_prop_core(obj, selector, prop, value_act); + if(found == LV_STYLE_RES_FOUND) return LV_STYLE_RES_FOUND; + } + /*Check the parent too.*/ + obj = obj->parent; + } + } + else { + /*Get the width and height from the class. + * WIDTH and HEIGHT are not inherited so add them in the `else` to skip checking them for inherited properties */ + if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) { + const lv_obj_class_t * cls = obj->class_p; + while(cls) { + if(prop == LV_STYLE_WIDTH) { + if(cls->width_def != 0) { + value_act->num = cls->width_def; + return LV_STYLE_RES_FOUND; + } + } + else { + if(cls->height_def != 0) { + value_act->num = cls->height_def; + return LV_STYLE_RES_FOUND; + } + } + cls = cls->base_class; + } + } + } + + return LV_STYLE_RES_NOT_FOUND; +} \ No newline at end of file diff --git a/src/core/lv_obj_style.h b/src/core/lv_obj_style.h index 04d0ef802..95a9dee46 100644 --- a/src/core/lv_obj_style.h +++ b/src/core/lv_obj_style.h @@ -155,6 +155,15 @@ void lv_obj_enable_style_refresh(bool en); */ lv_style_value_t lv_obj_get_style_prop(const struct _lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop); +/** + * Check if an object has a specified style property for a given style selector. + * @param obj pointer to an object + * @param selector the style selector to be checked, defining the scope of the style to be examined. + * @param prop the property to be checked. + * @return true if the object has the specified selector and property, false otherwise. + */ +bool lv_obj_has_style_prop(const struct _lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop); + /** * Set local style property on an object's part and state. * @param obj pointer to an object diff --git a/tests/src/test_cases/test_style.c b/tests/src/test_cases/test_style.c index 9a6cef6a6..3fd6b6906 100644 --- a/tests/src/test_cases/test_style.c +++ b/tests/src/test_cases/test_style.c @@ -117,4 +117,27 @@ void test_style_replacement(void) lv_style_reset(&style_blue); } +void test_style_has_prop(void) +{ + lv_style_t style; + lv_style_init(&style); + lv_style_set_outline_color(&style, lv_color_white()); + + /*Create object with style*/ + lv_obj_t * obj = lv_obj_create(lv_screen_active()); + + TEST_ASSERT_EQUAL(false, lv_obj_has_style_prop(obj, LV_PART_MAIN, LV_STYLE_OUTLINE_COLOR)); + TEST_ASSERT_EQUAL(false, lv_obj_has_style_prop(obj, LV_PART_MAIN, LV_STYLE_OUTLINE_WIDTH)); + TEST_ASSERT_EQUAL(false, lv_obj_has_style_prop(obj, LV_PART_INDICATOR, LV_STYLE_OUTLINE_COLOR)); + + lv_obj_add_style(obj, &style, LV_PART_MAIN); + lv_obj_set_style_outline_width(obj, 2, LV_PART_MAIN); + + TEST_ASSERT_EQUAL(true, lv_obj_has_style_prop(obj, LV_PART_MAIN, LV_STYLE_OUTLINE_COLOR)); + TEST_ASSERT_EQUAL(true, lv_obj_has_style_prop(obj, LV_PART_MAIN, LV_STYLE_OUTLINE_WIDTH)); + TEST_ASSERT_EQUAL(false, lv_obj_has_style_prop(obj, LV_PART_INDICATOR, LV_STYLE_OUTLINE_COLOR)); + + lv_style_reset(&style); +} + #endif