diff --git a/src/widgets/lv_table.c b/src/widgets/lv_table.c index 1b032156e..055935f7a 100644 --- a/src/widgets/lv_table.c +++ b/src/widgets/lv_table.c @@ -36,8 +36,15 @@ static void draw_main(lv_event_t * e); static lv_coord_t get_row_height(lv_obj_t * obj, uint16_t row_id, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t cell_left, lv_coord_t cell_right, lv_coord_t cell_top, lv_coord_t cell_bottom); -static void refr_size(lv_obj_t * obj, uint32_t strat_row); +static void refr_size(lv_obj_t * obj, uint32_t start_row); static lv_res_t get_pressed_cell(lv_obj_t * obj, uint16_t * row, uint16_t * col); +static size_t get_cell_txt_len(const char * txt); +static void copy_cell_txt(char * dst, const char * txt); + +static inline bool is_cell_empty(void * cell) +{ + return cell == NULL; +} /********************** * STATIC VARIABLES @@ -90,20 +97,13 @@ void lv_table_set_cell_value(lv_obj_t * obj, uint16_t row, uint16_t col, const c /*Save the control byte*/ if(table->cell_data[cell]) ctrl = table->cell_data[cell][0]; -#if LV_USE_ARABIC_PERSIAN_CHARS - /*Get the size of the Arabic text and process it*/ - size_t len_ap = _lv_txt_ap_calc_bytes_cnt(txt); - table->cell_data[cell] = lv_mem_realloc(table->cell_data[cell], len_ap + 1); + size_t to_allocate = get_cell_txt_len(txt); + + table->cell_data[cell] = lv_mem_realloc(table->cell_data[cell], to_allocate); LV_ASSERT_MALLOC(table->cell_data[cell]); if(table->cell_data[cell] == NULL) return; - _lv_txt_ap_proc(txt, &table->cell_data[cell][1]); -#else - table->cell_data[cell] = lv_mem_realloc(table->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ - LV_ASSERT_MALLOC(table->cell_data[cell]); - - strcpy(table->cell_data[cell] + 1, txt); /*+1 to skip the format byte*/ -#endif + copy_cell_txt(table->cell_data[cell], txt); table->cell_data[cell][0] = ctrl; refr_size(obj, row); @@ -118,8 +118,7 @@ void lv_table_set_cell_value_fmt(lv_obj_t * obj, uint16_t row, uint16_t col, con lv_table_t * table = (lv_table_t *)obj; if(col >= table->col_cnt) { - LV_LOG_WARN("lv_table_set_cell_value: invalid column"); - return; + lv_table_set_col_cnt(obj, col + 1); } /*Auto expand*/ @@ -245,7 +244,7 @@ void lv_table_set_col_cnt(lv_obj_t * obj, uint16_t col_cnt) lv_table_t * table = (lv_table_t *)obj; uint16_t old_col_cnt = table->col_cnt; table->col_cnt = col_cnt; - table->col_w = lv_mem_realloc(table->col_w, col_cnt * sizeof(table->row_h[0])); + table->col_w = lv_mem_realloc(table->col_w, col_cnt * sizeof(table->col_w[0])); LV_ASSERT_MALLOC(table->col_w); if(table->col_w == NULL) return; @@ -303,7 +302,7 @@ void lv_table_set_col_width(lv_obj_t * obj, uint16_t col_id, lv_coord_t w) if(col_id >= table->col_cnt) lv_table_set_col_cnt(obj, col_id + 1); table->col_w[col_id] = w; - refr_size(obj, 0) ; + refr_size(obj, 0); } void lv_table_add_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl) @@ -318,7 +317,7 @@ void lv_table_add_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table uint32_t cell = row * table->col_cnt + col; - if(table->cell_data[cell] == NULL) { + if(is_cell_empty(table->cell_data[cell])) { table->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ LV_ASSERT_MALLOC(table->cell_data[cell]); if(table->cell_data[cell] == NULL) return; @@ -342,7 +341,7 @@ void lv_table_clear_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_tab uint32_t cell = row * table->col_cnt + col; - if(table->cell_data[cell] == NULL) { + if(is_cell_empty(table->cell_data[cell])) { table->cell_data[cell] = lv_mem_alloc(2); /*+1: trailing '\0; +1: format byte*/ LV_ASSERT_MALLOC(table->cell_data[cell]); if(table->cell_data[cell] == NULL) return; @@ -369,7 +368,7 @@ const char * lv_table_get_cell_value(lv_obj_t * obj, uint16_t row, uint16_t col) } uint32_t cell = row * table->col_cnt + col; - if(table->cell_data[cell] == NULL) return ""; + if(is_cell_empty(table->cell_data[cell])) return ""; return &table->cell_data[cell][1]; /*Skip the format byte*/ } @@ -415,8 +414,8 @@ bool lv_table_has_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table } uint32_t cell = row * table->col_cnt + col; - if(table->cell_data[cell] == NULL) return false; - else return (table->cell_data[cell][0] & ctrl) == ctrl ? true : false; + if(is_cell_empty(table->cell_data[cell])) return false; + else return (table->cell_data[cell][0] & ctrl) == ctrl; } void lv_table_get_selected_cell(lv_obj_t * obj, uint16_t * row, uint16_t * col) @@ -599,8 +598,6 @@ static void draw_main(lv_event_t * e) lv_point_t txt_size; lv_area_t cell_area; - lv_area_t txt_area; - lv_text_flag_t txt_flags; lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); lv_coord_t bg_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); @@ -608,11 +605,6 @@ static void draw_main(lv_event_t * e) lv_coord_t bg_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); lv_coord_t bg_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); - lv_coord_t cell_left = lv_obj_get_style_pad_left(obj, LV_PART_ITEMS); - lv_coord_t cell_right = lv_obj_get_style_pad_right(obj, LV_PART_ITEMS); - lv_coord_t cell_top = lv_obj_get_style_pad_top(obj, LV_PART_ITEMS); - lv_coord_t cell_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_ITEMS); - lv_state_t state_ori = obj->state; obj->state = LV_STATE_DEFAULT; obj->skip_trans = 1; @@ -634,7 +626,7 @@ static void draw_main(lv_event_t * e) cell_area.y2 = obj->coords.y1 + bg_top - 1 - lv_obj_get_scroll_y(obj) + border_width; lv_coord_t scroll_x = lv_obj_get_scroll_x(obj) ; - bool rtl = lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL ? true : false; + bool rtl = lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL; /*Handle custom drawer*/ lv_obj_draw_part_dsc_t part_draw_dsc; @@ -671,15 +663,16 @@ static void draw_main(lv_event_t * e) uint16_t col_merge = 0; for(col_merge = 0; col_merge + col < table->col_cnt - 1; col_merge++) { - if(table->cell_data[cell + col_merge]) { - char * next_cell_data = table->cell_data[cell + col_merge]; - if(next_cell_data) ctrl = next_cell_data[0]; - if(ctrl & LV_TABLE_CELL_CTRL_MERGE_RIGHT) - if(rtl) cell_area.x1 -= table->col_w[col + col_merge + 1]; - else cell_area.x2 += table->col_w[col + col_merge + 1]; - else { - break; - } + char * next_cell_data = table->cell_data[cell + col_merge]; + + if(is_cell_empty(next_cell_data)) break; + + lv_table_cell_ctrl_t merge_ctrl = (lv_table_cell_ctrl_t) next_cell_data[0]; + if(merge_ctrl & LV_TABLE_CELL_CTRL_MERGE_RIGHT) { + lv_coord_t offset = table->col_w[col + col_merge + 1]; + + if(rtl) cell_area.x1 -= offset; + else cell_area.x2 += offset; } else { break; @@ -741,6 +734,13 @@ static void draw_main(lv_event_t * e) lv_draw_rect(draw_ctx, &rect_dsc_act, &cell_area_border); if(table->cell_data[cell]) { + const lv_coord_t cell_left = lv_obj_get_style_pad_left(obj, LV_PART_ITEMS); + const lv_coord_t cell_right = lv_obj_get_style_pad_right(obj, LV_PART_ITEMS); + const lv_coord_t cell_top = lv_obj_get_style_pad_top(obj, LV_PART_ITEMS); + const lv_coord_t cell_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_ITEMS); + lv_text_flag_t txt_flags = LV_TEXT_FLAG_NONE; + lv_area_t txt_area; + txt_area.x1 = cell_area.x1 + cell_left; txt_area.x2 = cell_area.x2 - cell_right; txt_area.y1 = cell_area.y1 + cell_top; @@ -749,7 +749,6 @@ static void draw_main(lv_event_t * e) /*Align the content to the middle if not cropped*/ bool crop = ctrl & LV_TABLE_CELL_CTRL_TEXT_CROP ? true : false; if(crop) txt_flags = LV_TEXT_FLAG_EXPAND; - else txt_flags = LV_TEXT_FLAG_NONE; lv_txt_get_size(&txt_size, table->cell_data[cell] + 1, label_dsc_def.font, label_dsc_act.letter_space, label_dsc_act.line_space, @@ -781,28 +780,27 @@ static void draw_main(lv_event_t * e) draw_ctx->clip_area = clip_area_ori; } -static void refr_size(lv_obj_t * obj, uint32_t strat_row) +/* Refreshes size of the table starting from @start_row row */ +static void refr_size(lv_obj_t * obj, uint32_t start_row) { - lv_table_t * table = (lv_table_t *)obj; - - uint32_t i; - - lv_coord_t cell_left = lv_obj_get_style_pad_left(obj, LV_PART_ITEMS); - lv_coord_t cell_right = lv_obj_get_style_pad_right(obj, LV_PART_ITEMS); - lv_coord_t cell_top = lv_obj_get_style_pad_top(obj, LV_PART_ITEMS); - lv_coord_t cell_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_ITEMS); + const lv_coord_t cell_left = lv_obj_get_style_pad_left(obj, LV_PART_ITEMS); + const lv_coord_t cell_right = lv_obj_get_style_pad_right(obj, LV_PART_ITEMS); + const lv_coord_t cell_top = lv_obj_get_style_pad_top(obj, LV_PART_ITEMS); + const lv_coord_t cell_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_ITEMS); lv_coord_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_ITEMS); lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_ITEMS); const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_ITEMS); - lv_coord_t minh = lv_obj_get_style_min_height(obj, LV_PART_ITEMS); - lv_coord_t maxh = lv_obj_get_style_max_height(obj, LV_PART_ITEMS); + const lv_coord_t minh = lv_obj_get_style_min_height(obj, LV_PART_ITEMS); + const lv_coord_t maxh = lv_obj_get_style_max_height(obj, LV_PART_ITEMS); - for(i = strat_row; i < table->row_cnt; i++) { - table->row_h[i] = get_row_height(obj, i, font, letter_space, line_space, - cell_left, cell_right, cell_top, cell_bottom); - table->row_h[i] = LV_CLAMP(minh, table->row_h[i], maxh); + lv_table_t * table = (lv_table_t *)obj; + uint32_t i; + for(i = start_row; i < table->row_cnt; i++) { + lv_coord_t calculated_height = get_row_height(obj, i, font, letter_space, line_space, + cell_left, cell_right, cell_top, cell_bottom); + table->row_h[i] = LV_CLAMP(minh, calculated_height, maxh); } lv_obj_refresh_self_size(obj) ; @@ -822,45 +820,46 @@ static lv_coord_t get_row_height(lv_obj_t * obj, uint16_t row_id, const lv_font_ lv_coord_t h_max = lv_font_get_line_height(font) + cell_top + cell_bottom; for(cell = row_start, col = 0; cell < row_start + table->col_cnt; cell++, col++) { - if(table->cell_data[cell] != NULL) { - txt_w = table->col_w[col]; - uint16_t col_merge = 0; - for(col_merge = 0; col_merge + col < table->col_cnt - 1; col_merge++) { + if(is_cell_empty(table->cell_data[cell])) { + continue; + } - if(table->cell_data[cell + col_merge] != NULL) { - lv_table_cell_ctrl_t ctrl = 0; - char * next_cell_data = table->cell_data[cell + col_merge]; - if(next_cell_data) ctrl = next_cell_data[0]; - if(ctrl & LV_TABLE_CELL_CTRL_MERGE_RIGHT) - txt_w += table->col_w[col + col_merge + 1]; - else - break; - } - else { - break; - } + txt_w = table->col_w[col]; + /* Merge cells */ + uint16_t col_merge = 0; + for(col_merge = 0; col_merge + col < table->col_cnt - 1; col_merge++) { + char * next_cell_data = table->cell_data[cell + col_merge]; + + if(is_cell_empty(next_cell_data)) break; + + lv_table_cell_ctrl_t ctrl = (lv_table_cell_ctrl_t) next_cell_data[0]; + if(ctrl & LV_TABLE_CELL_CTRL_MERGE_RIGHT) { + txt_w += table->col_w[col + col_merge + 1]; } - - lv_table_cell_ctrl_t ctrl = 0; - if(table->cell_data[cell]) ctrl = table->cell_data[cell][0]; - - /*With text crop assume 1 line*/ - if(ctrl & LV_TABLE_CELL_CTRL_TEXT_CROP) { - h_max = LV_MAX(lv_font_get_line_height(font) + cell_top + cell_bottom, - h_max); - } - /*Without text crop calculate the height of the text in the cell*/ else { - txt_w -= cell_left + cell_right; - - lv_txt_get_size(&txt_size, table->cell_data[cell] + 1, font, - letter_space, line_space, txt_w, LV_TEXT_FLAG_NONE); - - h_max = LV_MAX(txt_size.y + cell_top + cell_bottom, h_max); - cell += col_merge; - col += col_merge; + break; } } + + lv_table_cell_ctrl_t ctrl = 0; + if(table->cell_data[cell]) ctrl = table->cell_data[cell][0]; + + /*With text crop assume 1 line*/ + if(ctrl & LV_TABLE_CELL_CTRL_TEXT_CROP) { + h_max = LV_MAX(lv_font_get_line_height(font) + cell_top + cell_bottom, + h_max); + } + /*Without text crop calculate the height of the text in the cell*/ + else { + txt_w -= cell_left + cell_right; + + lv_txt_get_size(&txt_size, table->cell_data[cell] + 1, font, + letter_space, line_space, txt_w, LV_TEXT_FLAG_NONE); + + h_max = LV_MAX(txt_size.y + cell_top + cell_bottom, h_max); + cell += col_merge; + col += col_merge; + } } return h_max; @@ -917,5 +916,29 @@ static lv_res_t get_pressed_cell(lv_obj_t * obj, uint16_t * row, uint16_t * col) return LV_RES_OK; } +/* Returns number of bytes to allocate based on chars configuration */ +static size_t get_cell_txt_len(const char * txt) +{ + size_t retval = 0; + +#if LV_USE_ARABIC_PERSIAN_CHARS + retval = _lv_txt_ap_calc_bytes_cnt(txt) + 1; +#else + /* +1: trailing '\0'; +1: format byte */ + retval = strlen(txt) + 2; +#endif + + return retval; +} + +/* Copy txt into dst skipping the format byte */ +static void copy_cell_txt(char * dst, const char * txt) +{ +#if LV_USE_ARABIC_PERSIAN_CHARS + _lv_txt_ap_proc(txt, &dst[1]); +#else + strcpy(&dst[1], txt); +#endif +} #endif diff --git a/tests/ref_imgs/table_1.png b/tests/ref_imgs/table_1.png new file mode 100644 index 000000000..193e1327e Binary files /dev/null and b/tests/ref_imgs/table_1.png differ diff --git a/tests/src/test_cases/test_table.c b/tests/src/test_cases/test_table.c new file mode 100644 index 000000000..62f7065d8 --- /dev/null +++ b/tests/src/test_cases/test_table.c @@ -0,0 +1,187 @@ +#if LV_BUILD_TEST +#include "../lvgl.h" + +#include "unity/unity.h" + +static lv_obj_t * scr = NULL; +static lv_obj_t * table = NULL; + +void setUp(void) +{ + scr = lv_scr_act(); + table = lv_table_create(scr); +} + +void tearDown(void) +{ + lv_obj_clean(lv_scr_act()); +} + +void test_table_should_return_assigned_cell_value(void) +{ + uint16_t row = 0; + uint16_t column = 0; + const char * value = "LVGL"; + + lv_table_set_cell_value(table, row, column, value); + + TEST_ASSERT_EQUAL_STRING(value, lv_table_get_cell_value(table, row, column)); +} + +void test_table_should_grow_columns_automatically_when_setting_formatted_cell_value(void) +{ + /* Newly created tables have 1 column and 1 row */ + uint16_t original_column_count = lv_table_get_col_cnt(table); + TEST_ASSERT_EQUAL_UINT16(1, original_column_count); + + /* Table currently only has a cell at 0,0 (row, colum) */ + lv_table_set_cell_value_fmt(table, 0, 1, "LVGL %s", "Rocks!"); + + /* Table now should have cells at 0,0 and 0,1, so 2 columns */ + uint16_t expected_column_count = original_column_count + 1; + TEST_ASSERT_EQUAL_UINT16(expected_column_count, lv_table_get_col_cnt(table)); +} + +void test_table_should_identify_cell_with_ctrl(void) +{ + bool has_ctrl = false; + + has_ctrl = lv_table_has_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + + TEST_ASSERT_FALSE(has_ctrl); + + lv_table_add_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + has_ctrl = lv_table_has_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + TEST_ASSERT_TRUE(has_ctrl); +} + +void test_table_should_clear_selected_cell_ctrl(void) +{ + bool has_ctrl = false; + + lv_table_add_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + has_ctrl = lv_table_has_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + TEST_ASSERT_TRUE(has_ctrl); + + lv_table_clear_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + has_ctrl = lv_table_has_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + TEST_ASSERT_FALSE(has_ctrl); +} + +void test_table_should_keep_not_selected_cell_ctrl(void) +{ + bool has_ctrl = false; + + lv_table_add_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT | LV_TABLE_CELL_CTRL_TEXT_CROP); + + lv_table_clear_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + has_ctrl = lv_table_has_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + TEST_ASSERT_FALSE(has_ctrl); + + has_ctrl = lv_table_has_cell_ctrl(table, 0, 0, LV_TABLE_CELL_CTRL_TEXT_CROP); + TEST_ASSERT_TRUE(has_ctrl); +} + +/* We're using a newly created table */ +void test_table_cell_value_should_return_empty_string_when_cell_is_empty(void) +{ + TEST_ASSERT_EQUAL_STRING("", lv_table_get_cell_value(table, 0, 0)); +} + +void test_table_row_height_should_increase_with_multiline_cell_value(void) +{ + lv_table_t * table_ptr = (lv_table_t *) table; + const char * singleline_value = "LVGL"; + const char * multiline_value = "LVGL\nRocks"; + + lv_table_set_cell_value(table, 0, 0, singleline_value); + lv_coord_t singleline_row_height = table_ptr->row_h[0]; + + lv_table_set_cell_value(table, 0, 0, multiline_value); + lv_coord_t multiline_row_height = table_ptr->row_h[0]; + + TEST_ASSERT_GREATER_THAN(singleline_row_height, multiline_row_height); +} + +void test_table_should_wrap_long_texts(void) +{ + lv_table_t * table_ptr = (lv_table_t *) table; + const char * long_text = "Testing automatic text wrap with a very long text"; + const char * small_text = "Hi"; + + lv_table_set_col_width(table, 0, 50); + + lv_table_set_cell_value(table, 0, 0, small_text); + lv_coord_t row_height = table_ptr->row_h[0]; + + lv_table_set_cell_value(table, 0, 0, long_text); + lv_coord_t wrapped_row_height = table_ptr->row_h[0]; + + /* Row height on cells with wrapped text is bigger than cells with small texts */ + TEST_ASSERT_GREATER_THAN(row_height, wrapped_row_height); +} + +static void draw_part_event_cb(lv_event_t * e) +{ + lv_obj_t * obj = lv_event_get_target(e); + lv_obj_draw_part_dsc_t * dsc = lv_event_get_param(e); + /*If the cells are drawn...*/ + if(dsc->part == LV_PART_ITEMS) { + uint32_t row = dsc->id / lv_table_get_col_cnt(obj); + uint32_t col = dsc->id - row * lv_table_get_col_cnt(obj); + + /*Make the texts in the first cell center aligned*/ + if(row == 0) { + dsc->label_dsc->align = LV_TEXT_ALIGN_CENTER; + dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_BLUE), dsc->rect_dsc->bg_color, LV_OPA_40); + dsc->rect_dsc->bg_opa = LV_OPA_COVER; + } + /*In the first column align the texts to the right*/ + else if(col == 0) { + dsc->label_dsc->align = LV_TEXT_ALIGN_RIGHT; + } + + /*Make every 2nd row grayish*/ + if(row != 0 && (row % 2 == 0)) { + dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED), dsc->rect_dsc->bg_color, LV_OPA_30); + dsc->rect_dsc->bg_opa = LV_OPA_COVER; + } + } +} + +void test_table_rendering(void) +{ + lv_obj_center(table); + lv_obj_add_event_cb(table, draw_part_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); + lv_obj_set_style_border_side(table, LV_BORDER_SIDE_FULL, LV_PART_ITEMS); + lv_obj_set_style_pad_all(table, 10, LV_PART_ITEMS); + lv_obj_set_style_border_width(table, 5, LV_PART_ITEMS); + lv_table_set_col_cnt(table, 5); + lv_table_set_row_cnt(table, 5); + lv_table_set_col_width(table, 1, 60); + lv_table_set_col_width(table, 2, 100); + + lv_table_add_cell_ctrl(table, 0, 1, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + lv_table_set_cell_value(table, 0, 1, "2 cells are merged"); + + lv_table_add_cell_ctrl(table, 1, 0, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + lv_table_add_cell_ctrl(table, 1, 1, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + lv_table_add_cell_ctrl(table, 1, 2, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + lv_table_add_cell_ctrl(table, 1, 3, LV_TABLE_CELL_CTRL_MERGE_RIGHT); + lv_table_set_cell_value(table, 1, 0, "5 cells are merged"); + + uint32_t i; + for(i = 0; i < 5; i++) { + lv_table_set_cell_value_fmt(table, 3, i, "%d", i); + } + + lv_table_set_cell_value_fmt(table, 2, 3, "Multi\nline text"); + lv_table_set_cell_value_fmt(table, 2, 4, "Very long text wrapped automatically"); + + lv_table_add_cell_ctrl(table, 4, 3, LV_TABLE_CELL_CTRL_TEXT_CROP); + lv_table_set_cell_value_fmt(table, 4, 3, "crop crop crop crop crop crop crop crop "); + + TEST_ASSERT_EQUAL_SCREENSHOT("table_1.png"); +} + +#endif