From 6f001958ceac7bb15b1c33ed1fc38b587a4e5c29 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 11 Oct 2019 12:01:58 +0200 Subject: [PATCH] bidi: fix btnm, kb, ta, table behaviour in RTL context --- src/lv_misc/lv_bidi.c | 10 +++---- src/lv_objx/lv_btnm.c | 20 ++++++++++++- src/lv_objx/lv_kb.c | 2 +- src/lv_objx/lv_label.c | 66 ++++++++++++++++++++++-------------------- src/lv_objx/lv_label.h | 4 --- src/lv_objx/lv_ta.c | 40 ++++++++++++------------- src/lv_objx/lv_table.c | 6 +++- 7 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/lv_misc/lv_bidi.c b/src/lv_misc/lv_bidi.c index 5e4a264c5..668ae180d 100644 --- a/src/lv_misc/lv_bidi.c +++ b/src/lv_misc/lv_bidi.c @@ -43,8 +43,10 @@ static uint32_t char_change_to_pair(uint32_t letter); void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir) { - printf("\nInput str: \"%s\"\n", str_in); + if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in); + + printf("\nInput str: \"%s\"\n", str_in); uint32_t par_start = 0; uint32_t par_len; @@ -68,9 +70,6 @@ void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir str_out[par_start] = '\0'; printf("\nOutput str: \"%s\"\n", str_out); - - - } lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt) @@ -86,7 +85,8 @@ lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt) } /*If there were no strong char earlier return with the default base dir */ - return LV_BIDI_BASE_DIR_DEF; + if(LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_AUTO) return LV_BIDI_DIR_LTR; + else return LV_BIDI_BASE_DIR_DEF; } lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter) diff --git a/src/lv_objx/lv_btnm.c b/src/lv_objx/lv_btnm.c index 179213a60..6493f1c94 100644 --- a/src/lv_objx/lv_btnm.c +++ b/src/lv_objx/lv_btnm.c @@ -644,7 +644,6 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo } /*Draw the object*/ else if(mode == LV_DESIGN_DRAW_MAIN) { - ancestor_design_f(btnm, mask, mode); lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); @@ -665,6 +664,10 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE; if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR; +#if LV_USE_BIDI + char * bidi_buf = lv_mem_alloc(64); + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm); +#endif for(btn_i = 0; btn_i < ext->btn_cnt; btn_i++, txt_i++) { /*Search the next valid text in the map*/ @@ -734,9 +737,24 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo area_tmp.x2 = area_tmp.x1 + txt_size.x; area_tmp.y2 = area_tmp.y1 + txt_size.y; +#if LV_USE_BIDI == 0 lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, -1, -1, NULL); +#else + uint32_t txt_len = strlen(ext->map_p[txt_i]) + 1; + if(txt_len > lv_mem_get_size(bidi_buf)) { + bidi_buf = lv_mem_realloc(bidi_buf, txt_len); + } + + lv_bidi_process(ext->map_p[txt_i], bidi_buf, base_dir); + lv_draw_label(&area_tmp, mask, btn_style, opa_scale, bidi_buf, txt_flag, NULL, -1, -1, NULL); +#endif } + +#if LV_USE_BIDI + lv_mem_free(bidi_buf); +#endif } + return true; } diff --git a/src/lv_objx/lv_kb.c b/src/lv_objx/lv_kb.c index 1229ffa8b..55d17b868 100644 --- a/src/lv_objx/lv_kb.c +++ b/src/lv_objx/lv_kb.c @@ -395,7 +395,7 @@ void lv_kb_def_event_cb(lv_obj_t * kb, lv_event_t event) /*Add the characters to the text area if set*/ if(ext->ta == NULL) return; - if(strcmp(txt, "Enter") == 0) + if(strcmp(txt, LV_SYMBOL_NEW_LINE) == 0) lv_ta_add_char(ext->ta, '\n'); else if(strcmp(txt, LV_SYMBOL_LEFT) == 0) lv_ta_cursor_left(ext->ta); diff --git a/src/lv_objx/lv_label.c b/src/lv_objx/lv_label.c index 34201342a..069ea9812 100644 --- a/src/lv_objx/lv_label.c +++ b/src/lv_objx/lv_label.c @@ -182,16 +182,7 @@ void lv_label_set_text(lv_obj_t * label, const char * text) /*If text is NULL then refresh */ if(text == NULL) { -#if LV_USE_BIDI == 0 lv_label_refr_text(label); -#else - lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label); - if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(ext->text_ori); - - lv_bidi_process(ext->text_ori, ext->text, base_dir); - lv_label_refr_text(label); -#endif - return; } @@ -208,11 +199,6 @@ void lv_label_set_text(lv_obj_t * label, const char * text) if(ext->text != NULL && ext->static_txt == 0) { lv_mem_free(ext->text); ext->text = NULL; - -#if LV_USE_BIDI - lv_mem_free(ext->text_ori); - ext->text_ori = NULL; -#endif } ext->text = lv_mem_alloc(len); @@ -222,16 +208,8 @@ void lv_label_set_text(lv_obj_t * label, const char * text) #if LV_USE_BIDI == 0 strcpy(ext->text, text); #else - ext->text_ori = lv_mem_alloc(len); - LV_ASSERT_MEM(ext->text_ori); - if(ext->text_ori == NULL) return; - - strcpy(ext->text_ori, text); - lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label); - if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(text); - - lv_bidi_process(ext->text_ori, ext->text, base_dir); + lv_bidi_process(text, ext->text, base_dir); #endif /*Now the text is dynamically allocated*/ ext->static_txt = 0; @@ -622,7 +600,10 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + lv_label_align_t align = lv_label_get_align(label); + if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; /*If the width will be expanded the set the max length to very big */ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { @@ -654,12 +635,12 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t if(index != line_start) x += style->text.letter_space; - if(ext->align == LV_LABEL_ALIGN_CENTER) { + if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; - } else if(ext->align == LV_LABEL_ALIGN_RIGHT) { + } else if(align == LV_LABEL_ALIGN_RIGHT) { lv_coord_t line_w; line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); @@ -694,7 +675,10 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + lv_label_align_t align = lv_label_get_align(label); + if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; /*If the width will be expanded set the max length to very big */ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { @@ -713,11 +697,16 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) /*Calculate the x coordinate*/ lv_coord_t x = 0; - if(ext->align == LV_LABEL_ALIGN_CENTER) { + if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; } + else if(align == LV_LABEL_ALIGN_RIGHT) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + x += lv_obj_get_width(label) - line_w; + } lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; @@ -1192,11 +1181,12 @@ static void lv_label_refr_text(lv_obj_t * label) /*In roll inf. mode keep the size but start offset animations*/ else if(ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) { #if LV_USE_ANIMATION + lv_label_align_t align = lv_label_get_align(label); + lv_anim_t anim; anim.var = label; anim.repeat = 1; anim.playback = 0; - anim.start = 0; anim.act_time = -(((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) / ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT; @@ -1207,7 +1197,14 @@ static void lv_label_refr_text(lv_obj_t * label) bool hor_anim = false; if(size.x > lv_obj_get_width(label)) { - anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + if(align == LV_LABEL_ALIGN_RIGHT) { + anim.end = 0; + anim.start = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + } else { + anim.start = 0; + anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + } + anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_x; anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); lv_anim_create(&anim); @@ -1219,7 +1216,14 @@ static void lv_label_refr_text(lv_obj_t * label) } if(size.y > lv_obj_get_height(label) && hor_anim == false) { - anim.end = -size.y - (lv_font_get_line_height(font)); + if(align == LV_LABEL_ALIGN_RIGHT) { + anim.end = 0; + anim.start = -size.y - (lv_font_get_line_height(font)); + } else { + anim.start = 0; + anim.end = -size.y - (lv_font_get_line_height(font)); + } + anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_y; anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); lv_anim_create(&anim); diff --git a/src/lv_objx/lv_label.h b/src/lv_objx/lv_label.h index 13a0f6eed..6660c3c9d 100644 --- a/src/lv_objx/lv_label.h +++ b/src/lv_objx/lv_label.h @@ -71,10 +71,6 @@ typedef struct /*New data for this type */ char * text; /*Text of the label*/ -#if LV_USE_BIDI - char * text_ori; /*The original text. With BiDi `text` stores the characters in "bidi" ordered text*/ -#endif - union { char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled diff --git a/src/lv_objx/lv_ta.c b/src/lv_objx/lv_ta.c index b3da2abf4..77ea629d4 100644 --- a/src/lv_objx/lv_ta.c +++ b/src/lv_objx/lv_ta.c @@ -1850,53 +1850,53 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign, lv_ lv_indev_get_vect(click_source, &vect_act); if(point_act.x < 0 || point_act.y < 0) return; /*Ignore event from keypad*/ - lv_point_t relative_position; - relative_position.x = point_act.x - label_coords.x1; - relative_position.y = point_act.y - label_coords.y1; + lv_point_t rel_pos; + rel_pos.x = point_act.x - label_coords.x1; + rel_pos.y = point_act.y - label_coords.y1; lv_coord_t label_width = lv_obj_get_width(ext->label); - uint16_t index_of_char_at_position; + uint16_t char_id_at_click; #if LV_LABEL_TEXT_SEL lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label); bool click_outside_label; /*Check if the click happened on the left side of the area outside the label*/ - if(relative_position.x < 0) { - index_of_char_at_position = 0; + if(rel_pos.x < 0) { + char_id_at_click = 0; click_outside_label = true; } /*Check if the click happened on the right side of the area outside the label*/ - else if(relative_position.x >= label_width) { - index_of_char_at_position = LV_TA_CURSOR_LAST; + else if(rel_pos.x >= label_width) { + char_id_at_click = LV_TA_CURSOR_LAST; click_outside_label = true; } else { - index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position); - click_outside_label = !lv_label_is_char_under_pos(ext->label, &relative_position); + char_id_at_click = lv_label_get_letter_on(ext->label, &rel_pos); + click_outside_label = !lv_label_is_char_under_pos(ext->label, &rel_pos); } if(ext->text_sel_en) { if(!ext->text_sel_in_prog && !click_outside_label && sign == LV_SIGNAL_PRESSED) { /*Input device just went down. Store the selection start position*/ - ext->tmp_sel_start = index_of_char_at_position; + ext->tmp_sel_start = char_id_at_click; ext->tmp_sel_end = LV_LABEL_TEXT_SEL_OFF; ext->text_sel_in_prog = 1; lv_obj_set_drag(lv_page_get_scrl(ta), false); } else if(ext->text_sel_in_prog && sign == LV_SIGNAL_PRESSING) { /*Input device may be moving. Store the end position */ - ext->tmp_sel_end = index_of_char_at_position; + ext->tmp_sel_end = char_id_at_click; } else if(ext->text_sel_in_prog && (sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED)) { /*Input device is released. Check if anything was selected.*/ lv_obj_set_drag(lv_page_get_scrl(ta), true); } } - if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, index_of_char_at_position); + if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, char_id_at_click); if(ext->text_sel_in_prog) { /*If the selected area has changed then update the real values and*/ - /*invalidate the text area.*/ + /*Invalidate the text area.*/ if(ext->tmp_sel_start > ext->tmp_sel_end) { if(ext_label->txt_sel_start != ext->tmp_sel_end || ext_label->txt_sel_end != ext->tmp_sel_start) { ext_label->txt_sel_start = ext->tmp_sel_end; @@ -1923,17 +1923,17 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign, lv_ } #else /*Check if the click happened on the left side of the area outside the label*/ - if(relative_position.x < 0) { - index_of_char_at_position = 0; + if(rel_pos.x < 0) { + char_id_at_click = 0; } /*Check if the click happened on the right side of the area outside the label*/ - else if(relative_position.x >= label_width) { - index_of_char_at_position = LV_TA_CURSOR_LAST; + else if(rel_pos.x >= label_width) { + char_id_at_click = LV_TA_CURSOR_LAST; } else { - index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position); + char_id_at_click = lv_label_get_letter_on(ext->label, &rel_pos); } - if(sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, index_of_char_at_position); + if(sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, char_id_at_click); #endif } diff --git a/src/lv_objx/lv_table.c b/src/lv_objx/lv_table.c index b99c055f1..52f8604ce 100644 --- a/src/lv_objx/lv_table.c +++ b/src/lv_objx/lv_table.c @@ -151,7 +151,11 @@ void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const } /*Initialize the format byte*/ else { - format.s.align = LV_LABEL_ALIGN_LEFT; + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(table); + if(base_dir == LV_BIDI_DIR_LTR) format.s.align = LV_LABEL_ALIGN_LEFT; + else if(base_dir == LV_BIDI_DIR_RTL) format.s.align = LV_LABEL_ALIGN_RIGHT; + else if(base_dir == LV_BIDI_DIR_AUTO) format.s.align = lv_bidi_detect_base_dir(txt); + format.s.right_merge = 0; format.s.type = 0; format.s.crop = 0;