From 7ac12cd07100e7adfcd54a6bc8d876f675101d45 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sun, 30 Dec 2018 15:02:16 +0100 Subject: [PATCH] lv_ta: refresh only the cursor area on cursor blink --- lv_core/lv_vdb.c | 4 +- lv_misc/lv_txt.h | 2 +- lv_objx/lv_ta.c | 258 ++++++++++++++++++++++++++++++----------------- lv_objx/lv_ta.h | 4 +- 4 files changed, 169 insertions(+), 99 deletions(-) diff --git a/lv_core/lv_vdb.c b/lv_core/lv_vdb.c index c362a48c0..74c0c08f7 100644 --- a/lv_core/lv_vdb.c +++ b/lv_core/lv_vdb.c @@ -121,10 +121,10 @@ void lv_vdb_flush(void) /* With true double buffering the flushing should be only the address change of the current frame buffer * Wait until the address change is ready and copy the active content to the other frame buffer (new active VDB) * The changes will be written to the new VDB.*/ -#if LV_VDB_TRUE_DOUBLE_BUFFERED +# if LV_VDB_TRUE_DOUBLE_BUFFERED while(vdb_flushing); memcpy(vdb[vdb_active].buf, vdb[(vdb_active + 1) & 0x1].buf, LV_VDB_SIZE_IN_BYTES); -#endif +# endif #endif /*#if LV_VDB_DOUBLE*/ diff --git a/lv_misc/lv_txt.h b/lv_misc/lv_txt.h index fd0d68fe3..166d2cd7c 100644 --- a/lv_misc/lv_txt.h +++ b/lv_misc/lv_txt.h @@ -122,7 +122,7 @@ void lv_txt_cut(char * txt, uint32_t pos, uint32_t len); ***************************************************************/ /** - * Give the size of an encoded character + * Give the size of an encoded character * @param str pointer to a character in a string * @return length of the encoded character (1,2,3 ...). O in invalid */ diff --git a/lv_objx/lv_ta.c b/lv_objx/lv_ta.c index d750540a8..5342afbba 100644 --- a/lv_objx/lv_ta.c +++ b/lv_objx/lv_ta.c @@ -11,6 +11,7 @@ #if USE_LV_TA != 0 #include "../lv_core/lv_group.h" +#include "../lv_core/lv_refr.h" #include "../lv_draw/lv_draw.h" #include "../lv_themes/lv_theme.h" #include "../lv_misc/lv_anim.h" @@ -50,6 +51,8 @@ static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x); #endif static void pwd_char_hider(lv_obj_t * ta); static bool char_is_accepted(lv_obj_t * ta, uint32_t c); +static void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res); +static void refr_cursor_area(lv_obj_t * ta); /********************** * STATIC VARIABLES @@ -483,7 +486,7 @@ void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos) lv_anim_create(&a); #endif - lv_obj_invalidate(ta); + refr_cursor_area(ta); } /** @@ -497,7 +500,8 @@ void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type) if(ext->cursor.type == cur_type) return; ext->cursor.type = cur_type; - lv_obj_invalidate(ta); + + refr_cursor_area(ta); } /** @@ -536,6 +540,8 @@ void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en) } ext->pwd_mode = en == false ? 0 : 1; + + refr_cursor_area(ta); } /** @@ -568,6 +574,8 @@ void lv_ta_set_one_line(lv_obj_t * ta, bool en) lv_obj_set_height(ta, LV_TA_DEF_HEIGHT); lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver); } + + refr_cursor_area(ta); } /** @@ -601,8 +609,9 @@ void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align) lv_style_t * bg_style = lv_ta_get_style(ta, LV_TA_STYLE_BG); lv_obj_set_width(label, lv_obj_get_width(ta) - 2 * bg_style->body.padding.hor); } - } + + refr_cursor_area(ta); } /** @@ -652,6 +661,7 @@ void lv_ta_set_style(lv_obj_t * ta, lv_ta_style_t type, lv_style_t * style) case LV_TA_STYLE_CURSOR: ext->cursor.style = style; lv_obj_refresh_ext_size(lv_page_get_scrl(ta)); /*Refresh ext. size because of cursor drawing*/ + refr_cursor_area(ta); break; } } @@ -929,129 +939,53 @@ static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_ /*Draw the cursor*/ lv_obj_t * ta = lv_obj_get_parent(scrl); lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); - lv_style_t * label_style = lv_obj_get_style(ext->label); - lv_opa_t opa_scale = lv_obj_get_opa_scale(ta); + if(ext->cursor.type == LV_CURSOR_NONE || (ext->cursor.type & LV_CURSOR_HIDDEN) || - ext->cursor.state == 0 || - label_style->body.opa == LV_OPA_TRANSP) { + ext->cursor.state == 0) { return true; /*The cursor is not visible now*/ } - lv_style_t cur_style; - if(ext->cursor.style != NULL) { - lv_style_copy(&cur_style, ext->cursor.style); - } else { - /*If cursor style is not specified then use the modified label style */ - lv_style_copy(&cur_style, label_style); - lv_color_t clv_color_tmp = cur_style.text.color; /*Make letter color to cursor color*/ - cur_style.text.color = cur_style.body.main_color; /*In block mode the letter color will be current background color*/ - cur_style.body.main_color = clv_color_tmp; - cur_style.body.grad_color = clv_color_tmp; - cur_style.body.border.color = clv_color_tmp; - cur_style.body.border.opa = LV_OPA_COVER; - cur_style.body.border.width = 1; - cur_style.body.shadow.width = 0; - cur_style.body.radius = 0; - cur_style.body.empty = 0; - cur_style.body.padding.hor = 0; - cur_style.body.padding.ver = 0; - cur_style.line.width = 1; - cur_style.body.opa = LV_OPA_COVER; - } + get_cursor_style(ta, &cur_style); - uint16_t cur_pos = lv_ta_get_cursor_pos(ta); const char * txt = lv_label_get_text(ext->label); - uint32_t byte_pos; -#if LV_TXT_UTF8 != 0 - byte_pos = lv_txt_encoded_get_byte_id(txt, cur_pos); - uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL); -#else - byte_pos = cur_pos; - uint32_t letter = txt[byte_pos]; -#endif - - lv_coord_t letter_h = lv_font_get_height(label_style->text.font); - /*Set letter_w (set not 0 on non printable but valid chars)*/ - lv_coord_t letter_w; - if(letter == '\0' || letter == '\n' || letter == '\r') { - letter_w = lv_font_get_width(label_style->text.font, ' '); - } else { - letter_w = lv_font_get_width(label_style->text.font, letter); - } - - lv_point_t letter_pos; - lv_label_get_letter_pos(ext->label, cur_pos, &letter_pos); - - /*In one line mode the cursor can be only in the first line */ - if(ext->one_line && letter_pos.y > letter_h) return true; - - /*If the cursor is out of the text (most right) draw it to the next line*/ - if(letter_pos.x + ext->label->coords.x1 + letter_w > ext->label->coords.x2 && ext->one_line == 0) { - letter_pos.x = 0; - letter_pos.y += letter_h + label_style->text.line_space; - - if(letter != '\0') { - byte_pos += lv_txt_encoded_size(&txt[byte_pos]); - letter = lv_txt_encoded_next(&txt[byte_pos], NULL); - } - - if(letter == '\0' || letter == '\n' || letter == '\r') { - letter_w = lv_font_get_width(label_style->text.font, ' '); - } else { - letter_w = lv_font_get_width(label_style->text.font, letter); - } - } - /*Draw he cursor according to the type*/ lv_area_t cur_area; + lv_area_copy(&cur_area, &ext->cursor.area); + + cur_area.x1 += ext->label->coords.x1; + cur_area.y1 += ext->label->coords.y1; + cur_area.x2 += ext->label->coords.x1; + cur_area.y2 += ext->label->coords.y1; + + lv_opa_t opa_scale = lv_obj_get_opa_scale(ta); + if(ext->cursor.type == LV_CURSOR_LINE) { - cur_area.x1 = letter_pos.x + ext->label->coords.x1 + cur_style.body.padding.hor - (cur_style.line.width >> 1) - (cur_style.line.width & 0x1); - cur_area.y1 = letter_pos.y + ext->label->coords.y1 + cur_style.body.padding.ver; - cur_area.x2 = letter_pos.x + ext->label->coords.x1 + cur_style.body.padding.hor + (cur_style.line.width >> 1); - cur_area.y2 = letter_pos.y + ext->label->coords.y1 + cur_style.body.padding.ver + letter_h; lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); } else if(ext->cursor.type == LV_CURSOR_BLOCK) { - cur_area.x1 = letter_pos.x + ext->label->coords.x1 - cur_style.body.padding.hor; - cur_area.y1 = letter_pos.y + ext->label->coords.y1 - cur_style.body.padding.ver; - cur_area.x2 = letter_pos.x + ext->label->coords.x1 + cur_style.body.padding.hor + letter_w; - cur_area.y2 = letter_pos.y + ext->label->coords.y1 + cur_style.body.padding.ver + letter_h; - lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); - /*Get the current letter*/ #if LV_TXT_UTF8 == 0 char letter_buf[2]; - letter_buf[0] = txt[byte_pos]; + letter_buf[0] = txt[ext->cursor.txt_byte_pos]; letter_buf[1] = '\0'; #else char letter_buf[8] = {0}; - memcpy(letter_buf, &txt[byte_pos], lv_txt_encoded_size(&txt[byte_pos])); + memcpy(letter_buf, &txt[ext->cursor.txt_byte_pos], lv_txt_encoded_size(&txt[ext->cursor.txt_byte_pos])); #endif cur_area.x1 += cur_style.body.padding.hor; cur_area.y1 += cur_style.body.padding.ver; lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, 0); } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { - cur_area.x1 = letter_pos.x + ext->label->coords.x1 - cur_style.body.padding.hor; - cur_area.y1 = letter_pos.y + ext->label->coords.y1 - cur_style.body.padding.ver; - cur_area.x2 = letter_pos.x + ext->label->coords.x1 + cur_style.body.padding.hor + letter_w; - cur_area.y2 = letter_pos.y + ext->label->coords.y1 + cur_style.body.padding.ver + letter_h; - cur_style.body.empty = 1; if(cur_style.body.border.width == 0) cur_style.body.border.width = 1; /*Be sure the border will be drawn*/ lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) { - cur_area.x1 = letter_pos.x + ext->label->coords.x1 + cur_style.body.padding.hor; - cur_area.y1 = letter_pos.y + ext->label->coords.y1 + cur_style.body.padding.ver + letter_h - (cur_style.line.width >> 1); - cur_area.x2 = letter_pos.x + ext->label->coords.x1 + cur_style.body.padding.hor + letter_w; - cur_area.y2 = letter_pos.y + ext->label->coords.y1 + cur_style.body.padding.ver + letter_h + (cur_style.line.width >> 1) + (cur_style.line.width & 0x1); - lv_draw_rect(&cur_area, mask, &cur_style, opa_scale); } - } return true; @@ -1105,6 +1039,8 @@ static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param) lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor); lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver); lv_label_set_text(ext->label, NULL); /*Refresh the label*/ + + refr_cursor_area(ta); } } } else if(sign == LV_SIGNAL_CONTROLL) { @@ -1197,8 +1133,15 @@ static void cursor_blink_anim(lv_obj_t * ta, uint8_t show) if(show != ext->cursor.state) { ext->cursor.state = show == 0 ? 0 : 1; if(ext->cursor.type != LV_CURSOR_NONE && - (ext->cursor.type & LV_CURSOR_HIDDEN) == 0) { - lv_obj_invalidate(ta); + (ext->cursor.type & LV_CURSOR_HIDDEN) == 0) + { + lv_area_t area_tmp; + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); } } } @@ -1276,4 +1219,129 @@ static bool char_is_accepted(lv_obj_t * ta, uint32_t c) } } + +static void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_style_t * label_style = lv_obj_get_style(ext->label); + + if(ext->cursor.style) { + lv_style_copy(style_res, ext->cursor.style); + } else { + /*If cursor style is not specified then use the modified label style */ + lv_style_copy(style_res, label_style); + lv_color_t clv_color_tmp = style_res->text.color; /*Make letter color to cursor color*/ + style_res->text.color = style_res->body.main_color; /*In block mode the letter color will be current background color*/ + style_res->body.main_color = clv_color_tmp; + style_res->body.grad_color = clv_color_tmp; + style_res->body.border.color = clv_color_tmp; + style_res->body.border.opa = LV_OPA_COVER; + style_res->body.border.width = 1; + style_res->body.shadow.width = 0; + style_res->body.radius = 0; + style_res->body.empty = 0; + style_res->body.padding.hor = 0; + style_res->body.padding.ver = 0; + style_res->line.width = 1; + style_res->body.opa = LV_OPA_COVER; + } + +} + +static void refr_cursor_area(lv_obj_t * ta) +{ + lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); + lv_style_t * label_style = lv_obj_get_style(ext->label); + + lv_style_t cur_style; + get_cursor_style(ta, &cur_style); + + uint16_t cur_pos = lv_ta_get_cursor_pos(ta); + const char * txt = lv_label_get_text(ext->label); + uint32_t byte_pos; +#if LV_TXT_UTF8 != 0 + byte_pos = lv_txt_encoded_get_byte_id(txt, cur_pos); + uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL); +#else + byte_pos = cur_pos; + uint32_t letter = txt[byte_pos]; +#endif + + lv_coord_t letter_h = lv_font_get_height(label_style->text.font); + /*Set letter_w (set not 0 on non printable but valid chars)*/ + lv_coord_t letter_w; + if(letter == '\0' || letter == '\n' || letter == '\r') { + letter_w = lv_font_get_width(label_style->text.font, ' '); + } else { + letter_w = lv_font_get_width(label_style->text.font, letter); + } + + lv_point_t letter_pos; + lv_label_get_letter_pos(ext->label, cur_pos, &letter_pos); + + /*If the cursor is out of the text (most right) draw it to the next line*/ + if(letter_pos.x + ext->label->coords.x1 + letter_w > ext->label->coords.x2 && ext->one_line == 0) { + letter_pos.x = 0; + letter_pos.y += letter_h + label_style->text.line_space; + + if(letter != '\0') { + byte_pos += lv_txt_encoded_size(&txt[byte_pos]); + letter = lv_txt_encoded_next(&txt[byte_pos], NULL); + } + + if(letter == '\0' || letter == '\n' || letter == '\r') { + letter_w = lv_font_get_width(label_style->text.font, ' '); + } else { + letter_w = lv_font_get_width(label_style->text.font, letter); + } + } + + /*Save the byte position. It is required to draw `LV_CURSOR_BLOCK`*/ + ext->cursor.txt_byte_pos = byte_pos; + + /*Draw he cursor according to the type*/ + lv_area_t cur_area; + + if(ext->cursor.type == LV_CURSOR_LINE) { + cur_area.x1 = letter_pos.x + cur_style.body.padding.hor - (cur_style.line.width >> 1) - (cur_style.line.width & 0x1); + cur_area.y1 = letter_pos.y + cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + (cur_style.line.width >> 1); + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + } else if(ext->cursor.type == LV_CURSOR_BLOCK) { + cur_area.x1 = letter_pos.x - cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y - cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + + } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { + cur_area.x1 = letter_pos.x - cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y - cur_style.body.padding.ver; + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h; + } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) { + cur_area.x1 = letter_pos.x + cur_style.body.padding.hor; + cur_area.y1 = letter_pos.y + cur_style.body.padding.ver + letter_h - (cur_style.line.width >> 1); + cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w; + cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h + (cur_style.line.width >> 1) + (cur_style.line.width & 0x1); + } + + /*Save the new area*/ + lv_area_t area_tmp; + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); + + lv_area_copy(&ext->cursor.area, &cur_area); + + lv_area_copy(&area_tmp, &ext->cursor.area); + area_tmp.x1 += ext->label->coords.x1; + area_tmp.y1 += ext->label->coords.y1; + area_tmp.x2 += ext->label->coords.x1; + area_tmp.y2 += ext->label->coords.y1; + lv_inv_area(&area_tmp); +} + #endif diff --git a/lv_objx/lv_ta.h b/lv_objx/lv_ta.h index 02a0ec40d..04eeb29eb 100644 --- a/lv_objx/lv_ta.h +++ b/lv_objx/lv_ta.h @@ -66,8 +66,10 @@ typedef struct uint8_t one_line :1; /*One line mode (ignore line breaks)*/ struct { lv_style_t *style; /*Style of the cursor (NULL to use label's style)*/ - lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ + lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ uint16_t pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ lv_cursor_type_t type:4; /*Shape of the cursor*/ uint8_t state :1; /*Indicates that the cursor is visible now or not (Handled by the library)*/ } cursor;