From 7672847ce325e909981582b4153993025da7fe50 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 3 Aug 2021 16:02:22 +0200 Subject: [PATCH] fix(bidi) fix the handling of LV_BASE_DIR_AUTO in several widgets fixes #2421 --- .../widgets/textarea/lv_example_textarea_1.c | 4 ++- src/core/lv_obj_draw.c | 4 --- src/core/lv_obj_style.c | 9 ++++++ src/core/lv_obj_style.h | 2 ++ src/draw/lv_draw_label.c | 17 +++++++---- src/draw/lv_draw_label.h | 2 +- src/misc/lv_bidi.c | 10 +++++++ src/misc/lv_bidi.h | 24 +++++++++++++++ src/widgets/lv_dropdown.c | 6 +--- src/widgets/lv_label.c | 29 ++++--------------- src/widgets/lv_roller.c | 6 +--- src/widgets/lv_textarea.c | 7 ++--- 12 files changed, 70 insertions(+), 50 deletions(-) diff --git a/examples/widgets/textarea/lv_example_textarea_1.c b/examples/widgets/textarea/lv_example_textarea_1.c index cf7570972..52b90518d 100644 --- a/examples/widgets/textarea/lv_example_textarea_1.c +++ b/examples/widgets/textarea/lv_example_textarea_1.c @@ -22,7 +22,7 @@ static void btnm_event_handler(lv_event_t * e) void lv_example_textarea_1(void) { lv_obj_t * ta = lv_textarea_create(lv_scr_act()); - lv_textarea_set_one_line(ta, true); +// lv_textarea_set_one_line(ta, true); lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 10); lv_obj_add_event_cb(ta, textarea_event_handler, LV_EVENT_READY, ta); lv_obj_add_state(ta, LV_STATE_FOCUSED); /*To be sure the cursor is visible*/ @@ -38,6 +38,8 @@ void lv_example_textarea_1(void) lv_obj_add_event_cb(btnm, btnm_event_handler, LV_EVENT_VALUE_CHANGED, ta); lv_obj_clear_flag(btnm, LV_OBJ_FLAG_CLICK_FOCUSABLE); /*To keep the text area focused on button clicks*/ lv_btnmatrix_set_map(btnm, btnm_map); + + lv_textarea_set_text(ta, "שלום עולם!"); } #endif diff --git a/src/core/lv_obj_draw.c b/src/core/lv_obj_draw.c index a9b6dbf89..aa865edba 100644 --- a/src/core/lv_obj_draw.c +++ b/src/core/lv_obj_draw.c @@ -206,10 +206,6 @@ void lv_obj_init_draw_label_dsc(lv_obj_t * obj, uint32_t part, lv_draw_label_dsc #endif draw_dsc->align = lv_obj_get_style_text_align(obj, part); - if(draw_dsc->align == LV_TEXT_ALIGN_AUTO) { - if(draw_dsc->bidi_dir == LV_BASE_DIR_RTL) draw_dsc->align = LV_TEXT_ALIGN_RIGHT; - else draw_dsc->align = LV_TEXT_ALIGN_LEFT; - } } void lv_obj_init_draw_img_dsc(lv_obj_t * obj, uint32_t part, lv_draw_img_dsc_t * draw_dsc) diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c index 39be28e22..45e39fc43 100644 --- a/src/core/lv_obj_style.c +++ b/src/core/lv_obj_style.c @@ -457,6 +457,15 @@ lv_part_t lv_obj_style_get_selector_part(lv_style_selector_t selector) return selector & 0xFF0000; } + +lv_text_align_t lv_obj_calculate_style_text_align(struct _lv_obj_t * obj, lv_part_t part, const char * txt) +{ + lv_text_align_t align = lv_obj_get_style_text_align(obj, part); + lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, part); + lv_bidi_calculate_align(&align, &base_dir, txt); + return align; +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/core/lv_obj_style.h b/src/core/lv_obj_style.h index 0ccbb23f4..189e0197f 100644 --- a/src/core/lv_obj_style.h +++ b/src/core/lv_obj_style.h @@ -220,6 +220,8 @@ static inline void lv_obj_set_style_size(struct _lv_obj_t * obj, lv_coord_t val lv_obj_set_style_height(obj, value, selector); } +lv_text_align_t lv_obj_calculate_style_text_align(struct _lv_obj_t * obj, lv_part_t part, const char * txt); + /********************** * MACROS **********************/ diff --git a/src/draw/lv_draw_label.c b/src/draw/lv_draw_label.c index 1c686e1e3..c915dd864 100644 --- a/src/draw/lv_draw_label.c +++ b/src/draw/lv_draw_label.c @@ -128,6 +128,11 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area bool clip_ok = _lv_area_intersect(&clipped_area, coords, mask); if(!clip_ok) return; + lv_text_align_t align = dsc->align; + lv_base_dir_t base_dir = dsc->bidi_dir; + + lv_bidi_calculate_align(&align, &base_dir, txt); + if((dsc->flag & LV_TEXT_FLAG_EXPAND) == 0) { /*Normally use the label's width as width*/ w = lv_area_get_width(coords); @@ -193,14 +198,14 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area } /*Align to middle*/ - if(dsc->align == LV_TEXT_ALIGN_CENTER) { + if(align == LV_TEXT_ALIGN_CENTER) { line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); pos.x += (lv_area_get_width(coords) - line_width) / 2; } /*Align to the right*/ - else if(dsc->align == LV_TEXT_ALIGN_RIGHT) { + else if(align == LV_TEXT_ALIGN_RIGHT) { line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); pos.x += lv_area_get_width(coords) - line_width; } @@ -244,7 +249,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area i = 0; #if LV_USE_BIDI char * bidi_txt = lv_mem_buf_get(line_end - line_start + 1); - _lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, dsc->bidi_dir, NULL, 0); + _lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, base_dir, NULL, 0); #else const char * bidi_txt = txt + line_start; #endif @@ -255,7 +260,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area #if LV_USE_BIDI logical_char_pos = _lv_txt_encoded_get_char_id(txt, line_start); uint32_t t = _lv_txt_encoded_get_char_id(bidi_txt, i); - logical_char_pos += _lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, dsc->bidi_dir, t, NULL); + logical_char_pos += _lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, base_dir, t, NULL); #else logical_char_pos = _lv_txt_encoded_get_char_id(txt, line_start + i); #endif @@ -359,7 +364,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area pos.x = coords->x1; /*Align to middle*/ - if(dsc->align == LV_TEXT_ALIGN_CENTER) { + if(align == LV_TEXT_ALIGN_CENTER) { line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); @@ -367,7 +372,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area } /*Align to the right*/ - else if(dsc->align == LV_TEXT_ALIGN_RIGHT) { + else if(align == LV_TEXT_ALIGN_RIGHT) { line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); pos.x += lv_area_get_width(coords) - line_width; diff --git a/src/draw/lv_draw_label.h b/src/draw/lv_draw_label.h index fb71210d5..f4cc1fb88 100644 --- a/src/draw/lv_draw_label.h +++ b/src/draw/lv_draw_label.h @@ -40,8 +40,8 @@ typedef struct { lv_coord_t ofs_y; lv_opa_t opa; lv_base_dir_t bidi_dir; + lv_text_align_t align; lv_text_flag_t flag; - lv_text_align_t align :2; lv_text_decor_t decor : 3; lv_blend_mode_t blend_mode: 3; } lv_draw_label_dsc_t; diff --git a/src/misc/lv_bidi.c b/src/misc/lv_bidi.c index 906338348..4ea9bf774 100644 --- a/src/misc/lv_bidi.c +++ b/src/misc/lv_bidi.c @@ -305,6 +305,16 @@ void _lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t le } } +void lv_bidi_calculate_align(lv_text_align_t * align, lv_base_dir_t * base_dir, const char * txt) +{ + if(*base_dir == LV_BASE_DIR_AUTO) *base_dir = _lv_bidi_detect_base_dir(txt); + + if(*align == LV_TEXT_ALIGN_AUTO) { + if(*base_dir == LV_BASE_DIR_RTL) *align = LV_TEXT_ALIGN_RIGHT; + else *align = LV_TEXT_ALIGN_LEFT; + } +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/misc/lv_bidi.h b/src/misc/lv_bidi.h index d3a646e7d..a27b58086 100644 --- a/src/misc/lv_bidi.h +++ b/src/misc/lv_bidi.h @@ -17,6 +17,7 @@ extern "C" { #include #include +#include "lv_txt.h" /********************* * DEFINES @@ -104,10 +105,33 @@ uint16_t _lv_bidi_get_visual_pos(const char * str_in, char ** bidi_txt, uint16_t void _lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_base_dir_t base_dir, uint16_t * pos_conv_out, uint16_t pos_conv_len); +/** + * Get the real text alignment from the a text alignment, base direction and a text. + * @param align LV_TEXT_ALIGN_..., write back the calculated align here (LV_TEXT_ALIGN_LEFT/RIGHT/CENTER) + * @param base_dir LV_BASE_DIR_..., write the calculated base dir here (LV_BASE_DIR_LTR/RTL) + * @param txt a text, used with LV_BASE_DIR_AUTO to determine the base direction + */ +void lv_bidi_calculate_align(lv_text_align_t * align, lv_base_dir_t * base_dir, const char * txt); + + /********************** * MACROS **********************/ +#else /*LV_USE_BIDI*/ +/** + * For compatibility if LV_USE_BIDI = 0 + * Get the real text alignment from the a text alignment, base direction and a text. + * @param align For LV_TEXT_ALIGN_AUTO give LV_TEXT_ALIGN_LEFT else leave unchanged, write back the calculated align here + * @param base_dir Unused + * @param txt Unused + */ +static inline void lv_bidi_calculate_align(lv_text_align_t * align, lv_base_dir_t * base_dir, const char * txt) +{ + LV_UNUSED(txt); + LV_UNUSED(base_dir); + if(*align == LV_TEXT_ALIGN_AUTO) * align = LV_TEXT_ALIGN_LEFT; +} #endif /*LV_USE_BIDI*/ #ifdef __cplusplus diff --git a/src/widgets/lv_dropdown.c b/src/widgets/lv_dropdown.c index cba56b171..90bd31743 100644 --- a/src/widgets/lv_dropdown.c +++ b/src/widgets/lv_dropdown.c @@ -492,11 +492,7 @@ void lv_dropdown_open(lv_obj_t * dropdown_obj) } } - lv_text_align_t align = lv_obj_get_style_text_align(label, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(label, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } + lv_text_align_t align = lv_obj_calculate_style_text_align(label, LV_PART_MAIN, dropdown->options); switch(align) { default: diff --git a/src/widgets/lv_label.c b/src/widgets/lv_label.c index c71b74ada..4322edac0 100644 --- a/src/widgets/lv_label.c +++ b/src/widgets/lv_label.c @@ -288,12 +288,9 @@ void lv_label_get_letter_pos(const lv_obj_t * obj, uint32_t char_id, lv_point_t LV_ASSERT_OBJ(obj, MY_CLASS); LV_ASSERT_NULL(pos); + lv_label_t * label = (lv_label_t *)obj; const char * txt = lv_label_get_text(obj); - lv_text_align_t align = lv_obj_get_style_text_align(obj, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } + lv_text_align_t align = lv_obj_calculate_style_text_align(obj, LV_PART_MAIN, txt); if(txt[0] == '\0') { pos->y = 0; @@ -314,7 +311,6 @@ void lv_label_get_letter_pos(const lv_obj_t * obj, uint32_t char_id, lv_point_t lv_area_t txt_coords; lv_obj_get_content_coords(obj, &txt_coords); - lv_label_t * label = (lv_label_t *)obj; uint32_t line_start = 0; uint32_t new_line_start = 0; lv_coord_t max_w = lv_area_get_width(&txt_coords); @@ -427,11 +423,7 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in) if(label->expand != 0) flag |= LV_TEXT_FLAG_EXPAND; if(lv_obj_get_style_width(obj, LV_PART_MAIN) == LV_SIZE_CONTENT && !obj->w_layout) flag |= LV_TEXT_FLAG_FIT; - lv_text_align_t align = lv_obj_get_style_text_align(obj, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } + lv_text_align_t align = lv_obj_calculate_style_text_align(obj, LV_PART_MAIN, label->text); /*Search the line of the index letter*/; while(txt[line_start] != '\0') { @@ -542,11 +534,7 @@ bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos) lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); lv_coord_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN); lv_coord_t letter_height = lv_font_get_line_height(font); - lv_text_align_t align = lv_obj_get_style_text_align(obj, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } + lv_text_align_t align = lv_obj_calculate_style_text_align(obj, LV_PART_MAIN, label->text); lv_coord_t y = 0; lv_text_flag_t flag = LV_TEXT_FLAG_NONE; @@ -701,7 +689,6 @@ void lv_label_cut_text(lv_obj_t * obj, uint32_t pos, uint32_t cnt) lv_label_refr_text(obj); } - /********************** * STATIC FUNCTIONS **********************/ @@ -809,11 +796,6 @@ static void draw_main(lv_event_t * e) lv_area_t txt_coords; lv_obj_get_content_coords(obj, &txt_coords); - lv_text_align_t align = lv_obj_get_style_text_align(obj, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } lv_text_flag_t flag = LV_TEXT_FLAG_NONE; if(label->recolor != 0) flag |= LV_TEXT_FLAG_RECOLOR; if(label->expand != 0) flag |= LV_TEXT_FLAG_EXPAND; @@ -827,6 +809,7 @@ static void draw_main(lv_event_t * e) label_draw_dsc.flag = flag; lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_draw_dsc); + lv_bidi_calculate_align(&label_draw_dsc.align, &label_draw_dsc.bidi_dir, label->text); label_draw_dsc.sel_start = lv_label_get_text_selection_start(obj); label_draw_dsc.sel_end = lv_label_get_text_selection_end(obj); @@ -838,7 +821,7 @@ static void draw_main(lv_event_t * e) /* In SROLL and SROLL_CIRC mode the CENTER and RIGHT are pointless so remove them. * (In addition they will result misalignment is this case)*/ if((label->long_mode == LV_LABEL_LONG_SCROLL || label->long_mode == LV_LABEL_LONG_SCROLL_CIRCULAR) && - (align == LV_TEXT_ALIGN_CENTER || align == LV_TEXT_ALIGN_RIGHT)) { + (label_draw_dsc.align == LV_TEXT_ALIGN_CENTER || label_draw_dsc.align == LV_TEXT_ALIGN_RIGHT)) { lv_point_t size; lv_txt_get_size(&size, label->text, label_draw_dsc.font, label_draw_dsc.letter_space, label_draw_dsc.line_space, LV_COORD_MAX, flag); diff --git a/src/widgets/lv_roller.c b/src/widgets/lv_roller.c index 05bc450fd..40c4b4762 100644 --- a/src/widgets/lv_roller.c +++ b/src/widgets/lv_roller.c @@ -575,11 +575,7 @@ static void refr_position(lv_obj_t * obj, lv_anim_enable_t anim_en) lv_obj_t * label = get_label(obj); if(label == NULL) return; - lv_text_align_t align = lv_obj_get_style_text_align(label, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } + lv_text_align_t align = lv_obj_calculate_style_text_align(label, LV_PART_MAIN, lv_label_get_text(label)); switch(align) { case LV_TEXT_ALIGN_CENTER: diff --git a/src/widgets/lv_textarea.c b/src/widgets/lv_textarea.c index a979a965d..5a0fec351 100644 --- a/src/widgets/lv_textarea.c +++ b/src/widgets/lv_textarea.c @@ -247,6 +247,7 @@ void lv_textarea_del_char(lv_obj_t * obj) /*Delete a character*/ _lv_txt_cut(label_txt, ta->cursor.pos - 1, 1); + /*Refresh the label*/ lv_label_set_text(ta->label, label_txt); lv_textarea_clear_selection(obj); @@ -1076,11 +1077,7 @@ static void refr_cursor_area(lv_obj_t * obj) lv_point_t letter_pos; lv_label_get_letter_pos(ta->label, cur_pos, &letter_pos); - lv_text_align_t align = lv_obj_get_style_text_align(ta->label, LV_PART_MAIN); - if(align == LV_TEXT_ALIGN_AUTO) { - if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_TEXT_ALIGN_RIGHT; - else align = LV_TEXT_ALIGN_LEFT; - } + lv_text_align_t align = lv_obj_calculate_style_text_align(ta->label, LV_PART_MAIN, lv_label_get_text(ta->label)); /*If the cursor is out of the text (most right) draw it to the next line*/ if(letter_pos.x + ta->label->coords.x1 + letter_w > ta->label->coords.x2 && ta->one_line == 0 && align != LV_TEXT_ALIGN_RIGHT) {