1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

feat(style) add 'inherit' and 'initial' CSS properties (#3390)

Fixes #3086
This commit is contained in:
embeddedt 2022-06-09 20:20:34 -04:00 committed by GitHub
parent 03c43d95ad
commit 9a48de0f8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 312 additions and 175 deletions

View File

@ -84,6 +84,23 @@ Inheritance is applied only if the given property is not set in the object's sty
In this case, if the property is inheritable, the property's value will be searched in the parents until an object specifies a value for the property. The parents will use their own state to determine the value. In this case, if the property is inheritable, the property's value will be searched in the parents until an object specifies a value for the property. The parents will use their own state to determine the value.
So if a button is pressed, and the text color comes from here, the pressed text color will be used. So if a button is pressed, and the text color comes from here, the pressed text color will be used.
## Forced value inheritance/default value
Sometimes you may want to force a child object to use the parent's value for a given style property. To do this you can use
one of the following (depending on what type of style you're using):
```c
/* regular style */
lv_style_set_prop_meta(&style, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT);
/* local style */
lv_obj_set_local_style_prop_meta(child, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT, LV_PART_MAIN);
```
This acts like a value has been set on the style, so setting the value of the property afterwards will remove the flag.
You may also want to force the default value of a property to be used, without needing to hardcode it in your application.
To do this you can use the same API but with `LV_STYLE_PROP_META_INITIAL` instead. In future versions of LVGL, this
will use the value based upon the current theme, but for now it just selects the internal default regardless of theme.
## Parts ## Parts
Objects can be composed of *parts* which may each have their own styles. Objects can be composed of *parts* which may each have their own styles.

View File

@ -882,7 +882,7 @@ static void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state)
if(obj_style->is_trans) continue; if(obj_style->is_trans) continue;
lv_style_value_t v; lv_style_value_t v;
if(lv_style_get_prop_inlined(obj_style->style, LV_STYLE_TRANSITION, &v) == false) continue; if(lv_style_get_prop_inlined(obj_style->style, LV_STYLE_TRANSITION, &v) != LV_STYLE_RES_FOUND) continue;
const lv_style_transition_dsc_t * tr = v.ptr; const lv_style_transition_dsc_t * tr = v.ptr;
/*Add the props to the set if not added yet or added but with smaller weight*/ /*Add the props to the set if not added yet or added but with smaller weight*/

View File

@ -44,7 +44,7 @@ typedef enum {
**********************/ **********************/
static lv_style_t * get_local_style(lv_obj_t * obj, lv_style_selector_t selector); 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_obj_style_t * get_trans_style(lv_obj_t * obj, uint32_t part);
static bool 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_part_t part, lv_style_prop_t prop, lv_style_value_t * v);
static void report_style_change_core(void * style, lv_obj_t * obj); static void report_style_change_core(void * style, lv_obj_t * obj);
static void refresh_children_style(lv_obj_t * obj); static void refresh_children_style(lv_obj_t * obj);
static bool trans_del(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit); static bool trans_del(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit);
@ -176,7 +176,7 @@ void lv_obj_refresh_style(lv_obj_t * obj, lv_style_selector_t selector, lv_style
bool is_layout_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_LAYOUT_REFR); bool is_layout_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_LAYOUT_REFR);
bool is_ext_draw = lv_style_prop_has_flag(prop, LV_STYLE_PROP_EXT_DRAW); bool is_ext_draw = lv_style_prop_has_flag(prop, LV_STYLE_PROP_EXT_DRAW);
bool is_inherit = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT); bool is_inheritable = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT);
bool is_layer_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_LAYER_REFR); bool is_layer_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_LAYER_REFR);
if(is_layout_refr) { if(is_layout_refr) {
@ -208,7 +208,7 @@ void lv_obj_refresh_style(lv_obj_t * obj, lv_style_selector_t selector, lv_style
} }
lv_obj_invalidate(obj); lv_obj_invalidate(obj);
if(prop == LV_STYLE_PROP_ANY || (is_inherit && (is_ext_draw || is_layout_refr))) { if(prop == LV_STYLE_PROP_ANY || (is_inheritable && (is_ext_draw || is_layout_refr))) {
if(part != LV_PART_SCROLLBAR) { if(part != LV_PART_SCROLLBAR) {
refresh_children_style(obj); refresh_children_style(obj);
} }
@ -223,15 +223,15 @@ void lv_obj_enable_style_refresh(bool en)
lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop) lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop)
{ {
lv_style_value_t value_act; lv_style_value_t value_act;
bool inherit = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT); bool inheritable = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT);
bool found = false; lv_style_res_t found = LV_STYLE_RES_NOT_FOUND;
while(obj) { while(obj) {
found = get_prop_core(obj, part, prop, &value_act); found = get_prop_core(obj, part, prop, &value_act);
if(found) break; if(found == LV_STYLE_RES_FOUND) break;
if(!inherit) break; if(!inheritable) break;
/*If not found, check the `MAIN` style first*/ /*If not found, check the `MAIN` style first*/
if(part != LV_PART_MAIN) { if(found != LV_STYLE_RES_INHERIT && part != LV_PART_MAIN) {
part = LV_PART_MAIN; part = LV_PART_MAIN;
continue; continue;
} }
@ -240,7 +240,7 @@ lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_
obj = lv_obj_get_parent(obj); obj = lv_obj_get_parent(obj);
} }
if(!found) { if(found != LV_STYLE_RES_FOUND) {
if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) { if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) {
const lv_obj_class_t * cls = obj->class_p; const lv_obj_class_t * cls = obj->class_p;
while(cls) { while(cls) {
@ -275,8 +275,16 @@ void lv_obj_set_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_
lv_obj_refresh_style(obj, selector, prop); lv_obj_refresh_style(obj, selector, prop);
} }
void lv_obj_set_local_style_prop_meta(lv_obj_t * obj, lv_style_prop_t prop, uint16_t meta,
lv_style_selector_t selector)
{
lv_style_t * style = get_local_style(obj, selector);
lv_style_set_prop_meta(style, prop, meta);
lv_obj_refresh_style(obj, selector, prop);
}
lv_res_t lv_obj_get_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value,
lv_style_res_t lv_obj_get_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value,
lv_style_selector_t selector) lv_style_selector_t selector)
{ {
uint32_t i; uint32_t i;
@ -287,7 +295,7 @@ lv_res_t lv_obj_get_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_st
} }
} }
return LV_RES_INV; return LV_STYLE_RES_NOT_FOUND;
} }
bool lv_obj_remove_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector) bool lv_obj_remove_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector)
@ -556,7 +564,7 @@ static _lv_obj_style_t * get_trans_style(lv_obj_t * obj, lv_style_selector_t se
} }
static bool 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_part_t part, lv_style_prop_t prop, lv_style_value_t * v)
{ {
uint8_t group = 1 << _lv_style_get_prop_group(prop); uint8_t group = 1 << _lv_style_get_prop_group(prop);
int32_t weight = -1; int32_t weight = -1;
@ -565,7 +573,7 @@ static bool get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t
lv_style_value_t value_tmp; lv_style_value_t value_tmp;
bool skip_trans = obj->skip_trans; bool skip_trans = obj->skip_trans;
uint32_t i; uint32_t i;
bool found; lv_style_res_t found;
for(i = 0; i < obj->style_cnt; i++) { for(i = 0; i < obj->style_cnt; i++) {
_lv_obj_style_t * obj_style = &obj->styles[i]; _lv_obj_style_t * obj_style = &obj->styles[i];
if(obj_style->is_trans == false) break; if(obj_style->is_trans == false) break;
@ -576,9 +584,12 @@ static bool get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t
if(part_act != part) continue; if(part_act != part) continue;
if((obj_style->style->has_group & group) == 0) continue; if((obj_style->style->has_group & group) == 0) continue;
found = lv_style_get_prop(obj_style->style, prop, &value_tmp); found = lv_style_get_prop(obj_style->style, prop, &value_tmp);
if(found) { if(found == LV_STYLE_RES_FOUND) {
*v = value_tmp; *v = value_tmp;
return true; return LV_STYLE_RES_FOUND;
}
else if(found == LV_STYLE_RES_INHERIT) {
return LV_STYLE_RES_INHERIT;
} }
} }
@ -598,23 +609,26 @@ static bool get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t
found = lv_style_get_prop(obj_style->style, prop, &value_tmp); found = lv_style_get_prop(obj_style->style, prop, &value_tmp);
if(found) { if(found == LV_STYLE_RES_FOUND) {
if(state_act == state) { if(state_act == state) {
*v = value_tmp; *v = value_tmp;
return true; return LV_STYLE_RES_FOUND;
} }
if(weight < state_act) { if(weight < state_act) {
weight = state_act; weight = state_act;
*v = value_tmp; *v = value_tmp;
} }
} }
else if(found == LV_STYLE_RES_INHERIT) {
return LV_STYLE_RES_INHERIT;
}
} }
if(weight >= 0) { if(weight >= 0) {
*v = value_tmp; *v = value_tmp;
return true; return LV_STYLE_RES_FOUND;
} }
else return false; else return LV_STYLE_RES_NOT_FOUND;
} }
/** /**

View File

@ -140,7 +140,10 @@ lv_style_value_t lv_obj_get_style_prop(const struct _lv_obj_t * obj, lv_part_t p
void lv_obj_set_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value, void lv_obj_set_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value,
lv_style_selector_t selector); lv_style_selector_t selector);
lv_res_t lv_obj_get_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value, void lv_obj_set_local_style_prop_meta(struct _lv_obj_t * obj, lv_style_prop_t prop, uint16_t meta,
lv_style_selector_t selector);
lv_style_res_t lv_obj_get_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value,
lv_style_selector_t selector); lv_style_selector_t selector);
/** /**

View File

@ -600,8 +600,7 @@ void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selec
lv_obj_set_local_style_prop(obj, LV_STYLE_OPA, v, selector); lv_obj_set_local_style_prop(obj, LV_STYLE_OPA, v, selector);
} }
void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector)
lv_style_selector_t selector)
{ {
lv_style_value_t v = { lv_style_value_t v = {
.ptr = value .ptr = value
@ -641,8 +640,7 @@ void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_styl
lv_obj_set_local_style_prop(obj, LV_STYLE_ANIM_SPEED, v, selector); lv_obj_set_local_style_prop(obj, LV_STYLE_ANIM_SPEED, v, selector);
} }
void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector)
lv_style_selector_t selector)
{ {
lv_style_value_t v = { lv_style_value_t v = {
.ptr = value .ptr = value

View File

@ -162,8 +162,7 @@ static inline lv_color_t lv_obj_get_style_bg_grad_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_bg_grad_color_filtered(const struct _lv_obj_t * obj, uint32_t part) static inline lv_color_t lv_obj_get_style_bg_grad_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{ {
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR));
LV_STYLE_BG_GRAD_COLOR));
return v.color; return v.color;
} }
@ -217,8 +216,7 @@ static inline lv_color_t lv_obj_get_style_bg_img_recolor(const struct _lv_obj_t
static inline lv_color_t lv_obj_get_style_bg_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part) static inline lv_color_t lv_obj_get_style_bg_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part)
{ {
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_RECOLOR));
LV_STYLE_BG_IMG_RECOLOR));
return v.color; return v.color;
} }
@ -242,8 +240,7 @@ static inline lv_color_t lv_obj_get_style_border_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_border_color_filtered(const struct _lv_obj_t * obj, uint32_t part) static inline lv_color_t lv_obj_get_style_border_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{ {
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR));
LV_STYLE_BORDER_COLOR));
return v.color; return v.color;
} }
@ -285,8 +282,7 @@ static inline lv_color_t lv_obj_get_style_outline_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_outline_color_filtered(const struct _lv_obj_t * obj, uint32_t part) static inline lv_color_t lv_obj_get_style_outline_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{ {
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR));
LV_STYLE_OUTLINE_COLOR));
return v.color; return v.color;
} }
@ -334,8 +330,7 @@ static inline lv_color_t lv_obj_get_style_shadow_color(const struct _lv_obj_t *
static inline lv_color_t lv_obj_get_style_shadow_color_filtered(const struct _lv_obj_t * obj, uint32_t part) static inline lv_color_t lv_obj_get_style_shadow_color_filtered(const struct _lv_obj_t * obj, uint32_t part)
{ {
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR));
LV_STYLE_SHADOW_COLOR));
return v.color; return v.color;
} }
@ -359,8 +354,7 @@ static inline lv_color_t lv_obj_get_style_img_recolor(const struct _lv_obj_t * o
static inline lv_color_t lv_obj_get_style_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part) static inline lv_color_t lv_obj_get_style_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part)
{ {
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_RECOLOR));
LV_STYLE_IMG_RECOLOR));
return v.color; return v.color;
} }
@ -514,8 +508,7 @@ static inline lv_opa_t lv_obj_get_style_opa(const struct _lv_obj_t * obj, uint32
return (lv_opa_t)v.num; return (lv_opa_t)v.num;
} }
static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj, static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj, uint32_t part)
uint32_t part)
{ {
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_DSC); lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_DSC);
return (const lv_color_filter_dsc_t *)v.ptr; return (const lv_color_filter_dsc_t *)v.ptr;
@ -644,14 +637,12 @@ void lv_obj_set_style_text_align(struct _lv_obj_t * obj, lv_text_align_t value,
void lv_obj_set_style_radius(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); void lv_obj_set_style_radius(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_clip_corner(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector); void lv_obj_set_style_clip_corner(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector);
void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector);
lv_style_selector_t selector);
void lv_obj_set_style_color_filter_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); void lv_obj_set_style_color_filter_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_anim(struct _lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector); void lv_obj_set_style_anim(struct _lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector);
void lv_obj_set_style_anim_time(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector); void lv_obj_set_style_anim_time(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector); void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector);
lv_style_selector_t selector);
void lv_obj_set_style_blend_mode(struct _lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector); void lv_obj_set_style_blend_mode(struct _lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector);
void lv_obj_set_style_layout(struct _lv_obj_t * obj, uint16_t value, lv_style_selector_t selector); void lv_obj_set_style_layout(struct _lv_obj_t * obj, uint16_t value, lv_style_selector_t selector);
void lv_obj_set_style_base_dir(struct _lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector); void lv_obj_set_style_base_dir(struct _lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector);

View File

@ -9,6 +9,8 @@
#include "lv_style.h" #include "lv_style.h"
#include "../misc/lv_gc.h" #include "../misc/lv_gc.h"
#include "../misc/lv_mem.h" #include "../misc/lv_mem.h"
#include "lv_assert.h"
#include "lv_types.h"
/********************* /*********************
* DEFINES * DEFINES
@ -22,6 +24,13 @@
* STATIC PROTOTYPES * STATIC PROTOTYPES
**********************/ **********************/
static void lv_style_set_prop_internal(lv_style_t * style, lv_style_prop_t prop_and_meta, lv_style_value_t value,
void (*value_adjustment_helper)(lv_style_prop_t, lv_style_value_t, uint16_t *, lv_style_value_t *));
static void lv_style_set_prop_helper(lv_style_prop_t prop, lv_style_value_t value, uint16_t * prop_storage,
lv_style_value_t * value_storage);
static void lv_style_set_prop_meta_helper(lv_style_prop_t prop, lv_style_value_t value, uint16_t * prop_storage,
lv_style_value_t * value_storage);
/********************** /**********************
* GLOBAL VARIABLES * GLOBAL VARIABLES
**********************/ **********************/
@ -128,6 +137,7 @@ uint32_t _lv_style_custom_prop_flag_lookup_table_size = 0;
**********************/ **********************/
static uint16_t last_custom_prop_id = (uint16_t)_LV_STYLE_LAST_BUILT_IN_PROP; static uint16_t last_custom_prop_id = (uint16_t)_LV_STYLE_LAST_BUILT_IN_PROP;
static const lv_style_value_t null_style_value = { .num = 0 };
/********************** /**********************
* MACROS * MACROS
@ -155,7 +165,7 @@ void lv_style_reset(lv_style_t * style)
{ {
LV_ASSERT_STYLE(style); LV_ASSERT_STYLE(style);
if(style->is_const) { if(style->prop1 == LV_STYLE_PROP_ANY) {
LV_LOG_ERROR("Cannot reset const style"); LV_LOG_ERROR("Cannot reset const style");
return; return;
} }
@ -171,14 +181,22 @@ lv_style_prop_t lv_style_register_prop(uint8_t flag)
{ {
if(LV_GC_ROOT(_lv_style_custom_prop_flag_lookup_table) == NULL) { if(LV_GC_ROOT(_lv_style_custom_prop_flag_lookup_table) == NULL) {
_lv_style_custom_prop_flag_lookup_table_size = 0; _lv_style_custom_prop_flag_lookup_table_size = 0;
last_custom_prop_id = (uint16_t)_LV_STYLE_LAST_BUILT_IN_PROP;
} }
if(((last_custom_prop_id + 1) & LV_STYLE_PROP_META_MASK) != 0) {
LV_LOG_ERROR("No more custom property IDs available");
return LV_STYLE_PROP_INV;
}
/* /*
* Allocate the lookup table if it's not yet available. * Allocate the lookup table if it's not yet available.
*/ */
uint8_t required_size = (last_custom_prop_id + 1 - _LV_STYLE_LAST_BUILT_IN_PROP); size_t required_size = (last_custom_prop_id + 1 - _LV_STYLE_LAST_BUILT_IN_PROP);
if(_lv_style_custom_prop_flag_lookup_table_size < required_size) { if(_lv_style_custom_prop_flag_lookup_table_size < required_size) {
/* Round required_size up to the nearest 32-byte value */ /* Round required_size up to the nearest 32-byte value */
required_size = (required_size + 31) & ~31; required_size = (required_size + 31) & ~31;
LV_ASSERT_MSG(required_size > 0, "required size has become 0?");
uint8_t * old_p = LV_GC_ROOT(_lv_style_custom_prop_flag_lookup_table); uint8_t * old_p = LV_GC_ROOT(_lv_style_custom_prop_flag_lookup_table);
uint8_t * new_p = lv_mem_realloc(old_p, required_size * sizeof(uint8_t)); uint8_t * new_p = lv_mem_realloc(old_p, required_size * sizeof(uint8_t));
if(new_p == NULL) { if(new_p == NULL) {
@ -204,7 +222,7 @@ bool lv_style_remove_prop(lv_style_t * style, lv_style_prop_t prop)
{ {
LV_ASSERT_STYLE(style); LV_ASSERT_STYLE(style);
if(style->is_const) { if(style->prop1 == LV_STYLE_PROP_ANY) {
LV_LOG_ERROR("Cannot remove prop from const style"); LV_LOG_ERROR("Cannot remove prop from const style");
return false; return false;
} }
@ -212,7 +230,7 @@ bool lv_style_remove_prop(lv_style_t * style, lv_style_prop_t prop)
if(style->prop_cnt == 0) return false; if(style->prop_cnt == 0) return false;
if(style->prop_cnt == 1) { if(style->prop_cnt == 1) {
if(style->prop1 == prop) { if(LV_STYLE_PROP_ID_MASK(style->prop1) == prop) {
style->prop1 = LV_STYLE_PROP_INV; style->prop1 = LV_STYLE_PROP_INV;
style->prop_cnt = 0; style->prop_cnt = 0;
return true; return true;
@ -224,7 +242,7 @@ bool lv_style_remove_prop(lv_style_t * style, lv_style_prop_t prop)
uint16_t * old_props = (uint16_t *)tmp; uint16_t * old_props = (uint16_t *)tmp;
uint32_t i; uint32_t i;
for(i = 0; i < style->prop_cnt; i++) { for(i = 0; i < style->prop_cnt; i++) {
if(old_props[i] == prop) { if(LV_STYLE_PROP_ID_MASK(old_props[i]) == prop) {
lv_style_value_t * old_values = (lv_style_value_t *)style->v_p.values_and_props; lv_style_value_t * old_values = (lv_style_value_t *)style->v_p.values_and_props;
if(style->prop_cnt == 2) { if(style->prop_cnt == 2) {
@ -263,78 +281,15 @@ bool lv_style_remove_prop(lv_style_t * style, lv_style_prop_t prop)
void lv_style_set_prop(lv_style_t * style, lv_style_prop_t prop, lv_style_value_t value) void lv_style_set_prop(lv_style_t * style, lv_style_prop_t prop, lv_style_value_t value)
{ {
LV_ASSERT_STYLE(style); lv_style_set_prop_internal(style, prop, value, lv_style_set_prop_helper);
if(style->is_const) {
LV_LOG_ERROR("Cannot set property of constant style");
return;
}
if(style->prop_cnt > 1) {
uint8_t * tmp = style->v_p.values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
uint16_t * props = (uint16_t *)tmp;
int32_t i;
for(i = style->prop_cnt - 1; i >= 0; i--) {
if(props[i] == prop) {
lv_style_value_t * values = (lv_style_value_t *)style->v_p.values_and_props;
values[i] = value;
return;
}
}
size_t size = (style->prop_cnt + 1) * (sizeof(lv_style_value_t) + sizeof(uint16_t));
uint8_t * values_and_props = lv_mem_realloc(style->v_p.values_and_props, size);
if(values_and_props == NULL) return;
style->v_p.values_and_props = values_and_props;
tmp = values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
props = (uint16_t *)tmp;
/*Shift all props to make place for the value before them*/
for(i = style->prop_cnt - 1; i >= 0; i--) {
props[i + sizeof(lv_style_value_t) / sizeof(uint16_t)] = props[i];
}
style->prop_cnt++;
/*Go to the new position wit the props*/
tmp = values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
props = (uint16_t *)tmp;
lv_style_value_t * values = (lv_style_value_t *)values_and_props;
/*Set the new property and value*/
props[style->prop_cnt - 1] = prop;
values[style->prop_cnt - 1] = value;
}
else if(style->prop_cnt == 1) {
if(style->prop1 == prop) {
style->v_p.value1 = value;
return;
}
size_t size = (style->prop_cnt + 1) * (sizeof(lv_style_value_t) + sizeof(uint16_t));
uint8_t * values_and_props = lv_mem_alloc(size);
if(values_and_props == NULL) return;
lv_style_value_t value_tmp = style->v_p.value1;
style->v_p.values_and_props = values_and_props;
style->prop_cnt++;
uint8_t * tmp = values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
uint16_t * props = (uint16_t *)tmp;
lv_style_value_t * values = (lv_style_value_t *)values_and_props;
props[0] = style->prop1;
props[1] = prop;
values[0] = value_tmp;
values[1] = value;
}
else {
style->prop_cnt = 1;
style->prop1 = prop;
style->v_p.value1 = value;
}
uint8_t group = _lv_style_get_prop_group(prop);
style->has_group |= 1 << group;
} }
lv_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_style_value_t * value) void lv_style_set_prop_meta(lv_style_t * style, lv_style_prop_t prop, uint16_t meta)
{
lv_style_set_prop_internal(style, prop | meta, null_style_value, lv_style_set_prop_meta_helper);
}
lv_style_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_style_value_t * value)
{ {
return lv_style_get_prop_inlined(style, prop, value); return lv_style_get_prop_inlined(style, prop, value);
} }
@ -439,3 +394,92 @@ uint8_t _lv_style_prop_lookup_flags(lv_style_prop_t prop)
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/
static void lv_style_set_prop_helper(lv_style_prop_t prop, lv_style_value_t value, uint16_t * prop_storage,
lv_style_value_t * value_storage)
{
*prop_storage = prop;
*value_storage = value;
}
static void lv_style_set_prop_meta_helper(lv_style_prop_t prop, lv_style_value_t value, uint16_t * prop_storage,
lv_style_value_t * value_storage)
{
LV_UNUSED(value);
LV_UNUSED(value_storage);
*prop_storage = prop; /* meta is OR-ed into the prop ID already */
}
static void lv_style_set_prop_internal(lv_style_t * style, lv_style_prop_t prop_and_meta, lv_style_value_t value,
void (*value_adjustment_helper)(lv_style_prop_t, lv_style_value_t, uint16_t *, lv_style_value_t *))
{
LV_ASSERT_STYLE(style);
if(style->prop1 == LV_STYLE_PROP_ANY) {
LV_LOG_ERROR("Cannot set property of constant style");
return;
}
lv_style_prop_t prop_id = LV_STYLE_PROP_ID_MASK(prop_and_meta);
if(style->prop_cnt > 1) {
uint8_t * tmp = style->v_p.values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
uint16_t * props = (uint16_t *)tmp;
int32_t i;
for(i = style->prop_cnt - 1; i >= 0; i--) {
if(LV_STYLE_PROP_ID_MASK(props[i]) == prop_id) {
lv_style_value_t * values = (lv_style_value_t *)style->v_p.values_and_props;
value_adjustment_helper(prop_and_meta, value, &props[i], &values[i]);
return;
}
}
size_t size = (style->prop_cnt + 1) * (sizeof(lv_style_value_t) + sizeof(uint16_t));
uint8_t * values_and_props = lv_mem_realloc(style->v_p.values_and_props, size);
if(values_and_props == NULL) return;
style->v_p.values_and_props = values_and_props;
tmp = values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
props = (uint16_t *)tmp;
/*Shift all props to make place for the value before them*/
for(i = style->prop_cnt - 1; i >= 0; i--) {
props[i + sizeof(lv_style_value_t) / sizeof(uint16_t)] = props[i];
}
style->prop_cnt++;
/*Go to the new position wit the props*/
tmp = values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
props = (uint16_t *)tmp;
lv_style_value_t * values = (lv_style_value_t *)values_and_props;
/*Set the new property and value*/
value_adjustment_helper(prop_and_meta, value, &props[style->prop_cnt - 1], &values[style->prop_cnt - 1]);
}
else if(style->prop_cnt == 1) {
if(LV_STYLE_PROP_ID_MASK(style->prop1) == prop_id) {
value_adjustment_helper(prop_and_meta, value, &style->prop1, &style->v_p.value1);
return;
}
size_t size = (style->prop_cnt + 1) * (sizeof(lv_style_value_t) + sizeof(uint16_t));
uint8_t * values_and_props = lv_mem_alloc(size);
if(values_and_props == NULL) return;
lv_style_value_t value_tmp = style->v_p.value1;
style->v_p.values_and_props = values_and_props;
style->prop_cnt++;
uint8_t * tmp = values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
uint16_t * props = (uint16_t *)tmp;
lv_style_value_t * values = (lv_style_value_t *)values_and_props;
props[0] = style->prop1;
values[0] = value_tmp;
value_adjustment_helper(prop_and_meta, value, &props[1], &values[1]);
}
else {
style->prop_cnt = 1;
value_adjustment_helper(prop_and_meta, value, &style->prop1, &style->v_p.value1);
}
uint8_t group = _lv_style_get_prop_group(prop_id);
style->has_group |= 1 << group;
}

View File

@ -50,9 +50,9 @@ extern "C" {
LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE); LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE);
#if LV_USE_ASSERT_STYLE #if LV_USE_ASSERT_STYLE
#define LV_STYLE_CONST_INIT(var_name, prop_array) const lv_style_t var_name = { .sentinel = LV_STYLE_SENTINEL_VALUE, .v_p = { .const_props = prop_array }, .has_group = 0xFF, .is_const = 1 } #define LV_STYLE_CONST_INIT(var_name, prop_array) const lv_style_t var_name = { .sentinel = LV_STYLE_SENTINEL_VALUE, .v_p = { .const_props = prop_array }, .has_group = 0xFF, .prop1 = LV_STYLE_PROP_ANY }
#else #else
#define LV_STYLE_CONST_INIT(var_name, prop_array) const lv_style_t var_name = { .v_p = { .const_props = prop_array }, .has_group = 0xFF, .is_const = 1 } #define LV_STYLE_CONST_INIT(var_name, prop_array) const lv_style_t var_name = { .v_p = { .const_props = prop_array }, .has_group = 0xFF, .prop1 = LV_STYLE_PROP_ANY }
#endif #endif
/** On simple system, don't waste resources on gradients */ /** On simple system, don't waste resources on gradients */
@ -60,6 +60,11 @@ LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE);
#define LV_GRADIENT_MAX_STOPS 2 #define LV_GRADIENT_MAX_STOPS 2
#endif #endif
#define LV_STYLE_PROP_META_INHERIT 0x8000
#define LV_STYLE_PROP_META_INITIAL 0x4000
#define LV_STYLE_PROP_META_MASK (LV_STYLE_PROP_META_INHERIT | LV_STYLE_PROP_META_INITIAL)
#define LV_STYLE_PROP_ID_MASK(prop) ((lv_style_prop_t)((prop) & ~LV_STYLE_PROP_META_MASK))
/********************** /**********************
* TYPEDEFS * TYPEDEFS
@ -264,9 +269,18 @@ typedef enum {
_LV_STYLE_LAST_BUILT_IN_PROP = 111, _LV_STYLE_LAST_BUILT_IN_PROP = 111,
_LV_STYLE_NUM_BUILT_IN_PROPS = _LV_STYLE_LAST_BUILT_IN_PROP + 1, _LV_STYLE_NUM_BUILT_IN_PROPS = _LV_STYLE_LAST_BUILT_IN_PROP + 1,
LV_STYLE_PROP_ANY = 0xFFFF LV_STYLE_PROP_ANY = 0xFFFF,
_LV_STYLE_PROP_CONST = 0xFFFF /* magic value for const styles */
} lv_style_prop_t; } lv_style_prop_t;
enum {
LV_STYLE_RES_NOT_FOUND,
LV_STYLE_RES_FOUND,
LV_STYLE_RES_INHERIT
};
typedef uint8_t lv_style_res_t;
/** /**
* Descriptor for style transitions * Descriptor for style transitions
*/ */
@ -305,8 +319,7 @@ typedef struct {
const lv_style_const_prop_t * const_props; const lv_style_const_prop_t * const_props;
} v_p; } v_p;
uint16_t prop1 : 15; uint16_t prop1;
uint16_t is_const : 1;
uint8_t has_group; uint8_t has_group;
uint8_t prop_cnt; uint8_t prop_cnt;
} lv_style_t; } lv_style_t;
@ -370,16 +383,13 @@ bool lv_style_remove_prop(lv_style_t * style, lv_style_prop_t prop);
void lv_style_set_prop(lv_style_t * style, lv_style_prop_t prop, lv_style_value_t value); void lv_style_set_prop(lv_style_t * style, lv_style_prop_t prop, lv_style_value_t value);
/** /**
* Get the value of a property * Set a special meta state for a property in a style.
* @param style pointer to a style * This function shouldn't be used directly by the user.
* @param prop the ID of a property * @param style pointer to style
* @param value pointer to a `lv_style_value_t` variable to store the value * @param prop the ID of a property (e.g. `LV_STYLE_BG_COLOR`)
* @return LV_RES_INV: the property wasn't found in the style (`value` is unchanged) * @param meta the meta value to attach to the property in the style
* LV_RES_OK: the property was fond, and `value` is set accordingly
* @note For performance reasons there are no sanity check on `style`
*/ */
lv_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_style_value_t * value); void lv_style_set_prop_meta(lv_style_t * style, lv_style_prop_t prop, uint16_t meta);
/** /**
* Get the value of a property * Get the value of a property
@ -389,42 +399,8 @@ lv_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_st
* @return LV_RES_INV: the property wasn't found in the style (`value` is unchanged) * @return LV_RES_INV: the property wasn't found in the style (`value` is unchanged)
* LV_RES_OK: the property was fond, and `value` is set accordingly * LV_RES_OK: the property was fond, and `value` is set accordingly
* @note For performance reasons there are no sanity check on `style` * @note For performance reasons there are no sanity check on `style`
* @note This function is the same as ::lv_style_get_prop but inlined. Use it only on performance critical places
*/ */
static inline lv_res_t lv_style_get_prop_inlined(const lv_style_t * style, lv_style_prop_t prop, lv_style_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_style_value_t * value);
lv_style_value_t * value)
{
if(style->is_const) {
const lv_style_const_prop_t * const_prop;
for(const_prop = style->v_p.const_props; const_prop->prop != LV_STYLE_PROP_INV; const_prop++) {
if(const_prop->prop == prop) {
*value = const_prop->value;
return LV_RES_OK;
}
}
return LV_RES_INV;
}
if(style->prop_cnt == 0) return LV_RES_INV;
if(style->prop_cnt > 1) {
uint8_t * tmp = style->v_p.values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
uint16_t * props = (uint16_t *)tmp;
uint32_t i;
for(i = 0; i < style->prop_cnt; i++) {
if(props[i] == prop) {
lv_style_value_t * values = (lv_style_value_t *)style->v_p.values_and_props;
*value = values[i];
return LV_RES_OK;
}
}
}
else if(style->prop1 == prop) {
*value = style->v_p.value1;
return LV_RES_OK;
}
return LV_RES_INV;
}
/** /**
* Initialize a transition descriptor. * Initialize a transition descriptor.
@ -449,6 +425,64 @@ void lv_style_transition_dsc_init(lv_style_transition_dsc_t * tr, const lv_style
*/ */
lv_style_value_t lv_style_prop_get_default(lv_style_prop_t prop); lv_style_value_t lv_style_prop_get_default(lv_style_prop_t prop);
/**
* Get the value of a property
* @param style pointer to a style
* @param prop the ID of a property
* @param value pointer to a `lv_style_value_t` variable to store the value
* @return LV_RES_INV: the property wasn't found in the style (`value` is unchanged)
* LV_RES_OK: the property was fond, and `value` is set accordingly
* @note For performance reasons there are no sanity check on `style`
* @note This function is the same as ::lv_style_get_prop but inlined. Use it only on performance critical places
*/
static inline lv_style_res_t lv_style_get_prop_inlined(const lv_style_t * style, lv_style_prop_t prop,
lv_style_value_t * value)
{
if(style->prop1 == LV_STYLE_PROP_ANY) {
const lv_style_const_prop_t * const_prop;
for(const_prop = style->v_p.const_props; const_prop->prop != LV_STYLE_PROP_INV; const_prop++) {
lv_style_prop_t prop_id = LV_STYLE_PROP_ID_MASK(const_prop->prop);
if(prop_id == prop) {
if(const_prop->prop & LV_STYLE_PROP_META_INHERIT)
return LV_STYLE_RES_INHERIT;
*value = (const_prop->prop & LV_STYLE_PROP_META_INITIAL) ? lv_style_prop_get_default(prop_id) : const_prop->value;
return LV_STYLE_RES_FOUND;
}
}
return LV_STYLE_RES_NOT_FOUND;
}
if(style->prop_cnt == 0) return LV_STYLE_RES_NOT_FOUND;
if(style->prop_cnt > 1) {
uint8_t * tmp = style->v_p.values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
uint16_t * props = (uint16_t *)tmp;
uint32_t i;
for(i = 0; i < style->prop_cnt; i++) {
lv_style_prop_t prop_id = LV_STYLE_PROP_ID_MASK(props[i]);
if(prop_id == prop) {
if(props[i] & LV_STYLE_PROP_META_INHERIT)
return LV_STYLE_RES_INHERIT;
if(props[i] & LV_STYLE_PROP_META_INITIAL)
*value = lv_style_prop_get_default(prop_id);
else {
lv_style_value_t * values = (lv_style_value_t *)style->v_p.values_and_props;
*value = values[i];
}
return LV_STYLE_RES_FOUND;
}
}
}
else if(LV_STYLE_PROP_ID_MASK(style->prop1) == prop) {
if(style->prop1 & LV_STYLE_PROP_META_INHERIT)
return LV_STYLE_RES_INHERIT;
*value = (style->prop1 & LV_STYLE_PROP_META_INITIAL) ? lv_style_prop_get_default(LV_STYLE_PROP_ID_MASK(
style->prop1)) : style->v_p.value1;
return LV_STYLE_RES_FOUND;
}
return LV_STYLE_RES_NOT_FOUND;
}
/** /**
* Checks if a style is empty (has no properties) * Checks if a style is empty (has no properties)
* @param style pointer to a style * @param style pointer to a style

View File

@ -70,4 +70,40 @@ void test_custom_prop_ids(void)
TEST_ASSERT_EQUAL(_lv_style_custom_prop_flag_lookup_table_size, 96); TEST_ASSERT_EQUAL(_lv_style_custom_prop_flag_lookup_table_size, 96);
} }
void test_inherit_meta(void)
{
lv_obj_t * parent = lv_obj_create(lv_scr_act());
lv_obj_t * child = lv_obj_create(parent);
lv_obj_t * grandchild = lv_label_create(child);
lv_obj_set_style_text_color(parent, lv_color_hex(0xff0000), LV_PART_MAIN);
lv_obj_set_local_style_prop_meta(child, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT, LV_PART_MAIN);
TEST_ASSERT_EQUAL_HEX(lv_color_hex(0xff0000).full, lv_obj_get_style_text_color(grandchild, LV_PART_MAIN).full);
}
void test_id_meta_overrun(void)
{
/* Test that property ID registration is blocked once the ID reaches into the meta bits */
lv_style_prop_t prop_id;
do {
prop_id = lv_style_register_prop(0);
if(prop_id != LV_STYLE_PROP_INV) {
TEST_ASSERT_EQUAL(0, prop_id & LV_STYLE_PROP_META_MASK);
}
} while(prop_id != LV_STYLE_PROP_INV);
}
void test_inherit_meta_with_lower_precedence_style(void)
{
lv_obj_t * parent = lv_obj_create(lv_scr_act());
lv_obj_t * child = lv_obj_create(parent);
lv_obj_t * grandchild = lv_label_create(child);
lv_obj_set_style_text_color(parent, lv_color_hex(0xff0000), LV_PART_MAIN);
lv_style_t style;
lv_style_init(&style);
lv_style_set_text_color(&style, lv_color_hex(0xffffff));
lv_obj_set_local_style_prop_meta(child, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT, LV_PART_MAIN);
lv_obj_add_style(child, &style, LV_PART_MAIN);
TEST_ASSERT_EQUAL_HEX(lv_color_hex(0xff0000).full, lv_obj_get_style_text_color(grandchild, LV_PART_MAIN).full);
}
#endif #endif