From a37f84f34ce82ac5e924d603181a7fb13e6df8b1 Mon Sep 17 00:00:00 2001 From: lizhaoming19980614 <159675538+lizhaoming19980614@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:04:51 +0800 Subject: [PATCH] feat(switch): add vertical switch function (#6786) Co-authored-by: lizhaoming <13678462+lizhao-ming@user.noreply.gitee.com> Co-authored-by: 100ask Co-authored-by: Gabor Kiss-Vamosi --- docs/widgets/switch.rst | 8 ++ examples/widgets/lv_example_widgets.h | 1 + examples/widgets/switch/index.rst | 7 ++ examples/widgets/switch/lv_example_switch_2.c | 32 ++++++ src/widgets/switch/lv_switch.c | 106 ++++++++++++++---- src/widgets/switch/lv_switch.h | 32 ++++++ src/widgets/switch/lv_switch_private.h | 1 + tests/ref_imgs/widgets/switch_1.png | Bin 0 -> 7412 bytes tests/src/test_cases/widgets/test_switch.c | 29 +++++ 9 files changed, 196 insertions(+), 20 deletions(-) create mode 100644 examples/widgets/switch/lv_example_switch_2.c create mode 100644 tests/ref_imgs/widgets/switch_1.png diff --git a/docs/widgets/switch.rst b/docs/widgets/switch.rst index 4b0c445bf..938b48873 100644 --- a/docs/widgets/switch.rst +++ b/docs/widgets/switch.rst @@ -10,6 +10,8 @@ Overview The Switch looks like a little slider and can be used to turn something on and off. +Vertical Switch can be created if the width of the object is smaller than its height. + .. _lv_switch_parts_and_styles: Parts and Styles @@ -43,6 +45,12 @@ To get the current state of the switch (with ``true`` being on), use Call :cpp:expr:`lv_obj_add_state(obj, LV_STATE_CHECKED)` to turn it on, or :cpp:expr:`lv_obj_remove_state(obj, LV_STATE_CHECKED)` to turn it off. +Change orientation +------------------ + +:cpp:expr:`lv_switch_set_orientation(obj, LV_SWITCH_ORIENTATION_VERTICAL)` change orientation, default orientation is :cpp:enumerator:`LV_SWITCH_ORIENTATION_AUTO`, adaptive based on the width and height of the object. + + .. _lv_switch_events: Events diff --git a/examples/widgets/lv_example_widgets.h b/examples/widgets/lv_example_widgets.h index 8b4848d17..a52ed9016 100644 --- a/examples/widgets/lv_example_widgets.h +++ b/examples/widgets/lv_example_widgets.h @@ -136,6 +136,7 @@ void lv_example_spinbox_1(void); void lv_example_spinner_1(void); void lv_example_switch_1(void); +void lv_example_switch_2(void); void lv_example_table_1(void); void lv_example_table_2(void); diff --git a/examples/widgets/switch/index.rst b/examples/widgets/switch/index.rst index 07ee12670..060102614 100644 --- a/examples/widgets/switch/index.rst +++ b/examples/widgets/switch/index.rst @@ -5,3 +5,10 @@ Simple Switch .. lv_example:: widgets/switch/lv_example_switch_1 :language: c + +Switch Orientation +------------------- + +.. lv_example:: widgets/switch/lv_example_switch_2 + :language: c + diff --git a/examples/widgets/switch/lv_example_switch_2.c b/examples/widgets/switch/lv_example_switch_2.c new file mode 100644 index 000000000..1e3512fc9 --- /dev/null +++ b/examples/widgets/switch/lv_example_switch_2.c @@ -0,0 +1,32 @@ +#include "../../lv_examples.h" +#if LV_USE_SWITCH && LV_BUILD_EXAMPLES + +static void event_handler(lv_event_t * e) +{ + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t * obj = lv_event_get_target(e); + if(code == LV_EVENT_VALUE_CHANGED) { + LV_UNUSED(obj); + LV_LOG_USER("State: %s\n", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "On" : "Off"); + } +} + +void lv_example_switch_2(void) +{ + lv_obj_set_flex_flow(lv_screen_active(), LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(lv_screen_active(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + + lv_obj_t * sw; + + sw = lv_switch_create(lv_screen_active()); + lv_obj_set_size(sw, 30, 60); + lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL); + + sw = lv_switch_create(lv_screen_active()); + lv_obj_set_size(sw, 30, 60); + lv_switch_set_orientation(sw, LV_SWITCH_ORIENTATION_VERTICAL); + lv_obj_add_state(sw, LV_STATE_CHECKED); + lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL); +} + +#endif diff --git a/src/widgets/switch/lv_switch.c b/src/widgets/switch/lv_switch.c index 89b4b6363..6603f20c8 100644 --- a/src/widgets/switch/lv_switch.c +++ b/src/widgets/switch/lv_switch.c @@ -49,6 +49,7 @@ static void draw_main(lv_event_t * e); static void lv_switch_anim_exec_cb(void * sw, int32_t value); static void lv_switch_trigger_anim(lv_obj_t * obj); static void lv_switch_anim_completed(lv_anim_t * a); + /********************** * STATIC VARIABLES **********************/ @@ -80,6 +81,31 @@ lv_obj_t * lv_switch_create(lv_obj_t * parent) return obj; } +/*===================== + * Setter functions + *====================*/ + +void lv_switch_set_orientation(lv_obj_t * obj, lv_switch_orientation_t orientation) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + lv_switch_t * sw = (lv_switch_t *)obj; + + sw->orientation = orientation; + lv_obj_invalidate(obj); +} + +/*===================== + * Getter functions + *====================*/ + +lv_switch_orientation_t lv_switch_get_orientation(lv_obj_t * obj) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + lv_switch_t * sw = (lv_switch_t *)obj; + + return sw->orientation; +} + /********************** * STATIC FUNCTIONS **********************/ @@ -92,6 +118,7 @@ static void lv_switch_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj lv_switch_t * sw = (lv_switch_t *)obj; sw->anim_state = LV_SWITCH_ANIM_STATE_INV; + sw->orientation = LV_SWITCH_ORIENTATION_AUTO; lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE); lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE); @@ -163,28 +190,67 @@ static void draw_main(lv_event_t * e) lv_draw_rect(layer, &draw_indic_dsc, &indic_area); /*Draw the knob*/ - int32_t anim_value_x = 0; - int32_t knob_size = lv_obj_get_height(obj); - int32_t anim_length = lv_area_get_width(&obj->coords) - knob_size; - - if(LV_SWITCH_IS_ANIMATING(sw)) { - /* Use the animation's coordinate */ - anim_value_x = (anim_length * sw->anim_state) / LV_SWITCH_ANIM_STATE_END; - } - else { - /* Use LV_STATE_CHECKED to decide the coordinate */ - bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED; - anim_value_x = chk ? anim_length : 0; - } - - if(LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN)) { - anim_value_x = anim_length - anim_value_x; - } - lv_area_t knob_area; lv_area_copy(&knob_area, &obj->coords); - knob_area.x1 += anim_value_x; - knob_area.x2 = knob_area.x1 + (knob_size > 0 ? knob_size - 1 : 0); + + int32_t switch_w = lv_area_get_width(&obj->coords); + int32_t switch_h = lv_area_get_height(&obj->coords); + bool hor = false; + + switch(sw->orientation) { + case LV_SWITCH_ORIENTATION_HORIZONTAL: + hor = true; + break; + case LV_SWITCH_ORIENTATION_VERTICAL: + hor = false; + break; + case LV_SWITCH_ORIENTATION_AUTO: + default: + hor = (switch_w >= switch_h); + break; + } + + if(hor) { + int32_t anim_value_x = 0; + int32_t knob_size = lv_obj_get_height(obj); + int32_t anim_length = lv_area_get_width(&obj->coords) - knob_size; + if(LV_SWITCH_IS_ANIMATING(sw)) { + /* Use the animation's coordinate */ + anim_value_x = (anim_length * sw->anim_state) / LV_SWITCH_ANIM_STATE_END; + } + else { + /* Use LV_STATE_CHECKED to decide the coordinate */ + bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED; + anim_value_x = chk ? anim_length : 0; + } + + if(LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN)) { + anim_value_x = anim_length - anim_value_x; + } + knob_area.x1 += anim_value_x; + knob_area.x2 = knob_area.x1 + (knob_size > 0 ? knob_size - 1 : 0); + } + else { + int32_t anim_value_y = 0; + int32_t knob_size = lv_obj_get_width(obj); + int32_t anim_length = lv_area_get_height(&obj->coords) - knob_size; + if(LV_SWITCH_IS_ANIMATING(sw)) { + /* Use the animation's coordinate */ + anim_value_y = (anim_length * sw->anim_state) / LV_SWITCH_ANIM_STATE_END; + } + else { + /* Use LV_STATE_CHECKED to decide the coordinate */ + bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED; + anim_value_y = chk ? anim_length : 0; + } + + if(LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN)) { + anim_value_y = anim_length - anim_value_y; + } + + knob_area.y2 -= anim_value_y; + knob_area.y1 = knob_area.y2 - (knob_size > 0 ? knob_size - 1 : 0); + } int32_t knob_left = lv_obj_get_style_pad_left(obj, LV_PART_KNOB); int32_t knob_right = lv_obj_get_style_pad_right(obj, LV_PART_KNOB); diff --git a/src/widgets/switch/lv_switch.h b/src/widgets/switch/lv_switch.h index 989a3dd1b..3cc0d2846 100644 --- a/src/widgets/switch/lv_switch.h +++ b/src/widgets/switch/lv_switch.h @@ -28,6 +28,16 @@ extern "C" { LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_switch_class; +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_SWITCH_ORIENTATION_AUTO, + LV_SWITCH_ORIENTATION_HORIZONTAL, + LV_SWITCH_ORIENTATION_VERTICAL +} lv_switch_orientation_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -39,6 +49,28 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_switch_class; */ lv_obj_t * lv_switch_create(lv_obj_t * parent); +/*===================== + * Setter functions + *====================*/ + +/** + * Set the orientation of switch. + * @param obj pointer to switch object + * @param orientation switch orientation from `lv_switch_orientation_t` + */ +void lv_switch_set_orientation(lv_obj_t * obj, lv_switch_orientation_t orientation); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the orientation of switch. + * @param obj pointer to switch object + * @return switch orientation from ::lv_switch_orientation_t + */ +lv_switch_orientation_t lv_switch_get_orientation(lv_obj_t * obj); + /********************** * MACROS **********************/ diff --git a/src/widgets/switch/lv_switch_private.h b/src/widgets/switch/lv_switch_private.h index f7bf77e97..66e90d324 100644 --- a/src/widgets/switch/lv_switch_private.h +++ b/src/widgets/switch/lv_switch_private.h @@ -34,6 +34,7 @@ extern "C" { struct _lv_switch_t { lv_obj_t obj; int32_t anim_state; + lv_switch_orientation_t orientation : 3; /**< Orientation of switch*/ }; diff --git a/tests/ref_imgs/widgets/switch_1.png b/tests/ref_imgs/widgets/switch_1.png new file mode 100644 index 0000000000000000000000000000000000000000..108009aee22ed75df5f844f5fd0bbb8b58578b88 GIT binary patch literal 7412 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 aBU+h$$XJ#Zbq(HTqDVG&-xOGTeD@Fb*lu