From b521c8b97e9ccf5fca17899a46a4d53bd8feaa73 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 9 Aug 2018 23:37:00 +0200 Subject: [PATCH] lv_ta: check all characters in lv_ta_add/set_text agains accapted chars and max length --- lv_misc/lv_txt.c | 38 ++++++++++++++++++++++ lv_misc/lv_txt.h | 7 ++++ lv_objx/lv_ta.c | 84 +++++++++++++++++++++++++----------------------- lv_objx/lv_ta.h | 7 ++-- 4 files changed, 93 insertions(+), 43 deletions(-) diff --git a/lv_misc/lv_txt.c b/lv_misc/lv_txt.c index b3ba52208..295a6d49b 100644 --- a/lv_misc/lv_txt.c +++ b/lv_misc/lv_txt.c @@ -26,6 +26,7 @@ static bool is_break_char(uint32_t letter); #if LV_TXT_UTF8 static uint8_t lv_txt_utf8_size(const char * str); static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni); +static uint32_t lv_txt_utf8_conv_wc(uint32_t c); static uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i); static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start); static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id); @@ -34,6 +35,7 @@ static uint32_t lv_txt_utf8_get_length(const char * txt); #else static uint8_t lv_txt_ascii_size(const char * str); static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni); +static uint32_t lv_txt_ascii_conv_wc(uint32_t c); static uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i); static uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i_start); static uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id); @@ -52,6 +54,7 @@ static uint32_t lv_txt_ascii_get_length(const char * txt); #if LV_TXT_UTF8 uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_utf8_size; uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8; +uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc; uint32_t (*lv_txt_encoded_next)(const char * , uint32_t *) = lv_txt_utf8_next; uint32_t (*lv_txt_encoded_prev)(const char * , uint32_t * ) = lv_txt_utf8_prev; uint32_t (*txt_encoded_get_byte_id)(const char * , uint32_t) = lv_txt_utf8_get_byte_id; @@ -60,6 +63,7 @@ uint32_t (*lv_txt_get_encoded_length)(const char * ) = lv_txt_utf8_get_length #else uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_ascii_size; uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_ascii; +uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_ascii_conv_wc; uint32_t (*lv_txt_encoded_next)(const char * , uint32_t *) = lv_txt_ascii_next; uint32_t (*lv_txt_encoded_prev)(const char * , uint32_t * ) = lv_txt_ascii_prev; uint32_t (*txt_encoded_get_byte_id)(const char * , uint32_t) = lv_txt_ascii_get_byte_id; @@ -379,6 +383,29 @@ static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni) return *res_p; } +/** + * Convert a wide character, e.g. 'Á' little endian to be UTF-8 compatible + * @param c a wide character or a Little endian number + * @return `c` in big endian + */ +static uint32_t lv_txt_utf8_conv_wc(uint32_t c) +{ + /*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/ + if((c & 0x80) != 0) { + uint32_t swapped; + uint8_t c8[4]; + memcpy(c8, &c, 4); + swapped = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]); + uint8_t i; + for(i = 0; i < 4; i++) { + if((swapped & 0xFF) == 0) swapped = (swapped >> 8); /*Ignore leading zeros (they were in the end originally)*/ + } + c = swapped; + } + + return c; +} + /** * Decode an UTF-8 character from a string. * @param txt pointer to '\0' terminated string @@ -570,6 +597,17 @@ static uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni) else return ' '; } +/** + * Convert wide characters to ASCII, however wide characters in ASCII range (e.g. 'A') are ASCII compatible by default. + * So this function does nothing just returns with `c`. + * @param c a character, e.g. 'A' + * @return same as `c` + */ +static uint32_t lv_txt_ascii_conv_wc(uint32_t c) +{ + return c; +} + /** * Decode an UTF-8 character from a string. * @param txt pointer to '\0' terminated string diff --git a/lv_misc/lv_txt.h b/lv_misc/lv_txt.h index 5faa51adf..089833f25 100644 --- a/lv_misc/lv_txt.h +++ b/lv_misc/lv_txt.h @@ -134,6 +134,13 @@ extern uint8_t (*lv_txt_encoded_size)(const char *); */ extern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t ); +/** + * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format. + * @param c a wide character + * @return `c` in the encoded format + */ +extern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c); + /** * Decode the next encoded character from a string. * @param txt pointer to '\0' terminated string diff --git a/lv_objx/lv_ta.c b/lv_objx/lv_ta.c index 57c7da895..4c6490333 100644 --- a/lv_objx/lv_ta.c +++ b/lv_objx/lv_ta.c @@ -178,11 +178,12 @@ lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy) *=====================*/ /** - * Insert a character to the current cursor position + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')` * @param ta pointer to a text area object - * @param c a character + * @param c a character (e.g. 'a') */ -void lv_ta_add_char(lv_obj_t * ta, char c) +void lv_ta_add_char(lv_obj_t * ta, uint32_t c) { lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); @@ -191,17 +192,19 @@ void lv_ta_add_char(lv_obj_t * ta, char c) return; } - if(char_is_accepted(ta, c) == false) { + uint32_t c_uni = lv_txt_encoded_next(&c, NULL); + + if(char_is_accepted(ta, c_uni) == false) { LV_LOG_INFO("Character is no accepted by the text area (too long text or not in the accepted list)"); return; } if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ - char letter_buf[2]; + uint32_t letter_buf[2]; letter_buf[0] = c; letter_buf[1] = '\0'; - lv_label_ins_text(ext->label, ext->cursor.pos, letter_buf); /*Insert the character*/ + lv_label_ins_text(ext->label, ext->cursor.pos, (const char *)letter_buf); /*Insert the character*/ if(ext->pwd_mode != 0) { @@ -209,7 +212,7 @@ void lv_ta_add_char(lv_obj_t * ta, char c) lv_mem_assert(ext->pwd_tmp); if(ext->pwd_tmp== NULL) return; - lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, letter_buf); + lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, (const char *)letter_buf); #if USE_LV_ANIMATION /*Auto hide characters*/ @@ -247,13 +250,14 @@ void lv_ta_add_text(lv_obj_t * ta, const char * txt) if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ - /*If only one character is added check if it is accepted*/ - if(lv_txt_get_encoded_length(txt) == 1) { - uint32_t c = lv_txt_encoded_next(txt, NULL); - if(char_is_accepted(ta, c) == false) { - LV_LOG_INFO("Character is no accepted by the text area (too long text or not in the accepted list)"); - return; + /*Add the character one-by-one if not all characters are accepted or there is character limit.*/ + if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) { + uint32_t i = 0; + while(txt[i] != '\0') { + uint32_t c = lv_txt_encoded_next(txt, &i); + lv_ta_add_char(ta,lv_txt_unicode_to_encoded(c)); } + return; } /*Insert the text*/ @@ -342,10 +346,23 @@ void lv_ta_del_char(lv_obj_t * ta) void lv_ta_set_text(lv_obj_t * ta, const char * txt) { lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); - lv_label_set_text(ext->label, txt); - lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); - /*Don't let 'width == 0' because cursor will not be visible*/ + /*Add the character one-by-one if not all characters are accepted or there is character limit.*/ + if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) { + lv_label_set_text(ext->label, ""); + lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); + + uint32_t i = 0; + while(txt[i] != '\0') { + uint32_t c = lv_txt_encoded_next(txt, &i); + lv_ta_add_char(ta,lv_txt_unicode_to_encoded(c)); + } + } else { + lv_label_set_text(ext->label, txt); + lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST); + } + + /*Don't let 'width == 0' because the cursor will not be visible*/ if(lv_obj_get_width(ext->label) == 0) { lv_style_t * style = lv_obj_get_style(ext->label); lv_obj_set_width(ext->label, lv_font_get_width(style->text.font, ' ')); @@ -1029,32 +1046,13 @@ static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param) } } else if(sign == LV_SIGNAL_CONTROLL) { uint32_t c = *((uint32_t *)param); /*uint32_t because can be UTF-8*/ - if(c == LV_GROUP_KEY_RIGHT) lv_ta_cursor_right(ta); - else if(c == LV_GROUP_KEY_LEFT) lv_ta_cursor_left(ta); - else if(c == LV_GROUP_KEY_UP) lv_ta_cursor_up(ta); + if(c == LV_GROUP_KEY_RIGHT) lv_ta_cursor_right(ta); + else if(c == LV_GROUP_KEY_LEFT) lv_ta_cursor_left(ta); + else if(c == LV_GROUP_KEY_UP) lv_ta_cursor_up(ta); else if(c == LV_GROUP_KEY_DOWN) lv_ta_cursor_down(ta); - else if(c == LV_GROUP_KEY_DEL) lv_ta_del_char(ta); + else if(c == LV_GROUP_KEY_DEL) lv_ta_del_char(ta); else { -#if LV_TXT_UTF8 != 0 - /*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/ - if((c & 0x80) == 0) { /*ASCII*/ - lv_ta_add_char(ta, (char)c); - } else { - uint32_t swapped[2] = {0, 0}; /*the 2. element is the closing '\0'*/ - uint8_t c8[4]; - memcpy(c8, &c, 4); - swapped[0] = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]); - char * p = (char *)swapped; - uint8_t i; - for(i = 0; i < 4; i++) { - if(p[0] == 0) p++; /*Ignore leading zeros (they were in the end originally)*/ - } - lv_ta_add_text(ta, p); - } -#else - lv_ta_add_char(ta, (char)c); - -#endif + lv_ta_add_char(ta, c); } } else if(sign == LV_SIGNAL_GET_EDITABLE) { bool * editable = (bool *)param; @@ -1156,6 +1154,12 @@ static void pwd_char_hider(lv_obj_t * ta) } } +/** + * Test an unicode character if it is accepted or not. Checks max length and accepted char list. + * @param ta pointer to a test area object + * @param c an unicode character + * @return true: accapted; false: rejected + */ static bool char_is_accepted(lv_obj_t * ta, uint32_t c) { lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta); diff --git a/lv_objx/lv_ta.h b/lv_objx/lv_ta.h index de6b6b3f8..ee1d514d3 100644 --- a/lv_objx/lv_ta.h +++ b/lv_objx/lv_ta.h @@ -97,11 +97,12 @@ lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy); *=====================*/ /** - * Insert a character to the current cursor position + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')` * @param ta pointer to a text area object - * @param c a character + * @param c a character (e.g. 'a') */ -void lv_ta_add_char(lv_obj_t * ta, char c); +void lv_ta_add_char(lv_obj_t * ta, uint32_t c); /** * Insert a text to the current cursor position