diff --git a/src/widgets/roller/lv_roller.c b/src/widgets/roller/lv_roller.c index 9f84e6c23f..3a3d627537 100644 --- a/src/widgets/roller/lv_roller.c +++ b/src/widgets/roller/lv_roller.c @@ -329,7 +329,7 @@ static void lv_roller_event(const lv_obj_class_t * class_p, lv_event_t * e) res = lv_obj_event_base(MY_CLASS, e); if(res != LV_RES_OK) return; - lv_event_code_t code = lv_event_get_code(e); + const lv_event_code_t code = lv_event_get_code(e); lv_obj_t * obj = lv_event_get_target(e); lv_roller_t * roller = (lv_roller_t *)obj; @@ -366,26 +366,27 @@ static void lv_roller_event(const lv_obj_class_t * class_p, lv_event_t * e) } else if(code == LV_EVENT_FOCUSED) { lv_group_t * g = lv_obj_get_group(obj); - bool editing = lv_group_get_editing(g); lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act()); /*Encoders need special handling*/ if(indev_type == LV_INDEV_TYPE_ENCODER) { - /*In navigate mode revert the original value*/ - if(!editing) { + const bool editing = lv_group_get_editing(g); + + /*Save the current state when entered to edit mode*/ + if(editing) { + roller->sel_opt_id_ori = roller->sel_opt_id; + } + else { /*In navigate mode revert the original value*/ if(roller->sel_opt_id != roller->sel_opt_id_ori) { roller->sel_opt_id = roller->sel_opt_id_ori; refr_position(obj, LV_ANIM_ON); } } - /*Save the current state when entered to edit mode*/ - else { - roller->sel_opt_id_ori = roller->sel_opt_id; - } } else { - roller->sel_opt_id_ori = roller->sel_opt_id; /*Save the current value. Used to revert this state if - ENTER won't be pressed*/ + /*Save the current value. Used to revert this + *state if ENTER won't be pressed*/ + roller->sel_opt_id_ori = roller->sel_opt_id; } } else if(code == LV_EVENT_DEFOCUSED) { @@ -407,7 +408,6 @@ static void lv_roller_event(const lv_obj_class_t * class_p, lv_event_t * e) else if(c == LV_KEY_LEFT || c == LV_KEY_UP) { if(roller->sel_opt_id > 0) { uint16_t ori_id = roller->sel_opt_id_ori; /*lv_roller_set_selected will overwrite this*/ - lv_roller_set_selected(obj, roller->sel_opt_id - 1, LV_ANIM_ON); roller->sel_opt_id_ori = ori_id; } @@ -597,45 +597,50 @@ static void get_sel_area(lv_obj_t * obj, lv_area_t * sel_area) /** * Refresh the position of the roller. It uses the id stored in: roller->ddlist.selected_option_id * @param roller pointer to a roller object - * @param anim_en LV_ANIM_ON: refresh with animation; LV_ANOM_OFF: without animation + * @param anim_en LV_ANIM_ON: refresh with animation; LV_ANIM_OFF: without animation */ static void refr_position(lv_obj_t * obj, lv_anim_enable_t anim_en) { lv_obj_t * label = get_label(obj); if(label == NULL) return; - lv_text_align_t align = lv_obj_calculate_style_text_align(label, LV_PART_MAIN, lv_label_get_text(label)); + const lv_text_align_t align = lv_obj_calculate_style_text_align(label, LV_PART_MAIN, lv_label_get_text(label)); + lv_coord_t x = 0; switch(align) { case LV_TEXT_ALIGN_CENTER: - lv_obj_set_x(label, (lv_obj_get_content_width(obj) - lv_obj_get_width(label)) / 2); + x = (lv_obj_get_content_width(obj) - lv_obj_get_width(label)) / 2; break; case LV_TEXT_ALIGN_RIGHT: - lv_obj_set_x(label, lv_obj_get_content_width(obj) - lv_obj_get_width(label)); + x = lv_obj_get_content_width(obj) - lv_obj_get_width(label); break; case LV_TEXT_ALIGN_LEFT: - lv_obj_set_x(label, 0); + x = 0; + break; + default: + /* Invalid alignment */ break; } + lv_obj_set_x(label, x); - lv_roller_t * roller = (lv_roller_t *)obj; const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN); - lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); - lv_coord_t font_h = lv_font_get_line_height(font); - lv_coord_t h = lv_obj_get_content_height(obj); - uint16_t anim_time = lv_obj_get_style_anim_time(obj, LV_PART_MAIN); + const lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); + const lv_coord_t font_h = lv_font_get_line_height(font); + const lv_coord_t h = lv_obj_get_content_height(obj); + uint16_t anim_time = lv_obj_get_style_anim_time(obj, LV_PART_MAIN); /*Normally the animation's `end_cb` sets correct position of the roller if infinite. - *But without animations do it manually*/ + *But without animations we have to do it manually*/ if(anim_en == LV_ANIM_OFF || anim_time == 0) { inf_normalize(obj); } + /* Calculate animation configuration */ + lv_roller_t * roller = (lv_roller_t *)obj; int32_t id = roller->sel_opt_id; - lv_coord_t sel_y1 = id * (font_h + line_space); - lv_coord_t mid_y1 = h / 2 - font_h / 2; - - lv_coord_t new_y = mid_y1 - sel_y1; + const lv_coord_t sel_y1 = id * (font_h + line_space); + const lv_coord_t mid_y1 = h / 2 - font_h / 2; + const lv_coord_t new_y = mid_y1 - sel_y1; if(anim_en == LV_ANIM_OFF || anim_time == 0) { lv_anim_del(label, set_y_anim); diff --git a/src/widgets/roller/lv_roller.h b/src/widgets/roller/lv_roller.h index 6ea178530f..6f9e57edc0 100644 --- a/src/widgets/roller/lv_roller.h +++ b/src/widgets/roller/lv_roller.h @@ -48,7 +48,6 @@ typedef struct { uint32_t inf_page_cnt; /**< Number of extra pages added to make the roller look infinite */ lv_roller_mode_t mode : 1; uint32_t moved : 1; - } lv_roller_t; extern const lv_obj_class_t lv_roller_class; diff --git a/tests/ref_imgs/roller_1.png b/tests/ref_imgs/roller_1.png new file mode 100644 index 0000000000..af517c486e Binary files /dev/null and b/tests/ref_imgs/roller_1.png differ diff --git a/tests/src/test_cases/test_roller.c b/tests/src/test_cases/test_roller.c new file mode 100644 index 0000000000..4600f320d8 --- /dev/null +++ b/tests/src/test_cases/test_roller.c @@ -0,0 +1,236 @@ +#if LV_BUILD_TEST +#include "../lvgl.h" + +#include "unity/unity.h" +#include "lv_test_indev.h" + +#define OPTION_BUFFER_SZ (20U) +#define OPTION_SMALL_BUFFER_SZ (3U) + +static lv_obj_t * active_screen = NULL; +static lv_obj_t * roller = NULL; +static lv_obj_t * roller_infinite = NULL; +static lv_obj_t * roller_mouse = NULL; +static lv_group_t * g = NULL; +static lv_group_t * encoder_g = NULL; +static lv_group_t * mouse_g = NULL; + +static const char * default_roller_options = "One\nTwo\nThree"; +static const char * default_infinite_roller_options = "One\nTwo\nThree\nFour\nFive\nSix\nSeven\nEight\nNine\nTen"; + +void setUp(void) +{ + active_screen = lv_scr_act(); + roller = lv_roller_create(active_screen); + roller_infinite = lv_roller_create(active_screen); + roller_mouse = lv_roller_create(active_screen); + + lv_roller_set_options(roller, default_roller_options, LV_ROLLER_MODE_NORMAL); + lv_roller_set_options(roller_infinite, default_infinite_roller_options, LV_ROLLER_MODE_INFINITE); + lv_roller_set_options(roller_mouse, default_roller_options, LV_ROLLER_MODE_NORMAL); + + g = lv_group_create(); + lv_indev_set_group(lv_test_keypad_indev, g); + + encoder_g = lv_group_create(); + lv_indev_set_group(lv_test_encoder_indev, encoder_g); + + mouse_g = lv_group_create(); + lv_indev_set_group(lv_test_mouse_indev, mouse_g); + + lv_group_add_obj(g, roller); + lv_group_add_obj(encoder_g, roller_infinite); + lv_group_add_obj(mouse_g, roller_mouse); +} + +void tearDown(void) +{ + lv_group_remove_obj(roller); + lv_group_remove_obj(roller_infinite); + lv_group_remove_obj(roller_mouse); + lv_obj_clean(active_screen); +} + +void test_roller_get_options(void) +{ + TEST_ASSERT_EQUAL_STRING(default_roller_options, lv_roller_get_options(roller)); +} + +void test_roller_get_selected_option(void) +{ + char actual_str[OPTION_BUFFER_SZ] = {0x00}; + int16_t expected_index = 2; + int16_t actual_index = 0; + char * expected_index_str = "Three"; + + /* Select the last option, index starts at 0 */ + uint16_t option_count = lv_roller_get_option_cnt(roller); + lv_roller_set_selected(roller, option_count - 1, LV_ANIM_OFF); + + actual_index = lv_roller_get_selected(roller); + TEST_ASSERT_EQUAL(expected_index, actual_index); + + /* Get the index string */ + lv_roller_get_selected_str(roller, actual_str, OPTION_BUFFER_SZ); + + TEST_ASSERT_EQUAL_STRING(expected_index_str, actual_str); +} + +void test_roller_get_selected_option_truncated_buffer(void) +{ + char actual_str[OPTION_SMALL_BUFFER_SZ] = {0x00}; + char * expected_index_str = "Th"; + + /* Select the last option, index starts at 0 */ + uint16_t option_count = lv_roller_get_option_cnt(roller); + lv_roller_set_selected(roller, option_count - 1, LV_ANIM_OFF); + + /* Get the index string */ + lv_roller_get_selected_str(roller, actual_str, OPTION_SMALL_BUFFER_SZ); + + TEST_ASSERT_EQUAL_STRING(expected_index_str, actual_str); +} + +void test_roller_infinite_mode_get_selected_option(void) +{ + char actual_str[OPTION_BUFFER_SZ] = {0x00}; + int16_t expected_index = 9; + int16_t actual_index = 0; + + /* Select the last option of page 2 */ + uint16_t option_count = lv_roller_get_option_cnt(roller_infinite); + option_count = (option_count * 2) - 1; + lv_roller_set_selected(roller_infinite, option_count, LV_ANIM_OFF); + + actual_index = lv_roller_get_selected(roller_infinite); + TEST_ASSERT_EQUAL(expected_index, actual_index); + + /* Get the index string */ + lv_roller_get_selected_str(roller_infinite, actual_str, OPTION_BUFFER_SZ); + + TEST_ASSERT_EQUAL_STRING("Ten", actual_str); + memset(actual_str, 0x00, OPTION_BUFFER_SZ); + + /* Select the second option of page */ + lv_roller_set_selected(roller_infinite, 1, LV_ANIM_OFF); + + actual_index = lv_roller_get_selected(roller_infinite); + TEST_ASSERT_EQUAL(1, actual_index); + + /* Get the index string */ + lv_roller_get_selected_str(roller_infinite, actual_str, OPTION_BUFFER_SZ); + + TEST_ASSERT_EQUAL_STRING("Two", actual_str); +} + +void test_roller_keypad_events(void) +{ + int16_t expected_index = 1; + int16_t actual_index = 0; + + /* Select option index 1 with LV_KEY_RIGHT event */ + lv_roller_set_selected(roller, 0, LV_ANIM_OFF); + lv_test_key_hit(LV_KEY_RIGHT); + + actual_index = lv_roller_get_selected(roller); + TEST_ASSERT_EQUAL(expected_index, actual_index); + + /* Select next option with LV_KEY_DOWN */ + expected_index = 2; + lv_test_key_hit(LV_KEY_DOWN); + + actual_index = lv_roller_get_selected(roller); + TEST_ASSERT_EQUAL(expected_index, actual_index); + + /* Select previous option with LV_KEY_LEFT */ + expected_index = 1; + lv_test_key_hit(LV_KEY_LEFT); + + actual_index = lv_roller_get_selected(roller); + TEST_ASSERT_EQUAL(expected_index, actual_index); + + /* Select previous option with LV_KEY_UP */ + expected_index = 0; + lv_test_key_hit(LV_KEY_UP); + + actual_index = lv_roller_get_selected(roller); + TEST_ASSERT_EQUAL(expected_index, actual_index); +} + +void test_roller_infinite_mode_first_option_gets_selected_after_last_option(void) +{ + char actual_str[OPTION_BUFFER_SZ] = {0x00}; + + lv_group_remove_obj(roller); + lv_group_add_obj(g, roller_infinite); + + /* Select the last option of page 2 */ + uint16_t option_count = lv_roller_get_option_cnt(roller_infinite); + option_count = (option_count * 2) - 1; + lv_roller_set_selected(roller_infinite, option_count, LV_ANIM_OFF); + + /* Get the index string */ + lv_roller_get_selected_str(roller_infinite, actual_str, OPTION_BUFFER_SZ); + + TEST_ASSERT_EQUAL_STRING("Ten", actual_str); + memset(actual_str, 0x00, OPTION_BUFFER_SZ); + + lv_test_key_hit(LV_KEY_DOWN); + + /* Get the index string */ + lv_roller_get_selected_str(roller_infinite, actual_str, OPTION_BUFFER_SZ); + TEST_ASSERT_EQUAL_STRING("One", actual_str); + + lv_group_remove_obj(roller_infinite); +} + +void test_roller_rendering_test(void) +{ +#if LV_FONT_MONTSERRAT_24 + static lv_style_t style_sel; + lv_style_init(&style_sel); + lv_style_set_text_font(&style_sel, &lv_font_montserrat_24); + lv_style_set_bg_color(&style_sel, lv_color_hex3(0xf88)); + lv_style_set_border_width(&style_sel, 2); + lv_style_set_border_color(&style_sel, lv_color_hex3(0xf00)); + + lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED); + lv_obj_set_style_text_align(roller, LV_TEXT_ALIGN_RIGHT, 0); + lv_roller_set_options(roller, "One\nTwo\nThree\nFour\nFive", LV_ROLLER_MODE_NORMAL); + lv_roller_set_selected(roller, 1, LV_ANIM_OFF); + lv_obj_center(roller); + + TEST_ASSERT_EQUAL_SCREENSHOT("roller_1.png"); +#else + TEST_PASS(); +#endif +} + +void test_roller_select_option_with_click(void) +{ + char actual_str[OPTION_BUFFER_SZ] = {0x00}; + + lv_test_encoder_click(); + lv_test_encoder_turn(1); + + /* Get the index string */ + lv_roller_get_selected_str(roller_infinite, actual_str, OPTION_BUFFER_SZ); + + TEST_ASSERT_EQUAL_STRING("Two", actual_str); + memset(actual_str, 0x00, OPTION_BUFFER_SZ); +} + +void test_roller_release_handler_pointer_indev(void) +{ + /* Clic in the widget */ + lv_test_mouse_click_at(roller_mouse->coords.x1 + 5, roller_mouse->coords.y1 + 5); + /* Check which is the selected option */ + TEST_ASSERT_EQUAL(0, lv_roller_get_selected(roller_mouse)); + + /* Clic further down the roller */ + lv_test_mouse_click_at(roller_mouse->coords.x1 + 5, roller_mouse->coords.y1 + 100); + /* Check which is the selected option */ + TEST_ASSERT_NOT_EQUAL(0, lv_roller_get_selected(roller_mouse)); +} + +#endif