diff --git a/src/others/observer/lv_observer.c b/src/others/observer/lv_observer.c index 15cf46ed02..6d328574f6 100644 --- a/src/others/observer/lv_observer.c +++ b/src/others/observer/lv_observer.c @@ -55,12 +55,6 @@ typedef struct { const char * value; } subject_set_string_user_data_t; -typedef struct { - lv_subject_t * subject; - void * element; /**< E.g. span of a span group*/ - const char * fmt; -} bind_element_string_t; - typedef struct { lv_subject_t * subject; int32_t step; @@ -93,39 +87,6 @@ static void obj_value_changed_event_cb(lv_event_t * e); static void lv_subject_notify_if_changed(lv_subject_t * subject); -#if LV_USE_LABEL - static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - -#if LV_USE_SPAN - static void span_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - -#if LV_USE_ARC - static void arc_value_changed_event_cb(lv_event_t * e); - static void arc_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - -#if LV_USE_SLIDER - static void slider_value_changed_event_cb(lv_event_t * e); - static void slider_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - -#if LV_USE_ROLLER - static void roller_value_changed_event_cb(lv_event_t * e); - static void roller_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - -#if LV_USE_DROPDOWN - static void dropdown_value_changed_event_cb(lv_event_t * e); - static void dropdown_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - -#if LV_USE_SCALE - static void scale_section_min_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); - static void scale_section_max_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); -#endif - static void subject_set_string_free_user_data_event_cb(lv_event_t * e); /********************** @@ -759,192 +720,6 @@ lv_observer_t * lv_obj_bind_checked(lv_obj_t * obj, lv_subject_t * subject) return observable; } -#if LV_USE_LABEL -lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const char * fmt) -{ - LV_ASSERT_NULL(subject); - LV_ASSERT_NULL(obj); - - if(fmt == NULL) { - if(subject->type == LV_SUBJECT_TYPE_INT) { - 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) { - LV_LOG_WARN("Incompatible subject type: %d", subject->type); - return NULL; - } - } - else { - if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER && - subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { - LV_LOG_WARN("Incompatible subject type: %d", subject->type); - return NULL; - } - } - - lv_observer_t * observer = lv_subject_add_observer_obj(subject, label_text_observer_cb, obj, (void *)fmt); - return observer; -} -#endif /*LV_USE_LABEL*/ - -#if LV_USE_SPAN -lv_observer_t * lv_spangroup_bind_span_text(lv_obj_t * obj, lv_span_t * span, lv_subject_t * subject, const char * fmt) -{ - LV_ASSERT_NULL(subject); - LV_ASSERT_NULL(obj); - LV_ASSERT_NULL(span); - - if(fmt == NULL) { - if(subject->type == LV_SUBJECT_TYPE_INT) { - 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) { - LV_LOG_WARN("Incompatible subject type: %d", subject->type); - return NULL; - } - } - else { - if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER && - subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { - LV_LOG_WARN("Incompatible subject type: %d", subject->type); - return NULL; - } - } - - bind_element_string_t * user_data = lv_zalloc(sizeof(bind_element_string_t)); - if(user_data == NULL) { - LV_LOG_WARN("Couldn't allocate user_data"); - LV_ASSERT_MALLOC(user_data); - return NULL; - } - - user_data->subject = subject; - user_data->element = span; - user_data->fmt = fmt; - - lv_observer_t * observer = lv_subject_add_observer_obj(subject, span_text_observer_cb, obj, user_data); - observer->auto_free_user_data = 1; - - return observer; -} -#endif /*LV_USE_SPAN*/ - - -#if LV_USE_ARC -lv_observer_t * lv_arc_bind_value(lv_obj_t * obj, lv_subject_t * subject) -{ - LV_ASSERT_NULL(subject); - LV_ASSERT_NULL(obj); - - if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { - LV_LOG_WARN("Incompatible subject type: %d", subject->type); - return NULL; - } - - lv_obj_add_event_cb(obj, arc_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); - - lv_observer_t * observer = lv_subject_add_observer_obj(subject, arc_value_observer_cb, obj, NULL); - return observer; -} -#endif /*LV_USE_ARC*/ - -#if LV_USE_SLIDER -lv_observer_t * lv_slider_bind_value(lv_obj_t * obj, lv_subject_t * subject) -{ - LV_ASSERT_NULL(subject); - LV_ASSERT_NULL(obj); - - if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { - LV_LOG_WARN("Incompatible subject type: %d", subject->type); - return NULL; - } - - lv_obj_add_event_cb(obj, slider_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); - - lv_observer_t * observer = lv_subject_add_observer_obj(subject, slider_value_observer_cb, obj, NULL); - return observer; -} -#endif /*LV_USE_SLIDER*/ - -#if LV_USE_ROLLER -lv_observer_t * lv_roller_bind_value(lv_obj_t * obj, lv_subject_t * subject) -{ - 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_event_cb(obj, roller_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); - - lv_observer_t * observer = lv_subject_add_observer_obj(subject, roller_value_observer_cb, obj, NULL); - return observer; -} -#endif /*LV_USE_ROLLER*/ - -#if LV_USE_DROPDOWN -lv_observer_t * lv_dropdown_bind_value(lv_obj_t * obj, lv_subject_t * subject) -{ - 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_event_cb(obj, dropdown_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); - - lv_observer_t * observer = lv_subject_add_observer_obj(subject, dropdown_value_observer_cb, obj, NULL); - return observer; -} -#endif /*LV_USE_DROPDOWN*/ - -#if LV_USE_SCALE - -lv_observer_t * lv_scale_bind_section_min_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject) -{ - 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_observer_t * observer = lv_subject_add_observer_obj(subject, scale_section_min_value_observer_cb, obj, section); - - return observer; -} - -lv_observer_t * lv_scale_bind_section_max_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject) -{ - 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_observer_t * observer = lv_subject_add_observer_obj(subject, scale_section_max_value_observer_cb, obj, section); - - return observer; -} - -#endif /*LV_USE_SCALE*/ lv_obj_t * lv_observer_get_target_obj(lv_observer_t * observer) { @@ -1154,184 +929,6 @@ static void lv_subject_notify_if_changed(lv_subject_t * subject) } } -#if LV_USE_LABEL - -static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - const char * fmt = observer->user_data; - - if(fmt == NULL) { - lv_label_set_text(observer->target, subject->value.pointer); - } - else { - switch(subject->type) { - case LV_SUBJECT_TYPE_INT: - lv_label_set_text_fmt(observer->target, fmt, subject->value.num); - 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_POINTER: - lv_label_set_text_fmt(observer->target, fmt, subject->value.pointer); - break; - default: - break; - } - } -} - -#endif /*LV_USE_LABEL*/ - -#if LV_USE_SPAN - -static void span_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - bind_element_string_t * user_data = observer->user_data; - - if(user_data->fmt == NULL) { - lv_spangroup_set_span_text(observer->target, user_data->element, subject->value.pointer); - } - else { - switch(subject->type) { - - case LV_SUBJECT_TYPE_INT: - lv_spangroup_set_span_text_fmt(observer->target, user_data->element, user_data->fmt, subject->value.num); - break; -#if LV_USE_FLOAT - case LV_SUBJECT_TYPE_FLOAT: - lv_spangroup_set_span_text_fmt(observer->target, user_data->element, user_data->fmt, subject->value.float_v); - break; -#endif - case LV_SUBJECT_TYPE_STRING: - case LV_SUBJECT_TYPE_POINTER: - lv_spangroup_set_span_text_fmt(observer->target, user_data->element, user_data->fmt, subject->value.pointer); - break; - default: - return; - } - } -} - -#endif /*LV_USE_SPAN*/ - - -#if LV_USE_ARC - -static void arc_value_changed_event_cb(lv_event_t * e) -{ - lv_obj_t * arc = lv_event_get_current_target(e); - lv_subject_t * subject = lv_event_get_user_data(e); - - 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) -{ - 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*/ - -#if LV_USE_SLIDER - -static void slider_value_changed_event_cb(lv_event_t * e) -{ - lv_obj_t * slider = lv_event_get_current_target(e); - lv_subject_t * subject = lv_event_get_user_data(e); - - 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) -{ - 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*/ - -#if LV_USE_ROLLER - -static void roller_value_changed_event_cb(lv_event_t * e) -{ - lv_obj_t * roller = lv_event_get_current_target(e); - lv_subject_t * subject = lv_event_get_user_data(e); - - lv_subject_set_int(subject, lv_roller_get_selected(roller)); -} - -static void roller_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - if((int32_t)lv_roller_get_selected(observer->target) != subject->value.num) { - lv_roller_set_selected(observer->target, subject->value.num, LV_ANIM_OFF); - } -} - -#endif /*LV_USE_ROLLER*/ - -#if LV_USE_DROPDOWN - -static void dropdown_value_changed_event_cb(lv_event_t * e) -{ - lv_obj_t * dropdown = lv_event_get_current_target(e); - lv_subject_t * subject = lv_event_get_user_data(e); - - lv_subject_set_int(subject, lv_dropdown_get_selected(dropdown)); -} - -static void dropdown_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - lv_dropdown_set_selected(observer->target, subject->value.num); -} - -#endif /*LV_USE_DROPDOWN*/ - -#if LV_USE_SCALE - -static void scale_section_min_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - lv_scale_section_t * section = observer->user_data; - lv_scale_set_section_min_value(observer->target, section, subject->value.num); -} - -static void scale_section_max_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) -{ - lv_scale_section_t * section = observer->user_data; - lv_scale_set_section_max_value(observer->target, section, subject->value.num); -} - -#endif /*LV_USE_SCALE*/ - static void subject_set_string_free_user_data_event_cb(lv_event_t * e) { subject_set_string_user_data_t * user_data = lv_event_get_user_data(e); diff --git a/src/others/observer/lv_observer.h b/src/others/observer/lv_observer.h index f1fc68d32d..d2eeb67213 100644 --- a/src/others/observer/lv_observer.h +++ b/src/others/observer/lv_observer.h @@ -530,100 +530,6 @@ lv_observer_t * lv_obj_bind_state_if_le(lv_obj_t * obj, lv_subject_t * subject, */ lv_observer_t * lv_obj_bind_checked(lv_obj_t * obj, lv_subject_t * subject); -#if LV_USE_LABEL -/** - * Bind an integer, string, or pointer Subject to a Label. - * @param obj pointer to Label - * @param subject pointer to Subject - * @param fmt optional printf-like format string with 1 format specifier (e.g. "%d °C") - * or NULL to bind to the value directly. - * @return pointer to newly-created Observer - * @note `fmt == NULL` can be used only with string and pointer Subjects. - * @note If Subject is a pointer and `fmt == NULL`, pointer must point - * to a `\0` terminated string. - */ -lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const char * fmt); -#endif - -#if LV_USE_SPAN - -/** - * Bind an integer, string, or pointer Subject to a Spangroup's Span. - * @param obj pointer to Spangroup - * @param span pointer to Span - * @param subject pointer to Subject - * @param fmt optional printf-like format string with 1 format specifier (e.g. "%d °C") - * or NULL to bind to the value directly. - * @return pointer to newly-created Observer - * @note `fmt == NULL` can be used only with string and pointer Subjects. - * @note If `fmt == NULL` strings and pointers (`\0` terminated string) will be shown - * as text as they are, integers as %d, floats as %0.1f - */ -lv_observer_t * lv_spangroup_bind_span_text(lv_obj_t * obj, lv_span_t * span, lv_subject_t * subject, const char * fmt); - -#endif - -#if LV_USE_ARC -/** - * Bind an integer subject to an Arc's value. - * @param obj pointer to Arc - * @param subject pointer to Subject - * @return pointer to newly-created Observer - */ -lv_observer_t * lv_arc_bind_value(lv_obj_t * obj, lv_subject_t * subject); -#endif - -#if LV_USE_SLIDER -/** - * Bind an integer Subject to a Slider's value. - * @param obj pointer to Slider - * @param subject pointer to Subject - * @return pointer to newly-created Observer - */ -lv_observer_t * lv_slider_bind_value(lv_obj_t * obj, lv_subject_t * subject); -#endif - -#if LV_USE_ROLLER -/** - * Bind an integer Subject to a Roller's value. - * @param obj pointer to Roller - * @param subject pointer to Subject - * @return pointer to newly-created Observer - */ -lv_observer_t * lv_roller_bind_value(lv_obj_t * obj, lv_subject_t * subject); -#endif - -#if LV_USE_DROPDOWN -/** - * Bind an integer Subject to a Dropdown's value. - * @param obj pointer to Dropdown - * @param subject pointer to Subject - * @return pointer to newly-created Observer - */ -lv_observer_t * lv_dropdown_bind_value(lv_obj_t * obj, lv_subject_t * subject); -#endif - -#if LV_USE_SCALE - -/** - * Bind an integer subject to a scales section minimum value - * @param obj pointer to a Scale - * @param section pointer to a Scale section - * @param subject pointer to a Subject - * @return pointer to newly-created Observer - */ -lv_observer_t * lv_scale_bind_section_min_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject); - -/** - * Bind an integer subject to a scales section maximum value - * @param obj pointer to an Scale - * @param section pointer to a Scale section - * @param subject pointer to a Subject - * @return pointer to newly-created Observer - */ -lv_observer_t * lv_scale_bind_section_max_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject); - -#endif /********************** * MACROS diff --git a/src/widgets/arc/lv_arc.c b/src/widgets/arc/lv_arc.c index 201452a3e0..4a683ee4b8 100644 --- a/src/widgets/arc/lv_arc.c +++ b/src/widgets/arc/lv_arc.c @@ -18,6 +18,7 @@ #include "../../misc/lv_assert.h" #include "../../misc/lv_math.h" #include "../../draw/lv_draw_arc.h" +#include "../../others/observer/lv_observer_private.h" /********************* * DEFINES @@ -50,6 +51,10 @@ static void value_update(lv_obj_t * arc); static int32_t knob_get_extra_size(lv_obj_t * obj); static bool lv_arc_angle_within_bg_bounds(lv_obj_t * obj, const lv_value_precise_t angle, const lv_value_precise_t tolerance_deg); +#if LV_USE_OBSERVER + static void arc_value_changed_event_cb(lv_event_t * e); + static void arc_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif /*LV_USE_OBSERVER*/ /********************** * STATIC VARIABLES @@ -367,6 +372,25 @@ int32_t lv_arc_get_knob_offset(const lv_obj_t * obj) * Other functions *====================*/ +#if LV_USE_OBSERVER +lv_observer_t * lv_arc_bind_value(lv_obj_t * obj, lv_subject_t * subject) +{ + LV_ASSERT_NULL(subject); + LV_ASSERT_NULL(obj); + + if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { + LV_LOG_WARN("Incompatible subject type: %d", subject->type); + return NULL; + } + + lv_obj_add_event_cb(obj, arc_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); + + lv_observer_t * observer = lv_subject_add_observer_obj(subject, arc_value_observer_cb, obj, NULL); + return observer; +} +#endif /*LV_USE_OBSERVER*/ + + void lv_arc_align_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_align, int32_t r_offset) { LV_ASSERT_OBJ(obj, MY_CLASS); @@ -1025,4 +1049,36 @@ static bool lv_arc_angle_within_bg_bounds(lv_obj_t * obj, const lv_value_precise return false; } +#if LV_USE_OBSERVER + +static void arc_value_changed_event_cb(lv_event_t * e) +{ + lv_obj_t * arc = lv_event_get_current_target(e); + lv_subject_t * subject = lv_event_get_user_data(e); + + 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) +{ + 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_OBSERVER*/ + + #endif diff --git a/src/widgets/arc/lv_arc.h b/src/widgets/arc/lv_arc.h index 18c2dbc7ad..a96400ba0d 100644 --- a/src/widgets/arc/lv_arc.h +++ b/src/widgets/arc/lv_arc.h @@ -18,6 +18,7 @@ extern "C" { #if LV_USE_ARC != 0 #include "../../core/lv_obj.h" +#include "../../others/observer/lv_observer.h" /********************* * DEFINES @@ -232,6 +233,17 @@ int32_t lv_arc_get_knob_offset(const lv_obj_t * obj); * Other functions *====================*/ +#if LV_USE_OBSERVER +/** + * Bind an integer subject to an Arc's value. + * @param obj pointer to Arc + * @param subject pointer to Subject + * @return pointer to newly-created Observer + */ +lv_observer_t * lv_arc_bind_value(lv_obj_t * obj, lv_subject_t * subject); +#endif + + /** * Align an object to the current position of the arc (knob) * @param obj pointer to an arc object diff --git a/src/widgets/bar/lv_bar.h b/src/widgets/bar/lv_bar.h index 7e9953e116..17a1208ddf 100644 --- a/src/widgets/bar/lv_bar.h +++ b/src/widgets/bar/lv_bar.h @@ -20,6 +20,7 @@ extern "C" { #include "../../core/lv_obj.h" #include "../../misc/lv_anim.h" #include "../label/lv_label.h" +#include "../../others/observer/lv_observer.h" /********************* * DEFINES diff --git a/src/widgets/dropdown/lv_dropdown.c b/src/widgets/dropdown/lv_dropdown.c index b16ec89b93..db15f1c5a1 100644 --- a/src/widgets/dropdown/lv_dropdown.c +++ b/src/widgets/dropdown/lv_dropdown.c @@ -22,6 +22,7 @@ #include "../../misc/lv_math.h" #include "../../misc/lv_text_ap.h" #include "../../misc/lv_text_private.h" +#include "../../others/observer/lv_observer_private.h" #include "../../stdlib/lv_string.h" /********************* @@ -59,6 +60,11 @@ static uint32_t get_id_on_point(lv_obj_t * dropdown_obj, int32_t y); static void position_to_selected(lv_obj_t * dropdown_obj, lv_anim_enable_t anim_en); static lv_obj_t * get_label(const lv_obj_t * obj); +#if LV_USE_OBSERVER + static void dropdown_value_changed_event_cb(lv_event_t * e); + static void dropdown_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif /*LV_USE_OBSERVER*/ + /********************** * STATIC VARIABLES **********************/ @@ -636,6 +642,27 @@ bool lv_dropdown_is_open(lv_obj_t * obj) return lv_obj_has_flag(dropdown->list, LV_OBJ_FLAG_HIDDEN) ? false : true; } +#if LV_USE_OBSERVER + +lv_observer_t * lv_dropdown_bind_value(lv_obj_t * obj, lv_subject_t * subject) +{ + 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_event_cb(obj, dropdown_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); + + lv_observer_t * observer = lv_subject_add_observer_obj(subject, dropdown_value_observer_cb, obj, NULL); + return observer; +} +#endif /*LV_USE_OBSERVER*/ + + + /********************** * STATIC FUNCTIONS **********************/ @@ -1257,4 +1284,22 @@ static lv_obj_t * get_label(const lv_obj_t * obj) return lv_obj_get_child(dropdown->list, 0); } +#if LV_USE_OBSERVER + +static void dropdown_value_changed_event_cb(lv_event_t * e) +{ + lv_obj_t * dropdown = lv_event_get_current_target(e); + lv_subject_t * subject = lv_event_get_user_data(e); + + lv_subject_set_int(subject, lv_dropdown_get_selected(dropdown)); +} + +static void dropdown_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) +{ + lv_dropdown_set_selected(observer->target, subject->value.num); +} + +#endif /*LV_USE_OBSERVER*/ + + #endif diff --git a/src/widgets/dropdown/lv_dropdown.h b/src/widgets/dropdown/lv_dropdown.h index 07bbd0e840..a65f50d4a6 100644 --- a/src/widgets/dropdown/lv_dropdown.h +++ b/src/widgets/dropdown/lv_dropdown.h @@ -233,6 +233,17 @@ void lv_dropdown_close(lv_obj_t * obj); */ bool lv_dropdown_is_open(lv_obj_t * obj); + +#if LV_USE_OBSERVER +/** + * Bind an integer Subject to a Dropdown's value. + * @param obj pointer to Dropdown + * @param subject pointer to Subject + * @return pointer to newly-created Observer + */ +lv_observer_t * lv_dropdown_bind_value(lv_obj_t * obj, lv_subject_t * subject); +#endif + /********************** * MACROS **********************/ diff --git a/src/widgets/label/lv_label.c b/src/widgets/label/lv_label.c index 0ca8b99f10..9f947bcb86 100644 --- a/src/widgets/label/lv_label.c +++ b/src/widgets/label/lv_label.c @@ -24,6 +24,7 @@ #include "../../misc/lv_text_private.h" #include "../../stdlib/lv_sprintf.h" #include "../../stdlib/lv_string.h" +#include "../../others/observer/lv_observer_private.h" /********************* * DEFINES @@ -59,6 +60,10 @@ static lv_text_flag_t get_label_flags(lv_label_t * label); static void calculate_x_coordinate(int32_t * x, const lv_text_align_t align, const char * txt, uint32_t length, const lv_font_t * font, lv_area_t * txt_coords, lv_text_attributes_t * attributes); +#if LV_USE_OBSERVER + static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif + /********************** * STATIC VARIABLES **********************/ @@ -664,6 +669,40 @@ bool lv_label_get_recolor(const lv_obj_t * obj) * Other functions *====================*/ +#if LV_USE_OBSERVER +lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const char * fmt) +{ + LV_ASSERT_NULL(subject); + LV_ASSERT_NULL(obj); + + if(fmt == NULL) { + if(subject->type == LV_SUBJECT_TYPE_INT) { + 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) { + LV_LOG_WARN("Incompatible subject type: %d", subject->type); + return NULL; + } + } + else { + if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER && + subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { + LV_LOG_WARN("Incompatible subject type: %d", subject->type); + return NULL; + } + } + + lv_observer_t * observer = lv_subject_add_observer_obj(subject, label_text_observer_cb, obj, (void *)fmt); + return observer; +} +#endif /*LV_USE_OBSERVER*/ + + void lv_label_ins_text(lv_obj_t * obj, uint32_t pos, const char * txt) { LV_ASSERT_OBJ(obj, MY_CLASS); @@ -710,6 +749,8 @@ void lv_label_cut_text(lv_obj_t * obj, uint32_t pos, uint32_t cnt) lv_label_refr_text(obj); } + + /********************** * STATIC FUNCTIONS **********************/ @@ -1331,4 +1372,36 @@ static void calculate_x_coordinate(int32_t * x, const lv_text_align_t align, con } } +#if LV_USE_OBSERVER + +static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject) +{ + const char * fmt = observer->user_data; + + if(fmt == NULL) { + lv_label_set_text(observer->target, subject->value.pointer); + } + else { + switch(subject->type) { + case LV_SUBJECT_TYPE_INT: + lv_label_set_text_fmt(observer->target, fmt, subject->value.num); + 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_POINTER: + lv_label_set_text_fmt(observer->target, fmt, subject->value.pointer); + break; + default: + break; + } + } +} + +#endif /*LV_USE_LABEL*/ + + #endif diff --git a/src/widgets/label/lv_label.h b/src/widgets/label/lv_label.h index b71cc7bafa..54ccf89c97 100644 --- a/src/widgets/label/lv_label.h +++ b/src/widgets/label/lv_label.h @@ -23,6 +23,7 @@ extern "C" { #include "../../font/lv_symbol_def.h" #include "../../misc/lv_text.h" #include "../../draw/lv_draw.h" +#include "../../others/observer/lv_observer.h" /********************* * DEFINES @@ -227,6 +228,22 @@ bool lv_label_get_recolor(const lv_obj_t * obj); * Other functions *====================*/ +#if LV_USE_OBSERVER +/** + * Bind an integer, string, or pointer Subject to a Label. + * @param obj pointer to Label + * @param subject pointer to Subject + * @param fmt optional printf-like format string with 1 format specifier (e.g. "%d °C") + * or NULL to bind to the value directly. + * @return pointer to newly-created Observer + * @note `fmt == NULL` can be used only with string and pointer Subjects. + * @note If Subject is a pointer and `fmt == NULL`, pointer must point + * to a `\0` terminated string. + */ +lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const char * fmt); +#endif + + /** * Insert a text to a label. The label text cannot be static. * @param obj pointer to a label object @@ -245,6 +262,8 @@ void lv_label_ins_text(lv_obj_t * obj, uint32_t pos, const char * txt); */ void lv_label_cut_text(lv_obj_t * obj, uint32_t pos, uint32_t cnt); + + /********************** * MACROS **********************/ diff --git a/src/widgets/roller/lv_roller.c b/src/widgets/roller/lv_roller.c index 3966024bd3..7780f0c15f 100644 --- a/src/widgets/roller/lv_roller.c +++ b/src/widgets/roller/lv_roller.c @@ -22,6 +22,7 @@ #include "../../indev/lv_indev_scroll.h" #include "../../indev/lv_indev_private.h" #include "../../stdlib/lv_string.h" +#include "../../others/observer/lv_observer_private.h" /********************* * DEFINES @@ -52,6 +53,11 @@ static void scroll_anim_completed_cb(lv_anim_t * a); static void set_y_anim(void * obj, int32_t v); static void transform_vect_recursive(lv_obj_t * roller, lv_point_t * vect); +#if LV_USE_OBSERVER + static void roller_value_changed_event_cb(lv_event_t * e); + static void roller_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif /*LV_USE_OBSERVER*/ + /********************** * STATIC VARIABLES **********************/ @@ -328,6 +334,25 @@ uint32_t lv_roller_get_option_count(const lv_obj_t * obj) } } +#if LV_USE_OBSERVER + +lv_observer_t * lv_roller_bind_value(lv_obj_t * obj, lv_subject_t * subject) +{ + 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_event_cb(obj, roller_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); + + lv_observer_t * observer = lv_subject_add_observer_obj(subject, roller_value_observer_cb, obj, NULL); + return observer; +} +#endif /*LV_USE_OBSERVER*/ + /********************** * STATIC FUNCTIONS **********************/ @@ -915,4 +940,24 @@ static void transform_vect_recursive(lv_obj_t * roller, lv_point_t * vect) lv_point_transform(vect, -angle, scale_x, scale_y, &pivot, false); } +#if LV_USE_OBSERVER + +static void roller_value_changed_event_cb(lv_event_t * e) +{ + lv_obj_t * roller = lv_event_get_current_target(e); + lv_subject_t * subject = lv_event_get_user_data(e); + + lv_subject_set_int(subject, lv_roller_get_selected(roller)); +} + +static void roller_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) +{ + if((int32_t)lv_roller_get_selected(observer->target) != subject->value.num) { + lv_roller_set_selected(observer->target, subject->value.num, LV_ANIM_OFF); + } +} + +#endif /*LV_USE_OBSERVER*/ + + #endif diff --git a/src/widgets/roller/lv_roller.h b/src/widgets/roller/lv_roller.h index 37d94bed0d..7f960c7dcc 100644 --- a/src/widgets/roller/lv_roller.h +++ b/src/widgets/roller/lv_roller.h @@ -129,6 +129,17 @@ const char * lv_roller_get_options(const lv_obj_t * obj); */ uint32_t lv_roller_get_option_count(const lv_obj_t * obj); + +#if LV_USE_OBSERVER +/** + * Bind an integer Subject to a Roller's value. + * @param obj pointer to Roller + * @param subject pointer to Subject + * @return pointer to newly-created Observer + */ +lv_observer_t * lv_roller_bind_value(lv_obj_t * obj, lv_subject_t * subject); +#endif + /********************** * MACROS **********************/ diff --git a/src/widgets/scale/lv_scale.c b/src/widgets/scale/lv_scale.c index 961a768c34..5bc400d403 100644 --- a/src/widgets/scale/lv_scale.c +++ b/src/widgets/scale/lv_scale.c @@ -15,6 +15,7 @@ #include "../../misc/lv_assert.h" #include "../../misc/lv_math.h" #include "../../misc/lv_text_private.h" +#include "../../others/observer/lv_observer_private.h" #include "../../draw/lv_draw_arc.h" /********************* @@ -70,6 +71,11 @@ static void scale_free_line_needle_points_cb(lv_event_t * e); static bool scale_is_major_tick(lv_scale_t * scale, uint32_t tick_idx); +#if LV_USE_OBSERVER + static void scale_section_min_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); + static void scale_section_max_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif /*LV_USE_OBSERVER*/ + /********************** * STATIC VARIABLES **********************/ @@ -517,6 +523,40 @@ int32_t lv_scale_get_range_max_value(lv_obj_t * obj) * Other functions *====================*/ +#if LV_USE_OBSERVER + +lv_observer_t * lv_scale_bind_section_min_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject) +{ + 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_observer_t * observer = lv_subject_add_observer_obj(subject, scale_section_min_value_observer_cb, obj, section); + + return observer; +} + +lv_observer_t * lv_scale_bind_section_max_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject) +{ + 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_observer_t * observer = lv_subject_add_observer_obj(subject, scale_section_max_value_observer_cb, obj, section); + + return observer; +} + +#endif /*LV_USE_OBSERVER*/ + /********************** * STATIC FUNCTIONS **********************/ @@ -1719,4 +1759,21 @@ static bool scale_is_major_tick(lv_scale_t * scale, uint32_t tick_idx) return scale->major_tick_every != 0 && tick_idx % scale->major_tick_every == 0; } +#if LV_USE_OBSERVER + +static void scale_section_min_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) +{ + lv_scale_section_t * section = observer->user_data; + lv_scale_set_section_min_value(observer->target, section, subject->value.num); +} + +static void scale_section_max_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject) +{ + lv_scale_section_t * section = observer->user_data; + lv_scale_set_section_max_value(observer->target, section, subject->value.num); +} + +#endif /*LV_USE_OBSERVER*/ + + #endif diff --git a/src/widgets/scale/lv_scale.h b/src/widgets/scale/lv_scale.h index a5b856d900..642259a3b7 100644 --- a/src/widgets/scale/lv_scale.h +++ b/src/widgets/scale/lv_scale.h @@ -20,6 +20,7 @@ extern "C" { #include "../../core/lv_obj.h" #include "../line/lv_line.h" #include "../image/lv_image.h" +#include "../../others/observer/lv_observer.h" /********************* * DEFINES @@ -344,6 +345,32 @@ int32_t lv_scale_get_range_min_value(lv_obj_t * obj); */ int32_t lv_scale_get_range_max_value(lv_obj_t * obj); +/*===================== + * Other functions + *====================*/ + +#if LV_USE_OBSERVER + +/** + * Bind an integer subject to a scales section minimum value + * @param obj pointer to a Scale + * @param section pointer to a Scale section + * @param subject pointer to a Subject + * @return pointer to newly-created Observer + */ +lv_observer_t * lv_scale_bind_section_min_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject); + +/** + * Bind an integer subject to a scales section maximum value + * @param obj pointer to an Scale + * @param section pointer to a Scale section + * @param subject pointer to a Subject + * @return pointer to newly-created Observer + */ +lv_observer_t * lv_scale_bind_section_max_value(lv_obj_t * obj, lv_scale_section_t * section, lv_subject_t * subject); + +#endif + /********************** * MACROS **********************/ diff --git a/src/widgets/slider/lv_slider.c b/src/widgets/slider/lv_slider.c index 99a8c54d2d..89fe595d80 100644 --- a/src/widgets/slider/lv_slider.c +++ b/src/widgets/slider/lv_slider.c @@ -22,6 +22,7 @@ #include "../../stdlib/lv_string.h" #include "../../misc/lv_math.h" #include "../image/lv_image.h" +#include "../../others/observer/lv_observer_private.h" /********************* * DEFINES @@ -46,6 +47,11 @@ static bool is_slider_horizontal(lv_obj_t * obj); static void drag_start(lv_obj_t * obj); static void update_knob_pos(lv_obj_t * obj, bool check_drag); +#if LV_USE_OBSERVER + static void slider_value_changed_event_cb(lv_event_t * e); + static void slider_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif /*LV_USE_OBSERVER*/ + /********************** * STATIC VARIABLES **********************/ @@ -216,6 +222,25 @@ bool lv_slider_is_symmetrical(lv_obj_t * obj) return lv_bar_is_symmetrical(obj); } +#if LV_USE_OBSERVER +lv_observer_t * lv_slider_bind_value(lv_obj_t * obj, lv_subject_t * subject) +{ + LV_ASSERT_NULL(subject); + LV_ASSERT_NULL(obj); + + if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { + LV_LOG_WARN("Incompatible subject type: %d", subject->type); + return NULL; + } + + lv_obj_add_event_cb(obj, slider_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject); + + lv_observer_t * observer = lv_subject_add_observer_obj(subject, slider_value_observer_cb, obj, NULL); + return observer; +} +#endif /*LV_USE_OBSERVER*/ + + /********************** * STATIC FUNCTIONS **********************/ @@ -637,4 +662,37 @@ static void update_knob_pos(lv_obj_t * obj, bool check_drag) } } + +#if LV_USE_OBSERVER + +static void slider_value_changed_event_cb(lv_event_t * e) +{ + lv_obj_t * slider = lv_event_get_current_target(e); + lv_subject_t * subject = lv_event_get_user_data(e); + + 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) +{ + 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_OBSERVER*/ + + #endif diff --git a/src/widgets/slider/lv_slider.h b/src/widgets/slider/lv_slider.h index 90e68d251e..dee05ceb00 100644 --- a/src/widgets/slider/lv_slider.h +++ b/src/widgets/slider/lv_slider.h @@ -183,6 +183,17 @@ lv_slider_orientation_t lv_slider_get_orientation(lv_obj_t * slider); */ bool lv_slider_is_symmetrical(lv_obj_t * obj); + +#if LV_USE_OBSERVER +/** + * Bind an integer Subject to a Slider's value. + * @param obj pointer to Slider + * @param subject pointer to Subject + * @return pointer to newly-created Observer + */ +lv_observer_t * lv_slider_bind_value(lv_obj_t * obj, lv_subject_t * subject); +#endif + /********************** * MACROS **********************/ diff --git a/src/widgets/span/lv_span.c b/src/widgets/span/lv_span.c index 1f0dfa584d..554ac3f7b2 100644 --- a/src/widgets/span/lv_span.c +++ b/src/widgets/span/lv_span.c @@ -16,6 +16,7 @@ #include "../../misc/lv_assert.h" #include "../../misc/lv_text_private.h" #include "../../misc/lv_bidi_private.h" +#include "../../others/observer/lv_observer_private.h" #include "../../misc/lv_text_ap.h" #include "../../core/lv_global.h" @@ -43,6 +44,11 @@ struct _snippet_stack { uint32_t index; }; +typedef struct { + lv_subject_t * subject; + void * element; /**< span of a span group*/ + const char * fmt; +} bind_element_string_t; /********************** * STATIC PROTOTYPES **********************/ @@ -71,6 +77,9 @@ static int32_t convert_indent_pct(lv_obj_t * spans, int32_t width); static lv_span_coords_t make_span_coords(const lv_span_t * prev_span, const lv_span_t * curr_span, int32_t width, lv_area_t padding, int32_t indent); +#if LV_USE_OBSERVER + static void span_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject); +#endif /********************** * STATIC VARIABLES @@ -729,6 +738,54 @@ void lv_spangroup_refresh(lv_obj_t * obj) lv_obj_refresh_self_size(obj); } +#if LV_USE_OBSERVER +lv_observer_t * lv_spangroup_bind_span_text(lv_obj_t * obj, lv_span_t * span, lv_subject_t * subject, const char * fmt) +{ + LV_ASSERT_NULL(subject); + LV_ASSERT_NULL(obj); + LV_ASSERT_NULL(span); + + if(fmt == NULL) { + if(subject->type == LV_SUBJECT_TYPE_INT) { + 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) { + LV_LOG_WARN("Incompatible subject type: %d", subject->type); + return NULL; + } + } + else { + if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER && + subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { + LV_LOG_WARN("Incompatible subject type: %d", subject->type); + return NULL; + } + } + + bind_element_string_t * user_data = lv_zalloc(sizeof(bind_element_string_t)); + if(user_data == NULL) { + LV_LOG_WARN("Couldn't allocate user_data"); + LV_ASSERT_MALLOC(user_data); + return NULL; + } + + user_data->subject = subject; + user_data->element = span; + user_data->fmt = fmt; + + lv_observer_t * observer = lv_subject_add_observer_obj(subject, span_text_observer_cb, obj, user_data); + observer->auto_free_user_data = 1; + + return observer; +} +#endif /*LV_USE_OBSERVER*/ + + /********************** * STATIC FUNCTIONS **********************/ @@ -1398,4 +1455,36 @@ static lv_span_coords_t make_span_coords(const lv_span_t * prev_span, const lv_s return coords; } +#if LV_USE_OBSERVER + +static void span_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject) +{ + bind_element_string_t * user_data = observer->user_data; + + if(user_data->fmt == NULL) { + lv_spangroup_set_span_text(observer->target, user_data->element, subject->value.pointer); + } + else { + switch(subject->type) { + + case LV_SUBJECT_TYPE_INT: + lv_spangroup_set_span_text_fmt(observer->target, user_data->element, user_data->fmt, subject->value.num); + break; +#if LV_USE_FLOAT + case LV_SUBJECT_TYPE_FLOAT: + lv_spangroup_set_span_text_fmt(observer->target, user_data->element, user_data->fmt, subject->value.float_v); + break; +#endif + case LV_SUBJECT_TYPE_STRING: + case LV_SUBJECT_TYPE_POINTER: + lv_spangroup_set_span_text_fmt(observer->target, user_data->element, user_data->fmt, subject->value.pointer); + break; + default: + return; + } + } +} + +#endif /*LV_USE_OBSERVER*/ + #endif diff --git a/src/widgets/span/lv_span.h b/src/widgets/span/lv_span.h index 95f1599bbe..8e37b09087 100644 --- a/src/widgets/span/lv_span.h +++ b/src/widgets/span/lv_span.h @@ -15,6 +15,7 @@ extern "C" { *********************/ #include "../../lv_conf_internal.h" #include "../../core/lv_obj.h" +#include "../../others/observer/lv_observer.h" #if LV_USE_SPAN != 0 @@ -334,6 +335,24 @@ lv_span_t * lv_spangroup_get_span_by_point(lv_obj_t * obj, const lv_point_t * po */ void lv_spangroup_refresh(lv_obj_t * obj); +#if LV_USE_OBSERVER + +/** + * Bind an integer, string, or pointer Subject to a Spangroup's Span. + * @param obj pointer to Spangroup + * @param span pointer to Span + * @param subject pointer to Subject + * @param fmt optional printf-like format string with 1 format specifier (e.g. "%d °C") + * or NULL to bind to the value directly. + * @return pointer to newly-created Observer + * @note `fmt == NULL` can be used only with string and pointer Subjects. + * @note If `fmt == NULL` strings and pointers (`\0` terminated string) will be shown + * as text as they are, integers as %d, floats as %0.1f + */ +lv_observer_t * lv_spangroup_bind_span_text(lv_obj_t * obj, lv_span_t * span, lv_subject_t * subject, const char * fmt); + +#endif + /********************** * MACROS **********************/