diff --git a/docs/src/details/auxiliary-modules/observer/observer.rst b/docs/src/details/auxiliary-modules/observer/observer.rst index bbdfcab2a7..3b75c69ee7 100644 --- a/docs/src/details/auxiliary-modules/observer/observer.rst +++ b/docs/src/details/auxiliary-modules/observer/observer.rst @@ -497,26 +497,33 @@ This will toggle `subject1` between 0 and 1 each time `button1` is clicked. Increment ~~~~~~~~~ -:cpp:expr:`lv_obj_add_subject_increment_event(obj, subject, trigger, step, rollover)` -increments an integer subject's value by `step`. +:cpp:expr:`lv_obj_add_subject_increment_event(obj, subject, trigger, step)` +increments an integer subject's value by ``step``. -It works on both integer and float subject. +It returns a :cpp:type:`lv_subject_increment_dsc_t` pointer to configure the +event further: -``rollover`` can be ``true`` or ``false``. If ``true`` and the subject's minimum or maximum -value is exceeded, the other end value is set. That is, going beyond -the maximum value sets the minimum value, and vice versa. +- :cpp:expr:`lv_obj_set_subject_increment_event_min_value(obj, dsc, min_value)`: + Set a minimum value for the event. Default ``INT32_MIN`` +- :cpp:expr:`lv_obj_set_subject_increment_event_max_value(obj, dsc, max_value)`: + Set a maximum value for the event. Default ``INT32_MAX`` +- :cpp:expr:`lv_obj_set_subject_increment_event_rollover(obj, dsc, rollover)`: + Set what to do when the min/max value is crossed. ``false``: stop at the min/max + value; ``true``: jump to the other end. Default ``false`` -Using a negative `step` will decrement the value instead. +It works on both integer and float subjects, but the min/max value is an integer in both cases. +If the subject also sets a min/max value the narrower range will be used. + +Using a negative ``step`` will decrement the value instead. For example: -:cpp:expr:`lv_obj_add_subject_increment_event(button1, subject1, LV_EVENT_CLICKED, 5, false)` - -This will increment `subject1` by 5 when `button1` is clicked, stopping at the limits set by -:cpp:expr:`lv_subject_set_min_value_int()` and :cpp:expr:`lv_subject_set_max_value_int()` -(same for float subjects). +:cpp:expr:`lv_obj_add_subject_increment_event(button1, subject1, LV_EVENT_CLICKED, 5)` +This will increment ``subject1`` by 5 when ``button1`` is clicked, stopping at the limits +set by the min/max values of the event or :cpp:expr:`lv_subject_set_min_value_int()` +and :cpp:expr:`lv_subject_set_max_value_int()` (same for float subjects). Set to a Value ~~~~~~~~~~~~~~ diff --git a/docs/src/details/xml/features/subjects.rst b/docs/src/details/xml/features/subjects.rst index e6ca7ad187..1c3972bc06 100644 --- a/docs/src/details/xml/features/subjects.rst +++ b/docs/src/details/xml/features/subjects.rst @@ -80,3 +80,12 @@ Explanation of complex bindings: - ```` — Set a state if the subject's value is **less than or equal to** the reference value. Note: The ``lv_obj-`` prefix can be omitted. For example, you can simply write ```` instead. + +Subject Related Events +********************** + +Besides binding properties to subjects, it's also possible to add events the change the value +of a subject on pressed, release, etc. + +Learn more about these in :ref:`xml_events_set_subject_value` and +:ref:`xml_events_increment_subject_value`. diff --git a/docs/src/details/xml/ui_elements/events.rst b/docs/src/details/xml/ui_elements/events.rst index bf75f06414..fc3e8edbb9 100644 --- a/docs/src/details/xml/ui_elements/events.rst +++ b/docs/src/details/xml/ui_elements/events.rst @@ -20,7 +20,7 @@ All LVGL event types are supported with straightforward mapping: - :cpp:enumerator:`LV_EVENT_PRESSED`: ``"pressed"`` - etc. -Call function +Call Function ************* User-defined functions can be called like this: @@ -108,7 +108,9 @@ This is a simple example of both load and create: lv_obj_t * screen1 = lv_xml_create(NULL, "screen1", NULL); lv_screen_load(screen1); -Set subject value +.. _xml_events_set_subject_value: + +Set Subject Value ***************** It's possible to set a :ref:`Subject ` value on user interaction by adding a special child to any widget: @@ -126,7 +128,10 @@ It's possible to set a :ref:`Subject ` value on user interacti The usage is straightforward: the specified ``subject`` will be set to the given ``value`` when the ``trigger`` occurs. -Increment subject value + +.. _xml_events_increment_subject_value: + +Increment Subject Value *********************** Incrementing or decrementing a :ref:`Subject ` value can be defined as follows: @@ -136,18 +141,21 @@ Incrementing or decrementing a :ref:`Subject ` value can be de - + The ```` element defines a ``step`` to be added to the subject's current value -when the ``trigger`` occurs. Optionally, ``min`` and/or ``max`` can be set to limit the subject's value. +when the ``trigger`` occurs. ``subject`` must be an ``int`` or ``float`` subject. If ``step`` is **negative**, the subject's value will be decremented. Only integer ``step`` values are supported now. -**Note:** Only integer subjects are supported by ````. +Optionally, ``min_value`` and/or ``max_value`` can be set to limit the subject's value. +The default min/max values are ``INT32_MIN`` (-2B) and ``INT32_MAX`` (+2B) respectively. +``rollover`` is also an optional property. If it's ``false`` (default) stop at the +min/max value, if ``true`` jump to the other end. diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index f0e5384f4c..7b00fbf5d1 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -282,6 +282,8 @@ typedef struct _lv_gltf_model_t lv_gltf_model_t; typedef struct _lv_observer_t lv_observer_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_ime_pinyin_t lv_ime_pinyin_t; diff --git a/src/others/observer/lv_observer.c b/src/others/observer/lv_observer.c index 1cb34ca913..955a661a0c 100644 --- a/src/others/observer/lv_observer.c +++ b/src/others/observer/lv_observer.c @@ -59,12 +59,6 @@ typedef struct { const char * value; } subject_set_string_user_data_t; -typedef struct { - lv_subject_t * subject; - int32_t step; - bool rollover; -} subject_increment_user_data_t; - /********************** * STATIC PROTOTYPES **********************/ @@ -576,26 +570,91 @@ void lv_subject_notify(lv_subject_t * subject) } while(subject->notify_restart_query); } -void lv_obj_add_subject_increment_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger, int32_t step, - bool rollover) +lv_subject_increment_dsc_t * lv_obj_add_subject_increment_event(lv_obj_t * obj, lv_subject_t * subject, + lv_event_code_t trigger, int32_t step) { if(subject->type != LV_SUBJECT_TYPE_INT && subject->type != LV_SUBJECT_TYPE_FLOAT) { LV_LOG_WARN("Subject type must be `int` or `float` (was %d)", subject->type); - return; + return NULL; } - subject_increment_user_data_t * user_data = lv_malloc(sizeof(subject_increment_user_data_t)); + lv_subject_increment_dsc_t * user_data = lv_malloc(sizeof(lv_subject_increment_dsc_t)); if(user_data == NULL) { LV_ASSERT_MALLOC(user_data); LV_LOG_WARN("Couldn't allocate user_data in in "); - return; + return NULL; } user_data->step = step; user_data->subject = subject; - user_data->rollover = rollover; + user_data->rollover = false; + user_data->min_value = INT32_MIN; + user_data->max_value = INT32_MAX; lv_obj_add_event_cb(obj, subject_increment_cb, trigger, user_data); lv_obj_add_event_cb(obj, lv_event_free_user_data_cb, LV_EVENT_DELETE, user_data); + + return user_data; +} + +void lv_obj_set_subject_increment_event_min_value(lv_obj_t * obj, lv_subject_increment_dsc_t * dsc, int32_t min_value) +{ + LV_UNUSED(obj); + LV_ASSERT_NULL(dsc); + if(dsc == NULL) { + LV_LOG_WARN("Invalid parameters"); + return; + } + + dsc->min_value = min_value; + if(dsc->subject->type == LV_SUBJECT_TYPE_INT) { + if(dsc->subject->value.num < min_value) { + lv_subject_set_int(dsc->subject, min_value); + } + } +#if LV_USE_FLOAT + else if(dsc->subject->type == LV_SUBJECT_TYPE_FLOAT) { + if(dsc->subject->value.float_v < (float)min_value) { + lv_subject_set_float(dsc->subject, (float)min_value); + } + } +#endif +} + +void lv_obj_set_subject_increment_event_max_value(lv_obj_t * obj, lv_subject_increment_dsc_t * dsc, int32_t max_value) +{ + LV_UNUSED(obj); + LV_ASSERT_NULL(dsc); + if(dsc == NULL) { + LV_LOG_WARN("Invalid parameters"); + return; + } + + + dsc->max_value = max_value; + if(dsc->subject->type == LV_SUBJECT_TYPE_INT) { + if(dsc->subject->value.num > max_value) { + lv_subject_set_int(dsc->subject, max_value); + } + } +#if LV_USE_FLOAT + else if(dsc->subject->type == LV_SUBJECT_TYPE_FLOAT) { + if(dsc->subject->value.float_v > (float)max_value) { + lv_subject_set_float(dsc->subject, (float)max_value); + } + } +#endif +} + +void lv_obj_set_subject_increment_event_rollover(lv_obj_t * obj, lv_subject_increment_dsc_t * dsc, bool rollover) +{ + LV_UNUSED(obj); + LV_ASSERT_NULL(dsc); + if(dsc == NULL) { + LV_LOG_WARN("Invalid parameters"); + return; + } + + dsc->rollover = rollover; } void lv_obj_add_subject_toggle_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger) @@ -849,43 +908,57 @@ static void subject_set_string_cb(lv_event_t * e) static void subject_increment_cb(lv_event_t * e) { - subject_increment_user_data_t * user_data = lv_event_get_user_data(e); + lv_subject_increment_dsc_t * user_data = lv_event_get_user_data(e); if(user_data->subject->type == LV_SUBJECT_TYPE_INT) { + /*Use the smaller range*/ + int32_t max_value = LV_MIN(user_data->max_value, user_data->subject->max_value.num); + int32_t min_value = LV_MAX(user_data->min_value, user_data->subject->min_value.num); + int32_t value = lv_subject_get_int(user_data->subject); value += user_data->step; if(user_data->rollover) { - if(value > user_data->subject->max_value.num) { - value = user_data->subject->min_value.num; + if(value > max_value) { + value = min_value; } - else if(value < user_data->subject->min_value.num) { - value = user_data->subject->max_value.num; + else if(value < min_value) { + value = max_value; } } + else { + value = LV_CLAMP(min_value, value, max_value); + } lv_subject_set_int(user_data->subject, value); } #if LV_USE_FLOAT else if(user_data->subject->type == LV_SUBJECT_TYPE_FLOAT) { + /*Use the smaller range*/ + float max_value = LV_MIN((float)user_data->max_value, user_data->subject->max_value.float_v); + float min_value = LV_MAX((float)user_data->min_value, user_data->subject->min_value.float_v); + + float value = lv_subject_get_float(user_data->subject); + value += (float)user_data->step; if(user_data->rollover) { - if(value > user_data->subject->max_value.float_v) { - value = user_data->subject->min_value.float_v; + if(value > max_value) { + value = min_value; } - else if(value < user_data->subject->min_value.float_v) { - value = user_data->subject->max_value.float_v; + else if(value < min_value) { + value = max_value; } } + else { + value = LV_CLAMP(min_value, value, max_value); + } - value += (float)user_data->step; lv_subject_set_float(user_data->subject, value); } #endif } - static void group_notify_cb(lv_observer_t * observer, lv_subject_t * subject) { LV_UNUSED(subject); diff --git a/src/others/observer/lv_observer.h b/src/others/observer/lv_observer.h index 735cf307a3..4881b64a87 100644 --- a/src/others/observer/lv_observer.h +++ b/src/others/observer/lv_observer.h @@ -379,19 +379,43 @@ void lv_subject_notify(lv_subject_t * subject); * @param subject pointer to a subject to change * @param trigger the trigger on which the subject should be changed * @param step value to add on trigger - * @param rollover if true and the subject's maximum value is exceeded the minimum value is set, * if the minimum value is reached, the maximum value will be set on rollover. */ -void lv_obj_add_subject_increment_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger, int32_t step, - bool rollover); +lv_subject_increment_dsc_t * lv_obj_add_subject_increment_event(lv_obj_t * obj, lv_subject_t * subject, + lv_event_code_t trigger, int32_t step); /** - * Toggle the value of an integer subject on an event. If it was != 0 it will be 0. - * If it was 0, it will be 1. - * @param obj pointer to a widget - * @param subject pointer to a subject to toggle - * @param trigger the trigger on which the subject should be changed + * Set the minimum subject value to set by the event + * @param obj pointer to the Widget to which the event is attached + * @param dsc pointer to the descriptor returned by `lv_obj_add_subject_increment_event()` + * @param min_value the minimum value to set */ +void lv_obj_set_subject_increment_event_min_value(lv_obj_t * obj, lv_subject_increment_dsc_t * dsc, int32_t min_value); + +/** + * Set the maximum subject value to set by the event + * @param obj pointer to the Widget to which the event is attached + * @param dsc pointer to the descriptor returned by `lv_obj_add_subject_increment_event()` + * @param max_value the maximum value to set + */ +void lv_obj_set_subject_increment_event_max_value(lv_obj_t * obj, lv_subject_increment_dsc_t * dsc, int32_t max_value); + +/** + * Set what to do when the min/max value is crossed. + * @param obj pointer to the Widget to which the event is attached + * @param dsc pointer to the descriptor returned by `lv_obj_add_subject_increment_event()` + * @param rollover false: stop at the min/max value; true: jump to the other end + * @note the subject also can have min/max values and always the smaller range will be considered + */ +void lv_obj_set_subject_increment_event_rollover(lv_obj_t * obj, lv_subject_increment_dsc_t * dsc, bool rollover); + +/** +* Toggle the value of an integer subject on an event. If it was != 0 it will be 0. +* If it was 0, it will be 1. +* @param obj pointer to a widget +* @param subject pointer to a subject to toggle +* @param trigger the trigger on which the subject should be changed +*/ void lv_obj_add_subject_toggle_event(lv_obj_t * obj, lv_subject_t * subject, lv_event_code_t trigger); /** diff --git a/src/others/observer/lv_observer_private.h b/src/others/observer/lv_observer_private.h index d62d1f663f..6f6cd89f2b 100644 --- a/src/others/observer/lv_observer_private.h +++ b/src/others/observer/lv_observer_private.h @@ -39,6 +39,16 @@ struct _lv_observer_t { uint32_t for_obj : 1; /**< Is `target` a pointer to a Widget (`lv_obj_t *`)? */ }; +/** + * Descriptor created by `lv_obj_add_subject_increment_event()` + */ +struct _lv_subject_increment_dsc_t { + lv_subject_t * subject; /**< The subject to adjust*/ + int32_t step; /**< The step add to the subject */ + bool rollover; /**< Where to start over from the other end when one end is exceeded*/ + int32_t min_value; /**< Don't set a value smaller than this */ + int32_t max_value; /**< Don't set a value larger than this */ +}; /********************** * GLOBAL PROTOTYPES diff --git a/src/others/xml/parsers/lv_xml_obj_parser.c b/src/others/xml/parsers/lv_xml_obj_parser.c index 645fe82edb..79fef67a07 100644 --- a/src/others/xml/parsers/lv_xml_obj_parser.c +++ b/src/others/xml/parsers/lv_xml_obj_parser.c @@ -404,6 +404,8 @@ void lv_obj_xml_subject_increment_apply(lv_xml_parser_state_t * state, const cha const char * subject_str = lv_xml_get_value_of(attrs, "subject"); const char * trigger_str = lv_xml_get_value_of(attrs, "trigger"); const char * step_str = lv_xml_get_value_of(attrs, "step"); + const char * min_value_str = lv_xml_get_value_of(attrs, "min_value"); + const char * max_value_str = lv_xml_get_value_of(attrs, "max_value"); const char * rollover_str = lv_xml_get_value_of(attrs, "rollover"); if(subject_str == NULL) { @@ -435,8 +437,11 @@ void lv_obj_xml_subject_increment_apply(lv_xml_parser_state_t * state, const cha void * item = lv_xml_state_get_item(state); int32_t step = lv_xml_atoi(step_str); - bool rollover = lv_xml_to_bool(rollover_str); - lv_obj_add_subject_increment_event(item, subject, trigger, step, rollover); + lv_subject_increment_dsc_t * dsc = lv_obj_add_subject_increment_event(item, subject, trigger, step); + + if(min_value_str) lv_obj_set_subject_increment_event_min_value(item, dsc, lv_xml_atoi(min_value_str)); + if(max_value_str) lv_obj_set_subject_increment_event_max_value(item, dsc, lv_xml_atoi(max_value_str)); + if(rollover_str) lv_obj_set_subject_increment_event_rollover(item, dsc, lv_xml_to_bool(rollover_str)); } void * lv_obj_xml_bind_style_create(lv_xml_parser_state_t * state, const char ** attrs) diff --git a/xmls/lv_obj.xml b/xmls/lv_obj.xml index 49bc063ecd..1cec1b2977 100644 --- a/xmls/lv_obj.xml +++ b/xmls/lv_obj.xml @@ -113,33 +113,35 @@ Example - + - + + + - + - + - + - + @@ -151,7 +153,7 @@ Example - +