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:
parent
03c43d95ad
commit
9a48de0f8b
@ -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.
|
||||
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
|
||||
Objects can be composed of *parts* which may each have their own styles.
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
/*Add the props to the set if not added yet or added but with smaller weight*/
|
||||
|
@ -44,7 +44,7 @@ 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 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 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);
|
||||
@ -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_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);
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
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 value_act;
|
||||
bool inherit = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT);
|
||||
bool found = false;
|
||||
bool inheritable = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT);
|
||||
lv_style_res_t found = LV_STYLE_RES_NOT_FOUND;
|
||||
while(obj) {
|
||||
found = get_prop_core(obj, part, prop, &value_act);
|
||||
if(found) break;
|
||||
if(!inherit) break;
|
||||
if(found == LV_STYLE_RES_FOUND) break;
|
||||
if(!inheritable) break;
|
||||
|
||||
/*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;
|
||||
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);
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
if(found != LV_STYLE_RES_FOUND) {
|
||||
if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) {
|
||||
const lv_obj_class_t * cls = obj->class_p;
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -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);
|
||||
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;
|
||||
bool skip_trans = obj->skip_trans;
|
||||
uint32_t i;
|
||||
bool found;
|
||||
lv_style_res_t found;
|
||||
for(i = 0; i < obj->style_cnt; i++) {
|
||||
_lv_obj_style_t * obj_style = &obj->styles[i];
|
||||
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((obj_style->style->has_group & group) == 0) continue;
|
||||
found = lv_style_get_prop(obj_style->style, prop, &value_tmp);
|
||||
if(found) {
|
||||
if(found == LV_STYLE_RES_FOUND) {
|
||||
*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);
|
||||
|
||||
if(found) {
|
||||
if(found == LV_STYLE_RES_FOUND) {
|
||||
if(state_act == state) {
|
||||
*v = value_tmp;
|
||||
return true;
|
||||
return LV_STYLE_RES_FOUND;
|
||||
}
|
||||
if(weight < state_act) {
|
||||
weight = state_act;
|
||||
*v = value_tmp;
|
||||
}
|
||||
}
|
||||
else if(found == LV_STYLE_RES_INHERIT) {
|
||||
return LV_STYLE_RES_INHERIT;
|
||||
}
|
||||
}
|
||||
|
||||
if(weight >= 0) {
|
||||
*v = value_tmp;
|
||||
return true;
|
||||
return LV_STYLE_RES_FOUND;
|
||||
}
|
||||
else return false;
|
||||
else return LV_STYLE_RES_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
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_value_t v = {
|
||||
.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);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_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, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
|
@ -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)
|
||||
{
|
||||
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_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_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)
|
||||
{
|
||||
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_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_RECOLOR));
|
||||
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)
|
||||
{
|
||||
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_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_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)
|
||||
{
|
||||
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_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_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)
|
||||
{
|
||||
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_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_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)
|
||||
{
|
||||
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_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_RECOLOR));
|
||||
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;
|
||||
}
|
||||
|
||||
static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj,
|
||||
uint32_t part)
|
||||
static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj, uint32_t part)
|
||||
{
|
||||
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;
|
||||
@ -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_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_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_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, 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_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_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_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, 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_base_dir(struct _lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector);
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "lv_style.h"
|
||||
#include "../misc/lv_gc.h"
|
||||
#include "../misc/lv_mem.h"
|
||||
#include "lv_assert.h"
|
||||
#include "lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -22,6 +24,13 @@
|
||||
* 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
|
||||
**********************/
|
||||
@ -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 const lv_style_value_t null_style_value = { .num = 0 };
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -155,7 +165,7 @@ void lv_style_reset(lv_style_t * style)
|
||||
{
|
||||
LV_ASSERT_STYLE(style);
|
||||
|
||||
if(style->is_const) {
|
||||
if(style->prop1 == LV_STYLE_PROP_ANY) {
|
||||
LV_LOG_ERROR("Cannot reset const style");
|
||||
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) {
|
||||
_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.
|
||||
*/
|
||||
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) {
|
||||
/* Round required_size up to the nearest 32-byte value */
|
||||
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 * new_p = lv_mem_realloc(old_p, required_size * sizeof(uint8_t));
|
||||
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);
|
||||
|
||||
if(style->is_const) {
|
||||
if(style->prop1 == LV_STYLE_PROP_ANY) {
|
||||
LV_LOG_ERROR("Cannot remove prop from const style");
|
||||
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 == 1) {
|
||||
if(style->prop1 == prop) {
|
||||
if(LV_STYLE_PROP_ID_MASK(style->prop1) == prop) {
|
||||
style->prop1 = LV_STYLE_PROP_INV;
|
||||
style->prop_cnt = 0;
|
||||
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;
|
||||
uint32_t 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;
|
||||
|
||||
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)
|
||||
{
|
||||
LV_ASSERT_STYLE(style);
|
||||
|
||||
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_style_set_prop_internal(style, prop, value, lv_style_set_prop_helper);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -439,3 +394,92 @@ uint8_t _lv_style_prop_lookup_flags(lv_style_prop_t prop)
|
||||
/**********************
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,9 @@ extern "C" {
|
||||
LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE);
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
/** 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
|
||||
#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
|
||||
@ -264,9 +269,18 @@ typedef enum {
|
||||
_LV_STYLE_LAST_BUILT_IN_PROP = 111,
|
||||
_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;
|
||||
|
||||
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
|
||||
*/
|
||||
@ -305,8 +319,7 @@ typedef struct {
|
||||
const lv_style_const_prop_t * const_props;
|
||||
} v_p;
|
||||
|
||||
uint16_t prop1 : 15;
|
||||
uint16_t is_const : 1;
|
||||
uint16_t prop1;
|
||||
uint8_t has_group;
|
||||
uint8_t prop_cnt;
|
||||
} 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);
|
||||
|
||||
/**
|
||||
* 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`
|
||||
* Set a special meta state for a property in a style.
|
||||
* This function shouldn't be used directly by the user.
|
||||
* @param style pointer to style
|
||||
* @param prop the ID of a property (e.g. `LV_STYLE_BG_COLOR`)
|
||||
* @param meta the meta value to attach to the property in the 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
|
||||
@ -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)
|
||||
* 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_res_t lv_style_get_prop_inlined(const lv_style_t * style, lv_style_prop_t prop,
|
||||
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;
|
||||
}
|
||||
lv_style_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_style_value_t * value);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @param style pointer to a style
|
||||
|
@ -70,4 +70,40 @@ void test_custom_prop_ids(void)
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user