diff --git a/examples/others/observer/lv_example_observer.h b/examples/others/observer/lv_example_observer.h
index a43fca7b3a..2e03d051b2 100644
--- a/examples/others/observer/lv_example_observer.h
+++ b/examples/others/observer/lv_example_observer.h
@@ -31,6 +31,7 @@ void lv_example_observer_3(void);
void lv_example_observer_4(void);
void lv_example_observer_5(void);
void lv_example_observer_6(void);
+void lv_example_observer_7(void);
/**********************
* MACROS
diff --git a/examples/others/observer/lv_example_observer_7.c b/examples/others/observer/lv_example_observer_7.c
new file mode 100644
index 0000000000..1c278fcb4d
--- /dev/null
+++ b/examples/others/observer/lv_example_observer_7.c
@@ -0,0 +1,109 @@
+#include "../../lv_examples.h"
+#if LV_USE_OBSERVER && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
+
+/*Default style for the light theme*/
+static lv_style_t style_screen;
+
+static lv_style_t style_slider_main;
+static lv_style_t style_slider_indicator;
+static lv_style_t style_slider_knob;
+
+/*Style to make the default theme dark*/
+static lv_style_t style_screen_dark;
+static lv_style_t style_yellow;
+static lv_style_t style_bg_dark;
+
+/*Subjects for a temperature and the selected theme*/
+static lv_subject_t subject_room_temperature;
+static lv_subject_t subject_theme;
+
+/**
+ * Very simple and elegant way to create light and dark themes with subjects
+ */
+void lv_example_observer_7(void)
+{
+ /*-------------------
+ * Initialize subjects
+ *-------------------*/
+
+ lv_subject_init_int(&subject_theme, 0); /*Light theme by default*/
+ lv_subject_init_int(&subject_room_temperature, 25);
+
+ /*-------------------
+ * Initialize styles
+ *-------------------*/
+
+ /*Initialize the default light styles*/
+ lv_style_init(&style_screen);
+ lv_style_set_bg_color(&style_screen, lv_color_hex3(0xccc));
+
+ lv_style_init(&style_slider_main);
+ lv_style_set_radius(&style_slider_main, 2);
+ lv_style_set_bg_color(&style_slider_main, lv_palette_main(LV_PALETTE_RED));
+
+ lv_style_init(&style_slider_indicator);
+ lv_style_set_bg_color(&style_slider_indicator, lv_palette_main(LV_PALETTE_RED));
+
+ lv_style_init(&style_slider_knob);
+ lv_style_set_bg_color(&style_slider_knob, lv_palette_main(LV_PALETTE_RED));
+ lv_style_set_outline_color(&style_slider_knob, lv_color_hex3(0xfff));
+ lv_style_set_outline_width(&style_slider_knob, 4);
+
+ /*Initialize the styles that will overwrite color for the dark theme*/
+ lv_style_init(&style_screen_dark);
+ lv_style_set_bg_color(&style_screen_dark, lv_color_hex3(0x444));
+ lv_style_set_text_color(&style_screen_dark, lv_color_hex3(0xeee));
+
+ lv_style_init(&style_bg_dark);
+ lv_style_set_bg_color(&style_bg_dark, lv_color_hex3(0x222));
+ lv_style_set_text_color(&style_bg_dark, lv_color_hex3(0xeee));
+ lv_style_set_border_opa(&style_bg_dark, LV_OPA_30);
+
+ lv_style_init(&style_yellow);
+ lv_style_set_bg_color(&style_yellow, lv_palette_main(LV_PALETTE_YELLOW));
+ lv_style_set_outline_color(&style_yellow, lv_color_hex3(0x222));
+
+ /*----------------
+ * Create widgets
+ *----------------*/
+
+ /*Add the light them to the screen and bind the dark style only if the
+ *dark theme is selected*/
+ lv_obj_add_style(lv_screen_active(), &style_screen, 0);
+ lv_obj_bind_style(lv_screen_active(), &style_screen_dark, 0, &subject_theme, 1);
+
+ /*Create a container and add the dark style if the dark theme is selected*/
+ lv_obj_t * cont = lv_obj_create(lv_screen_active());
+ lv_obj_bind_style(cont, &style_bg_dark, 0, &subject_theme, 1);
+ lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
+ lv_obj_set_size(cont, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
+ lv_obj_align(cont, LV_ALIGN_TOP_MID, 0, 20);
+
+ lv_obj_t * label = lv_label_create(cont);
+ lv_label_bind_text(label, &subject_room_temperature, "%d °C");
+
+ /*Bind the slider to the temperature subject and some of its styles to
+ *theme subject*/
+ lv_obj_t * slider = lv_slider_create(cont);
+ lv_slider_bind_value(slider, &subject_room_temperature);
+ lv_obj_add_style(slider, &style_slider_main, 0);
+ lv_obj_add_style(slider, &style_slider_indicator, LV_PART_INDICATOR);
+ lv_obj_add_style(slider, &style_slider_knob, LV_PART_KNOB);
+ lv_obj_bind_style(slider, &style_yellow, 0, &subject_theme, 1);
+ lv_obj_bind_style(slider, &style_yellow, LV_PART_INDICATOR, &subject_theme, 1);
+ lv_obj_bind_style(slider, &style_yellow, LV_PART_KNOB, &subject_theme, 1);
+ lv_slider_set_range(slider, 20, 40);
+
+ /*Create a dropdown to select a theme.
+ *Also bind make dark if the dark theme is selected*/
+ lv_obj_t * dropdown = lv_dropdown_create(lv_screen_active());
+ lv_obj_align(dropdown, LV_ALIGN_TOP_MID, 0, 120);
+ lv_dropdown_set_options(dropdown, "Light\nDark");
+ lv_dropdown_bind_value(dropdown, &subject_theme);
+ lv_obj_bind_style(dropdown, &style_bg_dark, 0, &subject_theme, 1);
+ lv_obj_bind_style(lv_dropdown_get_list(dropdown), &style_bg_dark, 0, &subject_theme, 1);
+}
+
+
+#endif
diff --git a/src/core/lv_obj_private.h b/src/core/lv_obj_private.h
index 5b1100fb85..747e756eb3 100644
--- a/src/core/lv_obj_private.h
+++ b/src/core/lv_obj_private.h
@@ -78,7 +78,6 @@ struct _lv_obj_t {
uint16_t is_deleting : 1;
};
-
/**********************
* GLOBAL PROTOTYPES
**********************/
diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c
index afffffa151..dc947c986f 100644
--- a/src/core/lv_obj_style.c
+++ b/src/core/lv_obj_style.c
@@ -322,6 +322,37 @@ void lv_obj_refresh_style(lv_obj_t * obj, lv_style_selector_t selector, lv_style
LV_PROFILER_STYLE_END;
}
+void lv_obj_style_set_disabled(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector, bool dis)
+{
+ uint32_t i;
+ for(i = 0; i < obj->style_cnt; i++) {
+ if(obj->styles[i].style == style && obj->styles[i].selector == selector) {
+ if(dis == obj->styles[i].is_disabled) {
+ return; /*Already in the right state*/
+ }
+ obj->styles[i].is_disabled = dis;
+ full_cache_refresh(obj, lv_obj_style_get_selector_part(selector));
+ lv_obj_refresh_style(obj, selector, LV_STYLE_PROP_ANY);
+ return;
+ }
+ }
+ LV_LOG_WARN("%p style was not found on %p widget with %6x selector", (void *)style, (void *)obj, selector);
+}
+
+bool lv_obj_style_get_disabled(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector)
+{
+ uint32_t i;
+ for(i = 0; i < obj->style_cnt; i++) {
+ if(obj->styles[i].style == style && obj->styles[i].selector == selector) {
+ return obj->styles[i].is_disabled;
+ }
+ }
+
+ LV_LOG_WARN("%p style was not found on %p widget with %6x selector", (void *)style, (void *)obj, selector);
+ return false;
+}
+
+
void lv_obj_enable_style_refresh(bool en)
{
style_refr = en;
@@ -773,6 +804,7 @@ static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_style_selector_t se
lv_obj_style_t * obj_style = &obj->styles[i];
if(obj_style->is_trans == false) break;
if(skip_trans) continue;
+ if(obj_style->is_disabled) continue;
lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
@@ -786,6 +818,7 @@ static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_style_selector_t se
for(; i < obj->style_cnt; i++) {
if((obj->styles[i].style->has_group & group) == 0) continue;
+ if(obj->styles[i].is_disabled) continue;
lv_obj_style_t * obj_style = &obj->styles[i];
lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
if(part_act != part) continue;
@@ -1045,6 +1078,7 @@ static void full_cache_refresh(lv_obj_t * obj, lv_part_t part)
obj->style_main_prop_is_set = 0;
for(i = 0; i < obj->style_cnt; i++) {
if(lv_obj_style_get_selector_part(obj->styles[i].selector) != LV_PART_MAIN) continue;
+ if(obj->styles[i].is_disabled) continue;
lv_style_t * style = (lv_style_t *)obj->styles[i].style;
uint32_t j;
if(lv_style_is_const(style)) {
@@ -1065,6 +1099,8 @@ static void full_cache_refresh(lv_obj_t * obj, lv_part_t part)
obj->style_other_prop_is_set = 0;
for(i = 0; i < obj->style_cnt; i++) {
if(lv_obj_style_get_selector_part(obj->styles[i].selector) == LV_PART_MAIN) continue;
+ if(obj->styles[i].is_disabled) continue;
+
lv_style_t * style = (lv_style_t *)obj->styles[i].style;
uint32_t j;
if(lv_style_is_const(style)) {
diff --git a/src/core/lv_obj_style.h b/src/core/lv_obj_style.h
index 6db661e367..95e0458540 100644
--- a/src/core/lv_obj_style.h
+++ b/src/core/lv_obj_style.h
@@ -117,6 +117,24 @@ void lv_obj_report_style_change(lv_style_t * style);
*/
void lv_obj_refresh_style(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop);
+/**
+ * Temporary disable a style for a selector. It will look like is the style wasn't added
+ * @param obj pointer to an object
+ * @param style pointer to a style
+ * @param selector the selector of a style (e.g. LV_STATE_PRESSED | LV_PART_KNOB)
+ * @param dis true: disable the style, false: enable the style
+ */
+void lv_obj_style_set_disabled(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector, bool dis);
+
+/**
+ * Get if a given style is disabled on an object.
+ * @param obj pointer to an object
+ * @param style pointer to a style
+ * @param selector the selector of a style (e.g. LV_STATE_PRESSED | LV_PART_KNOB)
+ * @return true: disable the style, false: enable the style
+ */
+bool lv_obj_style_get_disabled(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector);
+
/**
* Enable or disable automatic style refreshing when a new style is added/removed to/from an object
* or any other style change happens.
diff --git a/src/core/lv_obj_style_private.h b/src/core/lv_obj_style_private.h
index e6be1279e5..97bb607f71 100644
--- a/src/core/lv_obj_style_private.h
+++ b/src/core/lv_obj_style_private.h
@@ -29,6 +29,7 @@ struct _lv_obj_style_t {
uint32_t selector : 24;
uint32_t is_local : 1;
uint32_t is_trans : 1;
+ uint32_t is_disabled : 1;
};
struct _lv_obj_style_transition_dsc_t {
diff --git a/src/others/observer/lv_observer.c b/src/others/observer/lv_observer.c
index 15a60a5a08..c61d0ff55b 100644
--- a/src/others/observer/lv_observer.c
+++ b/src/others/observer/lv_observer.c
@@ -34,6 +34,12 @@ typedef struct {
flag_cond_t cond : 3;
} flag_and_cond_t;
+typedef struct {
+ const lv_style_t * style;
+ lv_style_selector_t selector;
+ int32_t value;
+} bind_style_t;
+
typedef struct {
lv_subject_t * subject;
int32_t value;
@@ -64,6 +70,8 @@ static void unsubscribe_on_delete_cb(lv_event_t * e);
static void group_notify_cb(lv_observer_t * observer, lv_subject_t * subject);
static lv_observer_t * bind_to_bitfield(lv_subject_t * subject, lv_obj_t * obj, lv_observer_cb_t cb, uint32_t flag,
int32_t ref_value, bool inv, flag_cond_t cond);
+
+static void bind_style_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
static void obj_flag_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
static void obj_state_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
static void obj_value_changed_event_cb(lv_event_t * e);
@@ -538,6 +546,34 @@ void lv_obj_add_subject_set_string_event(lv_obj_t * obj, lv_subject_t * subject,
lv_obj_add_event_cb(obj, subject_set_string_free_user_data_event_cb, LV_EVENT_DELETE, user_data);
}
+lv_observer_t * lv_obj_bind_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector,
+ lv_subject_t * subject, int32_t ref_value)
+{
+ LV_ASSERT_NULL(subject);
+ LV_ASSERT_NULL(obj);
+
+ if(subject->type != LV_SUBJECT_TYPE_INT) {
+ LV_LOG_WARN("Incompatible subject type: %d", subject->type);
+ return NULL;
+ }
+
+ lv_obj_add_style(obj, style, selector);
+
+ bind_style_t * p = lv_malloc(sizeof(bind_style_t));
+ if(p == NULL) {
+ LV_LOG_WARN("Out of memory");
+ return NULL;
+ }
+
+ p->style = style;
+ p->selector = selector;
+ p->value = ref_value;
+
+ lv_observer_t * observable = lv_subject_add_observer_obj(subject, bind_style_observer_cb, obj, p);
+ observable->auto_free_user_data = 1;
+ return observable;
+}
+
lv_observer_t * lv_obj_bind_flag_if_eq(lv_obj_t * obj, lv_subject_t * subject, lv_obj_flag_t flag, int32_t ref_value)
{
lv_observer_t * observable = bind_to_bitfield(subject, obj, obj_flag_observer_cb, flag, ref_value, false, FLAG_COND_EQ);
@@ -816,6 +852,15 @@ static lv_observer_t * bind_to_bitfield(lv_subject_t * subject, lv_obj_t * obj,
return observable;
}
+static void bind_style_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
+{
+ bind_style_t * p = observer->user_data;
+
+ int32_t current_v = lv_subject_get_int(subject);
+ bool dis = current_v != p->value;
+ lv_obj_style_set_disabled(observer->target, p->style, p->selector, dis);
+}
+
static void obj_flag_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
{
flag_and_cond_t * p = observer->user_data;
diff --git a/src/others/observer/lv_observer.h b/src/others/observer/lv_observer.h
index f3ec9514fb..9545fb5c65 100644
--- a/src/others/observer/lv_observer.h
+++ b/src/others/observer/lv_observer.h
@@ -337,6 +337,18 @@ void lv_obj_add_subject_set_int_event(lv_obj_t * obj, lv_subject_t * subject, lv
void lv_obj_add_subject_set_string_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger,
const char * value);
+/**
+ * Disable a style if a subject's value is not equal to a reference value
+ * @param obj pointer to Widget
+ * @param style pointer to a style
+ * @param selector pointer to a selector
+ * @param subject pointer to Subject
+ * @param ref_value reference value to compare Subject's value with
+ * @return pointer to newly-created Observer
+ */
+lv_observer_t * lv_obj_bind_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector,
+ lv_subject_t * subject, int32_t ref_value);
+
/**
* Set Widget's flag(s) if an integer Subject's value is equal to a reference value, clear flag otherwise.
* @param obj pointer to Widget
diff --git a/src/others/xml/lv_xml.c b/src/others/xml/lv_xml.c
index 789f41f20b..2dfa748340 100644
--- a/src/others/xml/lv_xml.c
+++ b/src/others/xml/lv_xml.c
@@ -124,6 +124,7 @@ void lv_xml_init(void)
lv_xml_widget_register("lv_obj-screen_create_event", lv_obj_xml_screen_create_event_create,
lv_obj_xml_screen_create_event_apply);
+ lv_xml_widget_register("lv_obj-bind_style", lv_obj_xml_bind_style_create, lv_obj_xml_bind_style_apply);
lv_xml_widget_register("lv_obj-bind_flag_if_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
lv_xml_widget_register("lv_obj-bind_flag_if_not_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
lv_xml_widget_register("lv_obj-bind_flag_if_gt", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
diff --git a/src/others/xml/parsers/lv_xml_obj_parser.c b/src/others/xml/parsers/lv_xml_obj_parser.c
index 81191ef9e4..92c468163f 100644
--- a/src/others/xml/parsers/lv_xml_obj_parser.c
+++ b/src/others/xml/parsers/lv_xml_obj_parser.c
@@ -164,8 +164,8 @@ void lv_obj_xml_style_apply(lv_xml_parser_state_t * state, const char ** attrs)
{
const char * name = lv_xml_get_value_of(attrs, "name");
if(name == NULL) {
- /*Silently ignore this issue, as it might valid the name is not resolved during
- *parameter replacement if there is no default value.*/
+ /*Silently ignore this issue.
+ *The name set to NULL if there there was no default value when resolving params*/
return;
}
lv_xml_style_t * xml_style = lv_xml_get_style_by_name(&state->scope, name);
@@ -370,6 +370,54 @@ void lv_obj_xml_subject_increment_apply(lv_xml_parser_state_t * state, const cha
lv_obj_add_subject_increment_event(item, subject, trigger, step, min_v, max_v);
}
+void * lv_obj_xml_bind_style_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+ LV_UNUSED(attrs);
+ void * item = lv_xml_state_get_parent(state);
+ return item;
+}
+
+void lv_obj_xml_bind_style_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+ const char * name = lv_xml_get_value_of(attrs, "name");
+ if(name == NULL) {
+ /*Silently ignore this issue.
+ *The name set to NULL if there there was no default value when resolving params*/
+ return;
+ }
+ lv_xml_style_t * xml_style = lv_xml_get_style_by_name(&state->scope, name);
+ if(xml_style == NULL) {
+ LV_LOG_WARN("`%s` style is not found", name);
+ return;
+ }
+ const char * subject_str = lv_xml_get_value_of(attrs, "subject");
+
+ if(subject_str == NULL) {
+ LV_LOG_WARN("`subject` is missing in lv_obj bind_style");
+ return;
+ }
+
+ lv_subject_t * subject = lv_xml_get_subject(&state->scope, subject_str);
+ if(subject == NULL) {
+ LV_LOG_WARN("Subject `%s` doesn't exist in lv_obj bind_style", subject_str);
+ return;
+ }
+
+ const char * ref_value_str = lv_xml_get_value_of(attrs, "ref_value");
+ if(ref_value_str == NULL) {
+ LV_LOG_WARN("`ref_value` is missing in lv_obj bind_style");
+ return;
+ }
+
+ int32_t ref_value = lv_xml_atoi(ref_value_str);
+
+ const char * selector_str = lv_xml_get_value_of(attrs, "selector");
+ lv_style_selector_t selector = get_selector(selector_str);
+
+ void * item = lv_xml_state_get_parent(state);
+ lv_obj_bind_style(item, &xml_style->style, selector, subject, ref_value);
+}
+
void * lv_obj_xml_bind_flag_create(lv_xml_parser_state_t * state, const char ** attrs)
{
LV_UNUSED(attrs);
diff --git a/src/others/xml/parsers/lv_xml_obj_parser.h b/src/others/xml/parsers/lv_xml_obj_parser.h
index 28b462c2ed..8dd0eea570 100644
--- a/src/others/xml/parsers/lv_xml_obj_parser.h
+++ b/src/others/xml/parsers/lv_xml_obj_parser.h
@@ -45,6 +45,9 @@ void lv_obj_xml_subject_set_apply(lv_xml_parser_state_t * state, const char ** a
void * lv_obj_xml_subject_increment_create(lv_xml_parser_state_t * state, const char ** attrs);
void lv_obj_xml_subject_increment_apply(lv_xml_parser_state_t * state, const char ** attrs);
+void * lv_obj_xml_bind_style_create(lv_xml_parser_state_t * state, const char ** attrs);
+void lv_obj_xml_bind_style_apply(lv_xml_parser_state_t * state, const char ** attrs);
+
void * lv_obj_xml_bind_flag_create(lv_xml_parser_state_t * state, const char ** attrs);
void lv_obj_xml_bind_flag_apply(lv_xml_parser_state_t * state, const char ** attrs);
diff --git a/tests/src/test_cases/xml/test_xml_style.c b/tests/src/test_cases/xml/test_xml_style.c
index 87ce12cd25..3a300d472c 100644
--- a/tests/src/test_cases/xml/test_xml_style.c
+++ b/tests/src/test_cases/xml/test_xml_style.c
@@ -182,4 +182,30 @@ void test_xml_style_remove(void)
lv_xml_component_unregister("comp1");
}
+void test_xml_style_binding(void)
+{
+ const char * comp1_xml = {
+ ""
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ ""
+ };
+
+ lv_xml_component_register_from_data("comp1", comp1_xml);
+
+ lv_obj_t * obj = lv_xml_create(lv_screen_active(), "comp1", NULL);
+
+ TEST_ASSERT_NOT_EQUAL_COLOR(lv_color_hex(0xff0000), lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR));
+
+ lv_subject_t * subject = lv_xml_get_subject(lv_xml_component_get_scope("comp1"), "subject1");
+ lv_subject_set_int(subject, 5);
+ TEST_ASSERT_EQUAL_COLOR(lv_color_hex(0xff0000), lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR));
+}
#endif
diff --git a/xmls/lv_obj.xml b/xmls/lv_obj.xml
index d3a294f80f..d62010bef6 100644
--- a/xmls/lv_obj.xml
+++ b/xmls/lv_obj.xml
@@ -51,6 +51,13 @@ Example
+
+
+
+
+
+
+