lv_ta: check all characters in lv_ta_add/set_text agains accapted chars and max length

This commit is contained in:
Gabor Kiss-Vamosi
2018-08-09 23:37:00 +02:00
parent b0f7aeabbb
commit b521c8b97e
4 changed files with 93 additions and 43 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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);
/*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);
/*Don't let 'width == 0' because cursor will not be visible*/
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, ' '));
@@ -1035,26 +1052,7 @@ static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param)
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 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);

View File

@@ -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