mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-30 23:51:54 +08:00
feat(observer): add float subject type (#8388)
This commit is contained in:
committed by
GitHub
parent
1ef1d23342
commit
ae0a3bc822
@@ -17,7 +17,7 @@ This implementation consists of:
|
|||||||
|
|
||||||
:Subjects: (in global memory or heap) are "logic packages", each containing the
|
:Subjects: (in global memory or heap) are "logic packages", each containing the
|
||||||
value being "observed" and its type (integer (``int32_t``), a string, a
|
value being "observed" and its type (integer (``int32_t``), a string, a
|
||||||
pointer, an :cpp:type:`lv_color_t`, or a group);
|
pointer, an :cpp:type:`lv_color_t`, a :cpp_type:`float`, or a group);
|
||||||
|
|
||||||
:Observers: (zero or more per Subject, always dynamically-allocated) are always
|
:Observers: (zero or more per Subject, always dynamically-allocated) are always
|
||||||
attached to exactly one Subject, and provide user-defined notifications
|
attached to exactly one Subject, and provide user-defined notifications
|
||||||
@@ -114,6 +114,7 @@ To initialize a Subject use ``lv_subject_init_<type>(&subject, params, init_valu
|
|||||||
The following initialization functions exist, one for each of the Subject types:
|
The following initialization functions exist, one for each of the Subject types:
|
||||||
|
|
||||||
:Integer: void :cpp:expr:`lv_subject_init_int(subject, int_value)`
|
:Integer: void :cpp:expr:`lv_subject_init_int(subject, int_value)`
|
||||||
|
:Float: void :cpp:expr:`lv_subject_init_float(subject, float_value)`
|
||||||
:String: void :cpp:expr:`lv_subject_init_string(subject, buf, prev_buf, buf_size, initial_string)`
|
:String: void :cpp:expr:`lv_subject_init_string(subject, buf, prev_buf, buf_size, initial_string)`
|
||||||
:Pointer: void :cpp:expr:`lv_subject_init_pointer(subject, ptr)`
|
:Pointer: void :cpp:expr:`lv_subject_init_pointer(subject, ptr)`
|
||||||
:Color: void :cpp:expr:`lv_subject_init_color(subject, color)`
|
:Color: void :cpp:expr:`lv_subject_init_color(subject, color)`
|
||||||
@@ -141,6 +142,7 @@ The following functions are used to get a Subject's current value:
|
|||||||
|
|
||||||
|
|
||||||
:Integer: int32_t :cpp:expr:`lv_subject_get_int(subject)`
|
:Integer: int32_t :cpp:expr:`lv_subject_get_int(subject)`
|
||||||
|
:Float: float :cpp:expr:`lv_subject_get_float(subject)`
|
||||||
:String: const char * :cpp:expr:`lv_subject_get_string(subject)`
|
:String: const char * :cpp:expr:`lv_subject_get_string(subject)`
|
||||||
:Pointer: const void * :cpp:expr:`lv_subject_get_pointer(subject)`
|
:Pointer: const void * :cpp:expr:`lv_subject_get_pointer(subject)`
|
||||||
:Color: lv_color_t :cpp:expr:`lv_subject_get_color(subject)`
|
:Color: lv_color_t :cpp:expr:`lv_subject_get_color(subject)`
|
||||||
@@ -153,6 +155,7 @@ The following functions are used to get a Subject's previous value:
|
|||||||
|
|
||||||
|
|
||||||
:Integer: int32_t :cpp:expr:`lv_subject_get_previous_int(subject)`
|
:Integer: int32_t :cpp:expr:`lv_subject_get_previous_int(subject)`
|
||||||
|
:Float: float :cpp:expr:`lv_subject_get_previous_float(subject)`
|
||||||
:String: const char * :cpp:expr:`lv_subject_get_previous_string(subject)`
|
:String: const char * :cpp:expr:`lv_subject_get_previous_string(subject)`
|
||||||
:Pointer: const void * :cpp:expr:`lv_subject_get_previous_pointer(subject)`
|
:Pointer: const void * :cpp:expr:`lv_subject_get_previous_pointer(subject)`
|
||||||
:Color: lv_color_t :cpp:expr:`lv_subject_get_previous_color(subject)`
|
:Color: lv_color_t :cpp:expr:`lv_subject_get_previous_color(subject)`
|
||||||
@@ -492,11 +495,14 @@ printf-like format specifier and be one of the following:
|
|||||||
cross-platform equivalent where ``xx`` can be ``8``,
|
cross-platform equivalent where ``xx`` can be ``8``,
|
||||||
``16``, ``32`` or ``64``, depending on the platform).
|
``16``, ``32`` or ``64``, depending on the platform).
|
||||||
|
|
||||||
If NULL is passed for the ``format_string`` argument:
|
:float Subject: "%f" format specifier, or e.g. "%0.2f" to display two digits after the decimal point.
|
||||||
|
|
||||||
|
|
||||||
|
If ``NULL`` is passed for the ``format_string`` argument:
|
||||||
|
|
||||||
:string or pointer Subject: Updates expect the pointer to point to a NUL-terminated string.
|
:string or pointer Subject: Updates expect the pointer to point to a NUL-terminated string.
|
||||||
|
:integer Subject: The Label will simply display the number. Equivalent to "%d".
|
||||||
:integer Subject: The Label will display an empty string (i.e. nothing).
|
:float Subject: The Label will display the value with "%0.1f" format string.
|
||||||
|
|
||||||
**Example:** "%d |deg|\C"
|
**Example:** "%d |deg|\C"
|
||||||
|
|
||||||
@@ -509,6 +515,9 @@ value directly. Note that this is a two-way binding (Subject <===> Widget) so a
|
|||||||
user's direct interaction with the Arc Widget updates the Subject's value and vice
|
user's direct interaction with the Arc Widget updates the Subject's value and vice
|
||||||
versa. (Requires :c:macro:`LV_USE_ARC` to be configured to ``1``.)
|
versa. (Requires :c:macro:`LV_USE_ARC` to be configured to ``1``.)
|
||||||
|
|
||||||
|
It support integer and float subjects.
|
||||||
|
|
||||||
|
|
||||||
- :cpp:expr:`lv_arc_bind_value(arc, &subject)`
|
- :cpp:expr:`lv_arc_bind_value(arc, &subject)`
|
||||||
|
|
||||||
|
|
||||||
@@ -520,6 +529,8 @@ value directly. Note that this is a two-way binding (Subject <===> Widget) so a
|
|||||||
user's direct interaction with the Slider Widget updates the Subject's value and vice
|
user's direct interaction with the Slider Widget updates the Subject's value and vice
|
||||||
versa. (Requires :c:macro:`LV_USE_SLIDER` to be configured to ``1``.)
|
versa. (Requires :c:macro:`LV_USE_SLIDER` to be configured to ``1``.)
|
||||||
|
|
||||||
|
It support integer and float subjects.
|
||||||
|
|
||||||
- :cpp:expr:`lv_slider_bind_value(slider, &subject)`
|
- :cpp:expr:`lv_slider_bind_value(slider, &subject)`
|
||||||
|
|
||||||
|
|
||||||
@@ -531,6 +542,8 @@ value directly. Note that this is a two-way binding (Subject <===> Widget) so a
|
|||||||
user's direct interaction with the Slider Widget updates the Subject's value and vice
|
user's direct interaction with the Slider Widget updates the Subject's value and vice
|
||||||
versa. (Requires :c:macro:`LV_USE_ROLLER` to be configured to ``1``.)
|
versa. (Requires :c:macro:`LV_USE_ROLLER` to be configured to ``1``.)
|
||||||
|
|
||||||
|
It support only integer subjects.
|
||||||
|
|
||||||
- :cpp:expr:`lv_roller_bind_value(roller, &subject)`
|
- :cpp:expr:`lv_roller_bind_value(roller, &subject)`
|
||||||
|
|
||||||
|
|
||||||
@@ -542,6 +555,8 @@ value directly. Note that this is a two-way binding (Subject <===> Widget) so a
|
|||||||
user's direct interaction with the Drop-Down Widget updates the Subject's value and
|
user's direct interaction with the Drop-Down Widget updates the Subject's value and
|
||||||
vice versa. (Requires :c:macro:`LV_USE_DROPDOWN` to be configured to ``1``.)
|
vice versa. (Requires :c:macro:`LV_USE_DROPDOWN` to be configured to ``1``.)
|
||||||
|
|
||||||
|
It support only integer subjects.
|
||||||
|
|
||||||
- :cpp:expr:`lv_dropdown_bind_value(dropdown, &subject)`
|
- :cpp:expr:`lv_dropdown_bind_value(dropdown, &subject)`
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,51 @@ int32_t lv_subject_get_previous_int(lv_subject_t * subject)
|
|||||||
return subject->prev_value.num;
|
return subject->prev_value.num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
|
||||||
|
void lv_subject_init_float(lv_subject_t * subject, float value)
|
||||||
|
{
|
||||||
|
lv_memzero(subject, sizeof(lv_subject_t));
|
||||||
|
subject->type = LV_SUBJECT_TYPE_FLOAT;
|
||||||
|
subject->value.float_v = value;
|
||||||
|
subject->prev_value.float_v = value;
|
||||||
|
lv_ll_init(&(subject->subs_ll), sizeof(lv_observer_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void lv_subject_set_float(lv_subject_t * subject, float value)
|
||||||
|
{
|
||||||
|
if(subject->type != LV_SUBJECT_TYPE_FLOAT) {
|
||||||
|
LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_FLOAT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
subject->prev_value.float_v = subject->value.float_v;
|
||||||
|
subject->value.float_v = value;
|
||||||
|
lv_subject_notify_if_changed(subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
float lv_subject_get_float(lv_subject_t * subject)
|
||||||
|
{
|
||||||
|
if(subject->type != LV_SUBJECT_TYPE_FLOAT) {
|
||||||
|
LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_FLOAT");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject->value.float_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lv_subject_get_previous_float(lv_subject_t * subject)
|
||||||
|
{
|
||||||
|
if(subject->type != LV_SUBJECT_TYPE_FLOAT) {
|
||||||
|
LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_FLOAT");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject->prev_value.float_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*LV_USE_FLOAT*/
|
||||||
|
|
||||||
void lv_subject_init_string(lv_subject_t * subject, char * buf, char * prev_buf, size_t size, const char * value)
|
void lv_subject_init_string(lv_subject_t * subject, char * buf, char * prev_buf, size_t size, const char * value)
|
||||||
{
|
{
|
||||||
lv_memzero(subject, sizeof(lv_subject_t));
|
lv_memzero(subject, sizeof(lv_subject_t));
|
||||||
@@ -683,6 +728,11 @@ lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const
|
|||||||
if(subject->type == LV_SUBJECT_TYPE_INT) {
|
if(subject->type == LV_SUBJECT_TYPE_INT) {
|
||||||
fmt = "%d";
|
fmt = "%d";
|
||||||
}
|
}
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
else if(subject->type == LV_SUBJECT_TYPE_FLOAT) {
|
||||||
|
fmt = "%0.1f";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER) {
|
else if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER) {
|
||||||
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -690,7 +740,7 @@ lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER &&
|
if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER &&
|
||||||
subject->type != LV_SUBJECT_TYPE_INT) {
|
subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) {
|
||||||
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -707,7 +757,7 @@ lv_observer_t * lv_arc_bind_value(lv_obj_t * obj, lv_subject_t * subject)
|
|||||||
LV_ASSERT_NULL(subject);
|
LV_ASSERT_NULL(subject);
|
||||||
LV_ASSERT_NULL(obj);
|
LV_ASSERT_NULL(obj);
|
||||||
|
|
||||||
if(subject->type != LV_SUBJECT_TYPE_INT) {
|
if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) {
|
||||||
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -725,7 +775,7 @@ lv_observer_t * lv_slider_bind_value(lv_obj_t * obj, lv_subject_t * subject)
|
|||||||
LV_ASSERT_NULL(subject);
|
LV_ASSERT_NULL(subject);
|
||||||
LV_ASSERT_NULL(obj);
|
LV_ASSERT_NULL(obj);
|
||||||
|
|
||||||
if(subject->type != LV_SUBJECT_TYPE_INT) {
|
if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) {
|
||||||
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
LV_LOG_WARN("Incompatible subject type: %d", subject->type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -937,6 +987,13 @@ static void lv_subject_notify_if_changed(lv_subject_t * subject)
|
|||||||
lv_subject_notify(subject);
|
lv_subject_notify(subject);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
case LV_SUBJECT_TYPE_FLOAT :
|
||||||
|
if(subject->value.float_v != subject->prev_value.float_v) {
|
||||||
|
lv_subject_notify(subject);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case LV_SUBJECT_TYPE_GROUP :
|
case LV_SUBJECT_TYPE_GROUP :
|
||||||
case LV_SUBJECT_TYPE_POINTER :
|
case LV_SUBJECT_TYPE_POINTER :
|
||||||
/* Always notify as we don't know how to compare this */
|
/* Always notify as we don't know how to compare this */
|
||||||
@@ -970,6 +1027,11 @@ static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subj
|
|||||||
case LV_SUBJECT_TYPE_INT:
|
case LV_SUBJECT_TYPE_INT:
|
||||||
lv_label_set_text_fmt(observer->target, fmt, subject->value.num);
|
lv_label_set_text_fmt(observer->target, fmt, subject->value.num);
|
||||||
break;
|
break;
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
case LV_SUBJECT_TYPE_FLOAT:
|
||||||
|
lv_label_set_text_fmt(observer->target, fmt, subject->value.float_v);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case LV_SUBJECT_TYPE_STRING:
|
case LV_SUBJECT_TYPE_STRING:
|
||||||
case LV_SUBJECT_TYPE_POINTER:
|
case LV_SUBJECT_TYPE_POINTER:
|
||||||
lv_label_set_text_fmt(observer->target, fmt, subject->value.pointer);
|
lv_label_set_text_fmt(observer->target, fmt, subject->value.pointer);
|
||||||
@@ -989,12 +1051,26 @@ static void arc_value_changed_event_cb(lv_event_t * e)
|
|||||||
lv_obj_t * arc = lv_event_get_current_target(e);
|
lv_obj_t * arc = lv_event_get_current_target(e);
|
||||||
lv_subject_t * subject = lv_event_get_user_data(e);
|
lv_subject_t * subject = lv_event_get_user_data(e);
|
||||||
|
|
||||||
lv_subject_set_int(subject, lv_arc_get_value(arc));
|
if(subject->type == LV_SUBJECT_TYPE_INT) {
|
||||||
|
lv_subject_set_int(subject, lv_arc_get_value(arc));
|
||||||
|
}
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
else {
|
||||||
|
lv_subject_set_float(subject, (float)lv_arc_get_value(arc));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arc_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
static void arc_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||||
{
|
{
|
||||||
lv_arc_set_value(observer->target, subject->value.num);
|
if(subject->type == LV_SUBJECT_TYPE_INT) {
|
||||||
|
lv_arc_set_value(observer->target, subject->value.num);
|
||||||
|
}
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
else {
|
||||||
|
lv_arc_set_value(observer->target, (int32_t)subject->value.float_v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*LV_USE_ARC*/
|
#endif /*LV_USE_ARC*/
|
||||||
@@ -1006,12 +1082,26 @@ static void slider_value_changed_event_cb(lv_event_t * e)
|
|||||||
lv_obj_t * slider = lv_event_get_current_target(e);
|
lv_obj_t * slider = lv_event_get_current_target(e);
|
||||||
lv_subject_t * subject = lv_event_get_user_data(e);
|
lv_subject_t * subject = lv_event_get_user_data(e);
|
||||||
|
|
||||||
lv_subject_set_int(subject, lv_slider_get_value(slider));
|
if(subject->type == LV_SUBJECT_TYPE_INT) {
|
||||||
|
lv_subject_set_int(subject, lv_slider_get_value(slider));
|
||||||
|
}
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
else {
|
||||||
|
lv_subject_set_float(subject, (float)lv_slider_get_value(slider));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void slider_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
static void slider_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
|
||||||
{
|
{
|
||||||
lv_slider_set_value(observer->target, subject->value.num, LV_ANIM_OFF);
|
if(subject->type == LV_SUBJECT_TYPE_INT) {
|
||||||
|
lv_slider_set_value(observer->target, subject->value.num, LV_ANIM_OFF);
|
||||||
|
}
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
else {
|
||||||
|
lv_slider_set_value(observer->target, (int32_t)subject->value.float_v, LV_ANIM_OFF);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*LV_USE_SLIDER*/
|
#endif /*LV_USE_SLIDER*/
|
||||||
|
|||||||
@@ -32,10 +32,11 @@ typedef enum {
|
|||||||
LV_SUBJECT_TYPE_INVALID = 0, /**< indicates Subject not initialized yet */
|
LV_SUBJECT_TYPE_INVALID = 0, /**< indicates Subject not initialized yet */
|
||||||
LV_SUBJECT_TYPE_NONE = 1, /**< a null value like None or NILt */
|
LV_SUBJECT_TYPE_NONE = 1, /**< a null value like None or NILt */
|
||||||
LV_SUBJECT_TYPE_INT = 2, /**< an int32_t */
|
LV_SUBJECT_TYPE_INT = 2, /**< an int32_t */
|
||||||
LV_SUBJECT_TYPE_POINTER = 3, /**< a void pointer */
|
LV_SUBJECT_TYPE_FLOAT = 3, /**< a float, requires `LV_USE_FLOAT 1` */
|
||||||
LV_SUBJECT_TYPE_COLOR = 4, /**< an lv_color_t */
|
LV_SUBJECT_TYPE_POINTER = 4, /**< a void pointer */
|
||||||
LV_SUBJECT_TYPE_GROUP = 5, /**< an array of Subjects */
|
LV_SUBJECT_TYPE_COLOR = 5, /**< an lv_color_t */
|
||||||
LV_SUBJECT_TYPE_STRING = 6, /**< a char pointer */
|
LV_SUBJECT_TYPE_GROUP = 6, /**< an array of Subjects */
|
||||||
|
LV_SUBJECT_TYPE_STRING = 7, /**< a char pointer */
|
||||||
} lv_subject_type_t;
|
} lv_subject_type_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,6 +46,9 @@ typedef union {
|
|||||||
int32_t num; /**< Integer number (opacity, enums, booleans or "normal" numbers) */
|
int32_t num; /**< Integer number (opacity, enums, booleans or "normal" numbers) */
|
||||||
const void * pointer; /**< Constant pointer (string buffer, format string, font, cone text, etc.) */
|
const void * pointer; /**< Constant pointer (string buffer, format string, font, cone text, etc.) */
|
||||||
lv_color_t color; /**< Color */
|
lv_color_t color; /**< Color */
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
float float_v; /**< Floating point value*/
|
||||||
|
#endif
|
||||||
} lv_subject_value_t;
|
} lv_subject_value_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,6 +104,38 @@ int32_t lv_subject_get_int(lv_subject_t * subject);
|
|||||||
*/
|
*/
|
||||||
int32_t lv_subject_get_previous_int(lv_subject_t * subject);
|
int32_t lv_subject_get_previous_int(lv_subject_t * subject);
|
||||||
|
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an float-type Subject.
|
||||||
|
* @param subject pointer to Subject
|
||||||
|
* @param value initial value
|
||||||
|
*/
|
||||||
|
void lv_subject_init_float(lv_subject_t * subject, float value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set value of an float Subject and notify Observers.
|
||||||
|
* @param subject pointer to Subject
|
||||||
|
* @param value new value
|
||||||
|
*/
|
||||||
|
void lv_subject_set_float(lv_subject_t * subject, float value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current value of an float Subject.
|
||||||
|
* @param subject pointer to Subject
|
||||||
|
* @return current value
|
||||||
|
*/
|
||||||
|
float lv_subject_get_float(lv_subject_t * subject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get previous value of an float Subject.
|
||||||
|
* @param subject pointer to Subject
|
||||||
|
* @return current value
|
||||||
|
*/
|
||||||
|
float lv_subject_get_previous_float(lv_subject_t * subject);
|
||||||
|
|
||||||
|
#endif /*LV_USE_FLOAT*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a string-type Subject.
|
* Initialize a string-type Subject.
|
||||||
* @param subject pointer to Subject
|
* @param subject pointer to Subject
|
||||||
|
|||||||
@@ -460,6 +460,9 @@ static void process_subject_element(lv_xml_parser_state_t * state, const char *
|
|||||||
lv_subject_t * subject = lv_zalloc(sizeof(lv_subject_t));
|
lv_subject_t * subject = lv_zalloc(sizeof(lv_subject_t));
|
||||||
|
|
||||||
if(lv_streq(type, "int")) lv_subject_init_int(subject, lv_xml_atoi(value));
|
if(lv_streq(type, "int")) lv_subject_init_int(subject, lv_xml_atoi(value));
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
else if(lv_streq(type, "float")) lv_subject_init_float(subject, lv_xml_atof(value));
|
||||||
|
#endif
|
||||||
else if(lv_streq(type, "color")) lv_subject_init_color(subject, lv_xml_to_color(value));
|
else if(lv_streq(type, "color")) lv_subject_init_color(subject, lv_xml_to_color(value));
|
||||||
else if(lv_streq(type, "string")) {
|
else if(lv_streq(type, "string")) {
|
||||||
/*Simple solution for now. Will be improved later*/
|
/*Simple solution for now. Will be improved later*/
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ int32_t lv_xml_atoi_split(const char ** str, char delimiter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = result * sign;
|
result = result * sign;
|
||||||
|
while(*s != delimiter && *s != '\0') s++; /*Make sure to find the delimiter*/
|
||||||
|
|
||||||
if(*s != '\0') s++; /*Skip the delimiter*/
|
if(*s != '\0') s++; /*Skip the delimiter*/
|
||||||
*str = s;
|
*str = s;
|
||||||
@@ -120,6 +121,72 @@ int32_t lv_xml_atoi(const char * str)
|
|||||||
return lv_xml_atoi_split(&str, '\0');
|
return lv_xml_atoi_split(&str, '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
float lv_xml_atof_split(const char ** str, char delimiter)
|
||||||
|
{
|
||||||
|
const char * s = *str;
|
||||||
|
float result = 0.0f;
|
||||||
|
int sign = 1;
|
||||||
|
|
||||||
|
/* Skip leading whitespace */
|
||||||
|
while(*s == ' ' || *s == '\t') s++;
|
||||||
|
|
||||||
|
/* Handle optional sign */
|
||||||
|
if(*s == '-') {
|
||||||
|
sign = -1;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else if(*s == '+') {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the integer part */
|
||||||
|
while(*s != delimiter && *s != '.' && *s != '\0') {
|
||||||
|
if(*s >= '0' && *s <= '9') {
|
||||||
|
float digit = *s - '0';
|
||||||
|
result = result * 10.0f + digit;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break; /* Non-digit character */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the fractional part */
|
||||||
|
if(*s == '.') {
|
||||||
|
s++; /* Skip the decimal point */
|
||||||
|
float fraction = 0.0f;
|
||||||
|
float divisor = 10.0f;
|
||||||
|
|
||||||
|
while(*s != delimiter && *s != '\0') {
|
||||||
|
if(*s >= '0' && *s <= '9') {
|
||||||
|
float digit = *s - '0';
|
||||||
|
fraction += digit / divisor;
|
||||||
|
divisor *= 10.0f;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break; /* Non-digit character */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result * sign;
|
||||||
|
while(*s != delimiter && *s != '\0') s++; /*Make sure to find the delimiter*/
|
||||||
|
|
||||||
|
if(*s != '\0') s++; /*Skip the delimiter*/
|
||||||
|
*str = s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float lv_xml_atof(const char * str)
|
||||||
|
{
|
||||||
|
return lv_xml_atof_split(&str, '\0');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int32_t lv_xml_strtol(const char * str, char ** endptr, int32_t base)
|
int32_t lv_xml_strtol(const char * str, char ** endptr, int32_t base)
|
||||||
{
|
{
|
||||||
const char * s = str;
|
const char * s = str;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ const char * lv_xml_get_value_of(const char ** attrs, const char * name);
|
|||||||
|
|
||||||
int32_t lv_xml_atoi(const char * str);
|
int32_t lv_xml_atoi(const char * str);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert sections of a string to int.
|
* Convert sections of a string to int.
|
||||||
* The end of the string is indicated by the `delimiter`.
|
* The end of the string is indicated by the `delimiter`.
|
||||||
@@ -36,6 +35,19 @@ int32_t lv_xml_atoi(const char * str);
|
|||||||
*/
|
*/
|
||||||
int32_t lv_xml_atoi_split(const char ** str, char delimiter);
|
int32_t lv_xml_atoi_split(const char ** str, char delimiter);
|
||||||
|
|
||||||
|
#if LV_USE_FLOAT
|
||||||
|
float lv_xml_atof(const char * str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert sections of a string to float.
|
||||||
|
* The end of the string is indicated by the `delimiter`.
|
||||||
|
* @param str pointer to a string, it will point to the character after the delimiter
|
||||||
|
* @param delimiter a character to indicate the end of the float
|
||||||
|
* @return the float before the next delimiter
|
||||||
|
*/
|
||||||
|
float lv_xml_atof_split(const char ** str, char delimiter);
|
||||||
|
#endif
|
||||||
|
|
||||||
lv_color_t lv_xml_to_color(const char * str);
|
lv_color_t lv_xml_to_color(const char * str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -192,6 +192,52 @@ void test_observer_int(void)
|
|||||||
lv_observer_remove(basic_observer);
|
lv_observer_remove(basic_observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_observer_float(void)
|
||||||
|
{
|
||||||
|
static lv_subject_t subject;
|
||||||
|
lv_subject_init_float(&subject, 5.25);
|
||||||
|
lv_observer_t * basic_observer =
|
||||||
|
lv_subject_add_observer(&subject, observer_basic, NULL);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(5.25, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(5.25, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(1, observer_called);
|
||||||
|
|
||||||
|
lv_subject_set_float(&subject, 10.5);
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(10.5, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(5.25, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(2, observer_called);
|
||||||
|
|
||||||
|
lv_subject_set_float(&subject, 15.75);
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(10.5, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(3, observer_called);
|
||||||
|
|
||||||
|
/* Observer shouldn't be called if value is the same */
|
||||||
|
lv_subject_set_float(&subject, 15.75);
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(3, observer_called);
|
||||||
|
|
||||||
|
/*Ignore incorrect types*/
|
||||||
|
lv_subject_set_pointer(&subject, NULL);
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(3, observer_called);
|
||||||
|
|
||||||
|
lv_subject_set_color(&subject, lv_color_black());
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(3, observer_called);
|
||||||
|
|
||||||
|
lv_subject_copy_string(&subject, "hello");
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL_FLOAT(15.75, lv_subject_get_previous_float(&subject));
|
||||||
|
TEST_ASSERT_EQUAL(3, observer_called);
|
||||||
|
|
||||||
|
lv_observer_remove(basic_observer);
|
||||||
|
}
|
||||||
|
|
||||||
void test_observer_string(void)
|
void test_observer_string(void)
|
||||||
{
|
{
|
||||||
char buf_current[32];
|
char buf_current[32];
|
||||||
@@ -756,6 +802,17 @@ void test_observer_label_text_normal(void)
|
|||||||
observer = lv_label_bind_text(obj, &subject_int, NULL);
|
observer = lv_label_bind_text(obj, &subject_int, NULL);
|
||||||
TEST_ASSERT_EQUAL_STRING("10", lv_label_get_text(obj));
|
TEST_ASSERT_EQUAL_STRING("10", lv_label_get_text(obj));
|
||||||
|
|
||||||
|
/*Bind it with "%0.1f" if NULL is passed*/
|
||||||
|
static lv_subject_t subject_float;
|
||||||
|
lv_subject_init_float(&subject_float, 10.5);
|
||||||
|
observer = lv_label_bind_text(obj, &subject_float, NULL);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("10.5", lv_label_get_text(obj));
|
||||||
|
|
||||||
|
/*Bind it with "%0.1f" if NULL is passed*/
|
||||||
|
lv_subject_set_float(&subject_float, 81.5);
|
||||||
|
observer = lv_label_bind_text(obj, &subject_float, "Value: %0.2f");
|
||||||
|
TEST_ASSERT_EQUAL_STRING("Value: 81.50", lv_label_get_text(obj));
|
||||||
|
|
||||||
/*Bind to string*/
|
/*Bind to string*/
|
||||||
static char buf[32];
|
static char buf[32];
|
||||||
static lv_subject_t subject_string;
|
static lv_subject_t subject_string;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ void test_xml_label_with_attrs(void)
|
|||||||
lv_subject_init_int(&s1, 20);
|
lv_subject_init_int(&s1, 20);
|
||||||
lv_xml_register_subject(NULL, "s1", &s1);
|
lv_xml_register_subject(NULL, "s1", &s1);
|
||||||
|
|
||||||
|
|
||||||
const char * label2_attrs[] = {
|
const char * label2_attrs[] = {
|
||||||
"bind_text", "s1",
|
"bind_text", "s1",
|
||||||
"bind_text-fmt", "We have %d users",
|
"bind_text-fmt", "We have %d users",
|
||||||
@@ -45,6 +46,20 @@ void test_xml_label_with_attrs(void)
|
|||||||
|
|
||||||
lv_xml_create(scr, "lv_label", label2_attrs);
|
lv_xml_create(scr, "lv_label", label2_attrs);
|
||||||
|
|
||||||
|
static lv_subject_t s2;
|
||||||
|
lv_subject_init_float(&s2, 12.3f);
|
||||||
|
lv_xml_register_subject(NULL, "s2", &s2);
|
||||||
|
|
||||||
|
const char * label3_attrs[] = {
|
||||||
|
"bind_text", "s2",
|
||||||
|
"bind_text-fmt", "We have measured: %0.3f mW",
|
||||||
|
"y", "30",
|
||||||
|
"x", "5",
|
||||||
|
NULL, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
lv_xml_create(scr, "lv_label", label3_attrs);
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_label.png");
|
TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_label.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user