diff --git a/src/widgets/lv_switch.c b/src/widgets/lv_switch.c index 7bc89512c..4362f8eb6 100644 --- a/src/widgets/lv_switch.c +++ b/src/widgets/lv_switch.c @@ -127,7 +127,7 @@ static void lv_switch_event(const lv_obj_class_t * class_p, lv_event_t * e) /*The smaller size is the knob diameter*/ lv_coord_t knob_size = LV_MAX4(knob_left, knob_right, knob_bottom, knob_top); - knob_size += 2; /*For rounding error*/ + knob_size += _LV_SWITCH_KNOB_EXT_AREA_CORRECTION; knob_size += lv_obj_calculate_ext_draw_size(obj, LV_PART_KNOB); lv_coord_t * s = lv_event_get_param(e); @@ -149,7 +149,6 @@ static void draw_main(lv_event_t * e) lv_switch_t * sw = (lv_switch_t *)obj; const lv_area_t * clip_area = lv_event_get_param(e); - lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN); /*Calculate the indicator area*/ lv_coord_t bg_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); @@ -172,29 +171,25 @@ static void draw_main(lv_event_t * e) lv_draw_rect(&indic_area, clip_area, &draw_indic_dsc); /*Draw the knob*/ - lv_coord_t objh = lv_obj_get_height(obj); - lv_coord_t knob_size = objh; - lv_area_t knob_area; - + lv_coord_t anim_value_x = 0; + lv_coord_t knob_size = lv_obj_get_height(obj); lv_coord_t anim_length = obj->coords.x2 - bg_right - obj->coords.x1 - bg_left - knob_size; - lv_coord_t anim_value_x; - - bool chk = lv_obj_get_state(obj) & LV_STATE_CHECKED; - 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(base_dir == LV_BASE_DIR_RTL) { + 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; knob_area.x1 = obj->coords.x1 + bg_left + anim_value_x; knob_area.x2 = knob_area.x1 + knob_size; diff --git a/src/widgets/lv_switch.h b/src/widgets/lv_switch.h index 624bf2a08..83ca81bc4 100644 --- a/src/widgets/lv_switch.h +++ b/src/widgets/lv_switch.h @@ -23,6 +23,9 @@ extern "C" { * DEFINES *********************/ +/** Switch knob extra area correction factor */ +#define _LV_SWITCH_KNOB_EXT_AREA_CORRECTION 2 + /********************** * TYPEDEFS **********************/ diff --git a/tests/src/test_cases/test_switch.c b/tests/src/test_cases/test_switch.c new file mode 100644 index 000000000..666849cde --- /dev/null +++ b/tests/src/test_cases/test_switch.c @@ -0,0 +1,139 @@ +#if LV_BUILD_TEST +#include "../lvgl.h" + +#include "unity/unity.h" + +#include "lv_test_indev.h" + +#define SWITCHES_CNT 10 + +uint8_t value_changed_event_cnt = 0; +lv_obj_t *scr = NULL; +lv_obj_t *sw = NULL; + +void setUp(void) +{ + /* Function run before every test */ + scr = lv_scr_act(); + sw = lv_switch_create(scr); +} + +void tearDown(void) +{ + /* Function run after every test */ + value_changed_event_cnt = 0; +} + +static void mouse_click_on_switch(void) +{ + lv_test_mouse_click_at(sw->coords.x1, sw->coords.y1); +} + +static void event_handler(lv_event_t *e) +{ + lv_event_code_t event = lv_event_get_code(e); + + if (LV_EVENT_VALUE_CHANGED == event) { + value_changed_event_cnt++; + } + +} + +void test_switch_should_have_default_state_after_being_created(void) +{ + lv_state_t state = lv_obj_get_state(sw); + TEST_ASSERT_EQUAL(state, LV_STATE_DEFAULT); +} + +void test_switch_should_not_leak_memory_after_deletion(void) +{ + size_t idx = 0; + uint32_t initial_available_memory = 0; + uint32_t final_available_memory = 0; + lv_mem_monitor_t monitor; + lv_obj_t *switches[SWITCHES_CNT] = {NULL}; + + lv_mem_monitor(&monitor); + initial_available_memory = monitor.free_size; + + for (idx = 0; idx < SWITCHES_CNT; idx++) { + switches[idx] = lv_switch_create(scr); + } + + for (idx = 0; idx < SWITCHES_CNT; idx++) { + lv_obj_del(switches[idx]); + } + + lv_mem_monitor(&monitor); + final_available_memory = monitor.free_size; + + TEST_ASSERT_LESS_THAN(initial_available_memory, final_available_memory); +} + +void test_switch_animation(void) +{ + lv_switch_t * anim_sw = (lv_switch_t *) sw; + int32_t initial_anim_state = anim_sw->anim_state; + + /* Trigger animation */ + mouse_click_on_switch(); + /* Wait some time */ + lv_test_indev_wait(50); + + int32_t checked_anim_state = anim_sw->anim_state; + TEST_ASSERT_GREATER_THAN(initial_anim_state, checked_anim_state); + TEST_ASSERT(lv_obj_has_state(sw, LV_STATE_CHECKED)); + + mouse_click_on_switch(); + lv_test_indev_wait(50); + + TEST_ASSERT_LESS_THAN(checked_anim_state, anim_sw->anim_state); + TEST_ASSERT_FALSE(lv_obj_has_state(sw, LV_STATE_CHECKED)); +} + +void test_switch_should_not_have_extra_draw_size_at_creation(void) +{ + lv_coord_t extra_size = _lv_obj_get_ext_draw_size(sw); + + TEST_ASSERT_EQUAL(0, extra_size); +} + +void test_switch_should_update_extra_draw_size_after_editing_padding(void) +{ + lv_coord_t pad = 6; + lv_coord_t actual = 0; + lv_coord_t expected = pad + _LV_SWITCH_KNOB_EXT_AREA_CORRECTION; + + static lv_style_t style_knob; + lv_style_init(&style_knob); + lv_style_set_pad_all(&style_knob, pad); + + lv_obj_remove_style_all(sw); + lv_obj_add_style(sw, &style_knob, LV_PART_KNOB); + lv_obj_center(sw); + + /* Get extra draw size */ + actual = _lv_obj_get_ext_draw_size(sw); + + TEST_ASSERT_EQUAL(expected, actual); +} + +/* See #2330 for context */ +void test_switch_should_trigger_value_changed_event_only_once(void) +{ + lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL); + mouse_click_on_switch(); + + TEST_ASSERT_EQUAL(1, value_changed_event_cnt); +} + +/* See #2785 for context */ +void test_switch_should_state_change_when_event_bubbling_is_enabled(void) +{ + lv_obj_add_flag(sw, LV_OBJ_FLAG_EVENT_BUBBLE); + mouse_click_on_switch(); + + TEST_ASSERT(lv_obj_has_state(sw, LV_STATE_CHECKED)); +} + +#endif