mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-29 22:56:58 +08:00
feat(style): add lv_obj_bind_style_prop (#9173)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Liam Howatt <30486941+liamHowatt@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
483cb38f60
commit
ebc48b5c56
@@ -30,6 +30,22 @@ To set a local property use functions like
|
|||||||
lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED);
|
lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED);
|
||||||
|
|
||||||
|
|
||||||
|
Binding Local Styles
|
||||||
|
********************
|
||||||
|
|
||||||
|
By using :cpp:expr:`lv_obj_bind_style_prop`, it's possible to bind a style property
|
||||||
|
to a :ref:`Subject <observer_overview>`\ 's value.
|
||||||
|
|
||||||
|
It's a great way to map every slider's color or opacity to a subject and control it
|
||||||
|
externally.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
lv_obj_bind_style_prop(slider1, LV_STYLE_BG_OPA, LV_PART_MAIN, &subject_bg_opa);
|
||||||
|
lv_obj_bind_style_prop(slider1, LV_STYLE_BG_COLOR, LV_PART_INDICATOR, &subject_bg_color);
|
||||||
|
|
||||||
|
|
||||||
.. Hyperlinks
|
.. Hyperlinks
|
||||||
|
|
||||||
|
|||||||
@@ -160,3 +160,25 @@ notified. There are 3 options to do this:
|
|||||||
is ``NULL`` all Widgets will be notified about a style change.
|
is ``NULL`` all Widgets will be notified about a style change.
|
||||||
|
|
||||||
|
|
||||||
|
Binding Styles
|
||||||
|
**************
|
||||||
|
|
||||||
|
By using :cpp:expr:`lv_obj_bind_style`, it's possible to add a style to a Widget
|
||||||
|
but enable it only if a :ref:`Subject <observer_overview>`'s value is equal to
|
||||||
|
a reference value.
|
||||||
|
|
||||||
|
It's a great way to implement a light/dark theme switch by normally adding the styles
|
||||||
|
for the light theme, and binding only a few styles for the dark theme to change
|
||||||
|
only a few colors if, e.g., a ``dark_theme`` subject is ``1``.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
/*Style for the light theme*/
|
||||||
|
lv_obj_add_style(btn, &style_btn, LV_PART_MAIN);
|
||||||
|
lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED);
|
||||||
|
|
||||||
|
/*Style for the dark theme changing only a few colors*/
|
||||||
|
lv_obj_bind_style(btn, &style_btn_dark, LV_PART_MAIN, &dark_theme_subject, 1);
|
||||||
|
lv_obj_bind_style(btn, &style_btn_pressed_dark, LV_STATE_PRESSED, &dark_theme_subject, 1);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Styles can be referenced like this in the ``<view>``:
|
|||||||
|
|
||||||
As shown in the example, parts and states can be set using ``selector``.
|
As shown in the example, parts and states can be set using ``selector``.
|
||||||
|
|
||||||
Style binding
|
Style Binding
|
||||||
*************
|
*************
|
||||||
|
|
||||||
Instead of directly adding styles to the UI elements it's also possible to add them conditionally
|
Instead of directly adding styles to the UI elements it's also possible to add them conditionally
|
||||||
@@ -78,6 +78,23 @@ Local styles can be used directly, for example:
|
|||||||
|
|
||||||
Selectors are not supported for local style properties yet.
|
Selectors are not supported for local style properties yet.
|
||||||
|
|
||||||
|
|
||||||
|
Local Style Binding
|
||||||
|
*******************
|
||||||
|
|
||||||
|
Instead of setting local style properties directly, it's also possible to bind style properties
|
||||||
|
to :ref:`Subject <observer_how_to_use>` values:
|
||||||
|
|
||||||
|
.. code-block:: xml
|
||||||
|
|
||||||
|
<component>
|
||||||
|
<view extends="lv_slider">
|
||||||
|
<bind_style_prop prop="bg_opa" selector="knob|pressed" subject="slider_knob_opa" />
|
||||||
|
</view>
|
||||||
|
</component>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Gradients
|
Gradients
|
||||||
*********
|
*********
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ The following simple built-in types are supported:
|
|||||||
|
|
||||||
:scale_1/256: Scale/Zoom, where 256 means 100%, 128 means 50%, 512 means 200% etc.
|
:scale_1/256: Scale/Zoom, where 256 means 100%, 128 means 50%, 512 means 200% etc.
|
||||||
|
|
||||||
|
:style_prop: A style property, for example ``"bg_opa"`` meaning :cpp:enumerator:`LV_STYLE_BG_OPA`.
|
||||||
|
|
||||||
Name-based types
|
Name-based types
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include "../misc/lv_color.h"
|
#include "../misc/lv_color.h"
|
||||||
#include "../stdlib/lv_string.h"
|
#include "../stdlib/lv_string.h"
|
||||||
#include "../core/lv_global.h"
|
#include "../core/lv_global.h"
|
||||||
|
#include "lv_observer_private.h"
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
* DEFINES
|
* DEFINES
|
||||||
*********************/
|
*********************/
|
||||||
@@ -36,6 +38,17 @@ typedef struct {
|
|||||||
lv_style_value_t end_value;
|
lv_style_value_t end_value;
|
||||||
} trans_t;
|
} trans_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const lv_style_t * style;
|
||||||
|
lv_style_selector_t selector;
|
||||||
|
int32_t value;
|
||||||
|
} bind_style_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lv_style_prop_t prop;
|
||||||
|
lv_style_selector_t selector;
|
||||||
|
} bind_style_prop_t;
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* GLOBAL PROTOTYPES
|
* GLOBAL PROTOTYPES
|
||||||
**********************/
|
**********************/
|
||||||
@@ -60,6 +73,10 @@ static void fade_in_anim_completed(lv_anim_t * a);
|
|||||||
static bool style_has_flag(const lv_style_t * style, uint32_t flag);
|
static bool style_has_flag(const lv_style_t * style, uint32_t flag);
|
||||||
static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop,
|
static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop,
|
||||||
lv_style_value_t * value_act);
|
lv_style_value_t * value_act);
|
||||||
|
#if LV_USE_OBSERVER
|
||||||
|
static void bind_style_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
|
||||||
|
static void bind_style_prop_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC VARIABLES
|
* STATIC VARIABLES
|
||||||
@@ -702,6 +719,68 @@ lv_color32_t lv_obj_get_style_recolor_recursive(const lv_obj_t * obj, lv_part_t
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_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)
|
||||||
|
{
|
||||||
|
LV_ASSERT_NULL(subject);
|
||||||
|
LV_ASSERT_NULL(obj);
|
||||||
|
|
||||||
|
if(subject->type != LV_SUBJECT_TYPE_INT) {
|
||||||
|
LV_LOG_WARN("Subject type must be `int` (was %d)", subject->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_add_style(obj, style, selector);
|
||||||
|
|
||||||
|
bind_style_t * p = lv_malloc(sizeof(bind_style_t));
|
||||||
|
LV_ASSERT_MALLOC(p);
|
||||||
|
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_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector,
|
||||||
|
lv_subject_t * subject)
|
||||||
|
{
|
||||||
|
LV_ASSERT_NULL(subject);
|
||||||
|
LV_ASSERT_NULL(obj);
|
||||||
|
|
||||||
|
if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_COLOR &&
|
||||||
|
subject->type != LV_SUBJECT_TYPE_POINTER) {
|
||||||
|
LV_LOG_WARN("Subject type must be `int`, `color`, or `pointer` (was %"LV_PRIu32")", subject->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_style_prop_t * p = lv_malloc(sizeof(bind_style_prop_t));
|
||||||
|
LV_ASSERT_MALLOC(p);
|
||||||
|
if(p == NULL) {
|
||||||
|
LV_LOG_WARN("Out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->prop = prop;
|
||||||
|
p->selector = selector;
|
||||||
|
|
||||||
|
lv_observer_t * observable = lv_subject_add_observer_obj(subject, bind_style_prop_observer_cb, obj, p);
|
||||||
|
observable->auto_free_user_data = 1;
|
||||||
|
return observable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*LV_USE_OBSERVER*/
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC FUNCTIONS
|
* STATIC FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
@@ -1217,3 +1296,32 @@ static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_sel
|
|||||||
|
|
||||||
return LV_STYLE_RES_NOT_FOUND;
|
return LV_STYLE_RES_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_OBSERVER
|
||||||
|
|
||||||
|
static void bind_style_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||||
|
{
|
||||||
|
bind_style_t * p = observer->user_data;
|
||||||
|
|
||||||
|
int32_t v = lv_subject_get_int(subject);
|
||||||
|
bool dis = (v != p->value);
|
||||||
|
lv_obj_style_set_disabled(observer->target, p->style, p->selector, dis);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bind_style_prop_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||||
|
{
|
||||||
|
bind_style_prop_t * p = observer->user_data;
|
||||||
|
|
||||||
|
lv_style_value_t style_v;
|
||||||
|
if(subject->type == LV_SUBJECT_TYPE_INT) style_v.num = lv_subject_get_int(subject);
|
||||||
|
else if(subject->type == LV_SUBJECT_TYPE_COLOR) style_v.color = lv_subject_get_color(subject);
|
||||||
|
else if(subject->type == LV_SUBJECT_TYPE_POINTER) style_v.ptr = lv_subject_get_pointer(subject);
|
||||||
|
else {
|
||||||
|
LV_LOG_WARN("Not supported subject type (%"LV_PRIu32")", subject->type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_set_local_style_prop(observer->target, p->prop, style_v, p->selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*LV_USE_OBSERVER*/
|
||||||
|
|||||||
@@ -394,6 +394,32 @@ lv_color32_t lv_obj_style_apply_recolor(const lv_obj_t * obj, lv_part_t part, lv
|
|||||||
*/
|
*/
|
||||||
lv_color32_t lv_obj_get_style_recolor_recursive(const lv_obj_t * obj, lv_part_t part);
|
lv_color32_t lv_obj_get_style_recolor_recursive(const lv_obj_t * obj, lv_part_t part);
|
||||||
|
|
||||||
|
#if LV_USE_OBSERVER
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect a subject's value to a style property of a widget.
|
||||||
|
* @param obj pointer to a Widget
|
||||||
|
* @param prop a style property
|
||||||
|
* @param selector a selector for which the property should be added, e.g. `LV_PART_KNOB | LV_STATE_PRESSED`
|
||||||
|
* @param subject pointer a Subject to which value the property should be bound
|
||||||
|
* @return pointer to newly-created Observer
|
||||||
|
*/
|
||||||
|
lv_observer_t * lv_obj_bind_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector,
|
||||||
|
lv_subject_t * subject);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
**********************/
|
**********************/
|
||||||
|
|||||||
@@ -38,12 +38,6 @@ typedef struct {
|
|||||||
flag_cond_t cond : 3;
|
flag_cond_t cond : 3;
|
||||||
} flag_and_cond_t;
|
} flag_and_cond_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const lv_style_t * style;
|
|
||||||
lv_style_selector_t selector;
|
|
||||||
int32_t value;
|
|
||||||
} bind_style_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
lv_subject_t * subject;
|
lv_subject_t * subject;
|
||||||
int32_t value;
|
int32_t value;
|
||||||
@@ -77,7 +71,6 @@ 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,
|
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);
|
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_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_state_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
|
||||||
static void obj_value_changed_event_cb(lv_event_t * e);
|
static void obj_value_changed_event_cb(lv_event_t * e);
|
||||||
@@ -734,34 +727,6 @@ 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_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("Subject type must be `int` (was %d)", subject->type);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv_obj_add_style(obj, style, selector);
|
|
||||||
|
|
||||||
bind_style_t * p = lv_malloc(sizeof(bind_style_t));
|
|
||||||
LV_ASSERT_MALLOC(p);
|
|
||||||
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 * lv_obj_bind_flag_if_eq(lv_obj_t * obj, lv_subject_t * subject, lv_obj_flag_t flag, int32_t ref_value)
|
||||||
{
|
{
|
||||||
@@ -1002,15 +967,6 @@ static lv_observer_t * bind_to_bitfield(lv_subject_t * subject, lv_obj_t * obj,
|
|||||||
return observable;
|
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)
|
static void obj_flag_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||||
{
|
{
|
||||||
flag_and_cond_t * p = observer->user_data;
|
flag_and_cond_t * p = observer->user_data;
|
||||||
|
|||||||
+3
-14
@@ -15,6 +15,7 @@ extern "C" {
|
|||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
#include "lv_obj.h"
|
#include "lv_obj.h"
|
||||||
|
|
||||||
#if LV_USE_OBSERVER
|
#if LV_USE_OBSERVER
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
@@ -54,7 +55,7 @@ typedef union {
|
|||||||
/**
|
/**
|
||||||
* The Subject (an observable value)
|
* The Subject (an observable value)
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
struct _lv_subject_t {
|
||||||
lv_ll_t subs_ll; /**< Subscribers */
|
lv_ll_t subs_ll; /**< Subscribers */
|
||||||
lv_subject_value_t value; /**< Current value */
|
lv_subject_value_t value; /**< Current value */
|
||||||
lv_subject_value_t prev_value; /**< Previous value */
|
lv_subject_value_t prev_value; /**< Previous value */
|
||||||
@@ -65,7 +66,7 @@ typedef struct {
|
|||||||
uint32_t size : 24; /**< String buffer size or group length */
|
uint32_t size : 24; /**< String buffer size or group length */
|
||||||
uint32_t notify_restart_query : 1; /**< If an Observer was deleted during notification,
|
uint32_t notify_restart_query : 1; /**< If an Observer was deleted during notification,
|
||||||
* start notifying from the beginning. */
|
* start notifying from the beginning. */
|
||||||
} lv_subject_t;
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called to notify Observer that Subject's value has changed
|
* Callback called to notify Observer that Subject's value has changed
|
||||||
@@ -449,18 +450,6 @@ void lv_obj_add_subject_set_float_event(lv_obj_t * obj, lv_subject_t * subject,
|
|||||||
void lv_obj_add_subject_set_string_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger,
|
void lv_obj_add_subject_set_string_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger,
|
||||||
const char * value);
|
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.
|
* 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
|
* @param obj pointer to Widget
|
||||||
|
|||||||
+1
-1
@@ -282,8 +282,8 @@ typedef struct _lv_gltf_t lv_gltf_t;
|
|||||||
|
|
||||||
typedef struct _lv_gltf_model_t lv_gltf_model_t;
|
typedef struct _lv_gltf_model_t lv_gltf_model_t;
|
||||||
|
|
||||||
|
typedef struct _lv_subject_t lv_subject_t;
|
||||||
typedef struct _lv_observer_t lv_observer_t;
|
typedef struct _lv_observer_t lv_observer_t;
|
||||||
|
|
||||||
typedef struct _lv_subject_increment_dsc_t lv_subject_increment_dsc_t;
|
typedef struct _lv_subject_increment_dsc_t lv_subject_increment_dsc_t;
|
||||||
|
|
||||||
typedef struct _lv_monkey_config_t lv_monkey_config_t;
|
typedef struct _lv_monkey_config_t lv_monkey_config_t;
|
||||||
|
|||||||
@@ -237,6 +237,7 @@ void lv_xml_init(void)
|
|||||||
lv_obj_xml_play_timeline_event_apply);
|
lv_obj_xml_play_timeline_event_apply);
|
||||||
|
|
||||||
lv_xml_register_widget("lv_obj-bind_style", lv_obj_xml_bind_style_create, lv_obj_xml_bind_style_apply);
|
lv_xml_register_widget("lv_obj-bind_style", lv_obj_xml_bind_style_create, lv_obj_xml_bind_style_apply);
|
||||||
|
lv_xml_register_widget("lv_obj-bind_style_prop", lv_obj_xml_bind_style_prop_create, lv_obj_xml_bind_style_prop_apply);
|
||||||
lv_xml_register_widget("lv_obj-bind_flag_if_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
lv_xml_register_widget("lv_obj-bind_flag_if_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
||||||
lv_xml_register_widget("lv_obj-bind_flag_if_not_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
lv_xml_register_widget("lv_obj-bind_flag_if_not_eq", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
||||||
lv_xml_register_widget("lv_obj-bind_flag_if_gt", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
lv_xml_register_widget("lv_obj-bind_flag_if_gt", lv_obj_xml_bind_flag_create, lv_obj_xml_bind_flag_apply);
|
||||||
|
|||||||
@@ -492,6 +492,43 @@ void lv_obj_xml_bind_style_apply(lv_xml_parser_state_t * state, const char ** at
|
|||||||
lv_obj_bind_style(item, &xml_style->style, selector, subject, ref_value);
|
lv_obj_bind_style(item, &xml_style->style, selector, subject, ref_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * lv_obj_xml_bind_style_prop_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_prop_apply(lv_xml_parser_state_t * state, const char ** attrs)
|
||||||
|
{
|
||||||
|
const char * prop_str = lv_xml_get_value_of(attrs, "prop");
|
||||||
|
if(prop_str == NULL) {
|
||||||
|
LV_LOG_WARN("`prop` is missing in lv_obj bind_style_prop");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lv_style_prop_t prop = lv_xml_style_prop_to_enum(prop_str);
|
||||||
|
|
||||||
|
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_prop");
|
||||||
|
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_prop", subject_str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * selector_str = lv_xml_get_value_of(attrs, "selector");
|
||||||
|
lv_style_selector_t selector = lv_xml_style_selector_text_to_enum(selector_str);
|
||||||
|
|
||||||
|
void * item = lv_xml_state_get_parent(state);
|
||||||
|
lv_obj_bind_style_prop(item, prop, selector, subject);
|
||||||
|
}
|
||||||
|
|
||||||
void * lv_obj_xml_bind_flag_create(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)
|
||||||
{
|
{
|
||||||
LV_UNUSED(attrs);
|
LV_UNUSED(attrs);
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ void lv_obj_xml_subject_increment_apply(lv_xml_parser_state_t * state, const cha
|
|||||||
void * lv_obj_xml_bind_style_create(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_style_apply(lv_xml_parser_state_t * state, const char ** attrs);
|
||||||
|
|
||||||
|
void * lv_obj_xml_bind_style_prop_create(lv_xml_parser_state_t * state, const char ** attrs);
|
||||||
|
void lv_obj_xml_bind_style_prop_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_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);
|
void lv_obj_xml_bind_flag_apply(lv_xml_parser_state_t * state, const char ** attrs);
|
||||||
|
|
||||||
|
|||||||
@@ -208,4 +208,40 @@ void test_xml_style_binding(void)
|
|||||||
lv_subject_set_int(subject, 5);
|
lv_subject_set_int(subject, 5);
|
||||||
TEST_ASSERT_EQUAL_COLOR(lv_color_hex(0xff0000), lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR));
|
TEST_ASSERT_EQUAL_COLOR(lv_color_hex(0xff0000), lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_xml_style_prop_binding(void)
|
||||||
|
{
|
||||||
|
const char * comp1_xml = {
|
||||||
|
"<component>"
|
||||||
|
" <subjects>"
|
||||||
|
" <int name=\"subject1\" value=\"128\"/>"
|
||||||
|
" <color name=\"subject2\" value=\"0xff0000\"/>"
|
||||||
|
" </subjects>"
|
||||||
|
" <view>"
|
||||||
|
" <bind_style_prop prop=\"bg_opa\" selector=\"scrollbar|checked\" subject=\"subject1\"/>"
|
||||||
|
" <bind_style_prop prop=\"bg_color\" selector=\"scrollbar|checked\" subject=\"subject2\"/>"
|
||||||
|
" </view>"
|
||||||
|
"</component>"
|
||||||
|
};
|
||||||
|
|
||||||
|
lv_xml_register_component_from_data("comp1", comp1_xml);
|
||||||
|
|
||||||
|
lv_obj_t * obj = lv_xml_create(lv_screen_active(), "comp1", NULL);
|
||||||
|
lv_obj_add_state(obj, LV_STATE_CHECKED);
|
||||||
|
lv_test_wait(1000); /*Wait for transitions*/
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(128, lv_obj_get_style_bg_opa(obj, LV_PART_SCROLLBAR | LV_STATE_CHECKED));
|
||||||
|
TEST_ASSERT_EQUAL_COLOR(lv_color_hex(0xff0000), lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR));
|
||||||
|
|
||||||
|
lv_subject_t * subject1 = lv_xml_get_subject(lv_xml_component_get_scope("comp1"), "subject1");
|
||||||
|
lv_subject_t * subject2 = lv_xml_get_subject(lv_xml_component_get_scope("comp1"), "subject2");
|
||||||
|
|
||||||
|
lv_subject_set_int(subject1, 20);
|
||||||
|
lv_subject_set_color(subject2, lv_color_hex(0xff00ff));
|
||||||
|
lv_test_wait(1000); /*Wait for transitions*/
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(20, lv_obj_get_style_bg_opa(obj, LV_PART_SCROLLBAR | LV_STATE_CHECKED));
|
||||||
|
TEST_ASSERT_EQUAL_COLOR(lv_color_hex(0xff00ff), lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR | LV_STATE_CHECKED));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ Example
|
|||||||
<arg name="ref_value" type="int" help="Value that activates the style"/>
|
<arg name="ref_value" type="int" help="Value that activates the style"/>
|
||||||
</element>
|
</element>
|
||||||
|
|
||||||
|
<element name="bind_style_prop" access="custom" type="void" help="Bind a style to a subject value">
|
||||||
|
<arg name="prop" type="style_prop" help="Name of a style property"/>
|
||||||
|
<arg name="selector" type="selector+" default="0" help="Selector (part and/or state)"/>
|
||||||
|
<arg name="subject" type="subject" help="Subject to bind"/>
|
||||||
|
</element>
|
||||||
|
|
||||||
<element name="event_cb" access="add" type="void" help="Attach an event callback">
|
<element name="event_cb" access="add" type="void" help="Attach an event callback">
|
||||||
<arg name="callback" type="event_cb" help="Callback function"/>
|
<arg name="callback" type="event_cb" help="Callback function"/>
|
||||||
<arg name="trigger" type="lv_event" default="clicked" help="Event to trigger callback"/>
|
<arg name="trigger" type="lv_event" default="clicked" help="Event to trigger callback"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user