From 306fa1968238fe33dd95e2865e147bceb4706ad5 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 18 Mar 2022 15:00:58 +0100 Subject: [PATCH] fix(table): invalidate only the changed cell fixes: https://forum.lvgl.io/t/refresh-cells-that-changed/8454 --- src/widgets/lv_table.c | 124 +++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 36 deletions(-) diff --git a/src/widgets/lv_table.c b/src/widgets/lv_table.c index 64c15cdbd..5ff65ab23 100644 --- a/src/widgets/lv_table.c +++ b/src/widgets/lv_table.c @@ -36,10 +36,12 @@ 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 start_row); +static void refr_size_form_row(lv_obj_t * obj, uint32_t start_row); +static void refr_cell_size(lv_obj_t * obj, uint32_t row, uint32_t col); 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 void get_cell_area(lv_obj_t * obj, uint16_t row, uint16_t col, lv_area_t * area); static inline bool is_cell_empty(void * cell) { @@ -106,9 +108,7 @@ void lv_table_set_cell_value(lv_obj_t * obj, uint16_t row, uint16_t col, const c copy_cell_txt(table->cell_data[cell], txt); table->cell_data[cell][0] = ctrl; - refr_size(obj, row); - - lv_obj_invalidate(obj); + refr_cell_size(obj, row, col); } void lv_table_set_cell_value_fmt(lv_obj_t * obj, uint16_t row, uint16_t col, const char * fmt, ...) @@ -179,26 +179,7 @@ void lv_table_set_cell_value_fmt(lv_obj_t * obj, uint16_t row, uint16_t col, con table->cell_data[cell][0] = ctrl; - /*Refresh the row height*/ - 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_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 h = get_row_height(obj, row, font, letter_space, line_space, - cell_left, cell_right, cell_top, cell_bottom); - - - 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); - - table->row_h[row] = LV_CLAMP(minh, h, maxh); - - lv_obj_invalidate(obj); + refr_cell_size(obj, row, col); } void lv_table_set_row_cnt(lv_obj_t * obj, uint16_t row_cnt) @@ -237,7 +218,7 @@ void lv_table_set_row_cnt(lv_obj_t * obj, uint16_t row_cnt) lv_memset_00(&table->cell_data[old_cell_cnt], (new_cell_cnt - old_cell_cnt) * sizeof(table->cell_data[0])); } - refr_size(obj, 0); + refr_size_form_row(obj, 0); } void lv_table_set_col_cnt(lv_obj_t * obj, uint16_t col_cnt) @@ -293,7 +274,7 @@ void lv_table_set_col_cnt(lv_obj_t * obj, uint16_t col_cnt) } - refr_size(obj, 0) ; + refr_size_form_row(obj, 0) ; } void lv_table_set_col_width(lv_obj_t * obj, uint16_t col_id, lv_coord_t w) @@ -306,7 +287,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_form_row(obj, 0); } void lv_table_add_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl) @@ -367,7 +348,7 @@ const char * lv_table_get_cell_value(lv_obj_t * obj, uint16_t row, uint16_t col) lv_table_t * table = (lv_table_t *)obj; if(row >= table->row_cnt || col >= table->col_cnt) { - LV_LOG_WARN("lv_table_set_cell_value: invalid row or column"); + LV_LOG_WARN("invalid row or column"); return ""; } uint32_t cell = row * table->col_cnt + col; @@ -485,7 +466,7 @@ static void lv_table_event(const lv_obj_class_t * class_p, lv_event_t * e) lv_table_t * table = (lv_table_t *)obj; if(code == LV_EVENT_STYLE_CHANGED) { - refr_size(obj, 0); + refr_size_form_row(obj, 0); } else if(code == LV_EVENT_GET_SELF_SIZE) { lv_point_t * p = lv_event_get_param(e); @@ -785,12 +766,12 @@ static void draw_main(lv_event_t * e) } /* Refreshes size of the table starting from @start_row row */ -static void refr_size(lv_obj_t * obj, uint32_t start_row) +static void refr_size_form_row(lv_obj_t * obj, uint32_t start_row) { - 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); + const lv_coord_t cell_pad_left = lv_obj_get_style_pad_left(obj, LV_PART_ITEMS); + const lv_coord_t cell_pad_right = lv_obj_get_style_pad_right(obj, LV_PART_ITEMS); + const lv_coord_t cell_pad_top = lv_obj_get_style_pad_top(obj, LV_PART_ITEMS); + const lv_coord_t cell_pad_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); @@ -803,11 +784,47 @@ static void refr_size(lv_obj_t * obj, uint32_t start_row) 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); + cell_pad_left, cell_pad_right, cell_pad_top, cell_pad_bottom); table->row_h[i] = LV_CLAMP(minh, calculated_height, maxh); } - lv_obj_refresh_self_size(obj) ; + lv_obj_refresh_self_size(obj); + lv_obj_invalidate(obj); +} + + +static void refr_cell_size(lv_obj_t * obj, uint32_t row, uint32_t col) +{ + const lv_coord_t cell_pad_left = lv_obj_get_style_pad_left(obj, LV_PART_ITEMS); + const lv_coord_t cell_pad_right = lv_obj_get_style_pad_right(obj, LV_PART_ITEMS); + const lv_coord_t cell_pad_top = lv_obj_get_style_pad_top(obj, LV_PART_ITEMS); + const lv_coord_t cell_pad_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); + + 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); + + lv_table_t * table = (lv_table_t *)obj; + lv_coord_t calculated_height = get_row_height(obj, row, font, letter_space, line_space, + cell_pad_left, cell_pad_right, cell_pad_top, cell_pad_bottom); + + lv_coord_t prev_row_size = table->row_h[row]; + table->row_h[row] = LV_CLAMP(minh, calculated_height, maxh); + + /*If the row height havn't changed invalidate only this cell*/ + if(prev_row_size == table->row_h[row]) { + lv_area_t cell_area; + get_cell_area(obj, row, col, &cell_area); + lv_area_move(&cell_area, obj->coords.x1, obj->coords.y1); + lv_obj_invalidate_area(obj, &cell_area); + } + else { + lv_obj_refresh_self_size(obj); + lv_obj_invalidate(obj); + } } static lv_coord_t get_row_height(lv_obj_t * obj, uint16_t row_id, const lv_font_t * font, @@ -952,4 +969,39 @@ static void copy_cell_txt(char * dst, const char * txt) #endif } +static void get_cell_area(lv_obj_t * obj, uint16_t row, uint16_t col, lv_area_t * area) +{ + lv_table_t * table = (lv_table_t *)obj; + + uint32_t c; + area->x1 = 0; + for(c = 0; c < col; c++) { + area->x1 += table->col_w[c]; + } + + bool rtl = lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL; + if(rtl) { + area->x1 += lv_obj_get_scroll_x(obj); + lv_coord_t w = lv_obj_get_width(obj); + area->x2 = w - area->x1 - lv_obj_get_style_pad_right(obj, 0); + area->x1 = area->x2 - table->col_w[col]; + } + else { + area->x1 -= lv_obj_get_scroll_x(obj); + area->x1 += lv_obj_get_style_pad_left(obj, 0); + area->x2 = area->x1 + table->col_w[col] - 1; + } + + uint32_t r; + area->y1 = 0; + for(r = 0; r < row; r++) { + area->y1 += table->row_h[r]; + } + + area->y1 += lv_obj_get_style_pad_top(obj, 0); + area->y1 -= lv_obj_get_scroll_y(obj); + area->y2 = area->y1 + table->row_h[row] - 1; + +} + #endif