diff --git a/src/misc/lv_text.c b/src/misc/lv_text.c index f563a66fa..d531176dd 100644 --- a/src/misc/lv_text.c +++ b/src/misc/lv_text.c @@ -164,12 +164,11 @@ void lv_text_get_size(lv_point_t * size_res, const char * text, const lv_font_t * @param max_width max width of the text (break the lines to fit this size). Set COORD_MAX to avoid line breaks * @param flags settings for the text from 'txt_flag_type' enum * @param[out] word_w_ptr width (in pixels) of the parsed word. May be NULL. - * @param force Force return the fraction of the word that can fit in the provided space. * @return the index of the first char of the next word (in byte index not letter index. With UTF-8 they are different) */ static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font, int32_t letter_space, int32_t max_width, - lv_text_flag_t flag, uint32_t * word_w_ptr, bool force) + lv_text_flag_t flag, uint32_t * word_w_ptr) { if(txt == NULL || txt[0] == '\0') return 0; if(font == NULL) return 0; @@ -239,14 +238,14 @@ static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font, #if LV_TXT_LINE_BREAK_LONG_LEN > 0 /*Word doesn't fit in provided space, but isn't "long"*/ if(word_len < LV_TXT_LINE_BREAK_LONG_LEN) { - if(force) return break_index; + if(flag & LV_TEXT_FLAG_BREAK_ALL) return break_index; if(word_w_ptr != NULL) *word_w_ptr = 0; /*Return no word*/ return 0; } /*Word is "long," but insufficient amounts can fit in provided space*/ if(break_letter_count < LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN) { - if(force) return break_index; + if(flag & LV_TEXT_FLAG_BREAK_ALL) return break_index; if(word_w_ptr != NULL) *word_w_ptr = 0; return 0; } @@ -266,7 +265,7 @@ static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font, } return i; #else - if(force) return break_index; + if(flag & LV_TEXT_FLAG_BREAK_ALL) return break_index; if(word_w_ptr != NULL) *word_w_ptr = 0; /*Return no word*/ (void) break_letter_count; return 0; @@ -301,8 +300,11 @@ uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font, uint32_t i = 0; /*Iterating index into txt*/ while(txt[i] != '\0' && max_width > 0) { + lv_text_flag_t word_flag = flag; + if(i == 0) word_flag |= LV_TEXT_FLAG_BREAK_ALL; + uint32_t word_w = 0; - uint32_t advance = lv_text_get_next_word(&txt[i], font, letter_space, max_width, flag, &word_w, i == 0); + uint32_t advance = lv_text_get_next_word(&txt[i], font, letter_space, max_width, word_flag, &word_w); max_width -= word_w; line_w += word_w; diff --git a/src/misc/lv_text.h b/src/misc/lv_text.h index ac5257d1b..0b8fd5d91 100644 --- a/src/misc/lv_text.h +++ b/src/misc/lv_text.h @@ -36,9 +36,13 @@ extern "C" { */ enum _lv_text_flag_t { - LV_TEXT_FLAG_NONE = 0x00, - LV_TEXT_FLAG_EXPAND = 0x01, /**< Ignore max-width to avoid automatic word wrapping*/ - LV_TEXT_FLAG_FIT = 0x02, /**< Max-width is already equal to the longest line. (Used to skip some calculation)*/ + LV_TEXT_FLAG_NONE = 0x00, + LV_TEXT_FLAG_EXPAND = 0x01, /**< Ignore max-width to avoid automatic word wrapping*/ + LV_TEXT_FLAG_FIT = 0x02, /**< Max-width is already equal to the longest line. (Used to skip some calculation)*/ + LV_TEXT_FLAG_BREAK_ALL = 0x04, /**< To prevent overflow, insert breaks between any two characters. + Otherwise breaks are inserted at word boundaries, as configured via LV_TXT_BREAK_CHARS + or according to LV_TXT_LINE_BREAK_LONG_LEN, LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN, + and LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN.*/ }; #ifdef DOXYGEN diff --git a/src/widgets/label/lv_label.c b/src/widgets/label/lv_label.c index ebebbe497..d1ca93320 100644 --- a/src/widgets/label/lv_label.c +++ b/src/widgets/label/lv_label.c @@ -291,11 +291,15 @@ 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); const int32_t max_w = lv_area_get_width(&txt_coords); + const int32_t max_h = lv_area_get_height(&txt_coords); int32_t y = 0; uint32_t line_start = 0; uint32_t new_line_start = 0; while(txt[new_line_start] != '\0') { + bool last_line = y + letter_height + line_space + letter_height > max_h; + if(last_line && label->long_mode == LV_LABEL_LONG_DOT) flag |= LV_TEXT_FLAG_BREAK_ALL; + new_line_start += lv_text_get_next_line(&txt[line_start], font, letter_space, max_w, NULL, flag); if(byte_id < new_line_start || txt[new_line_start] == '\0') break; /*The line of 'index' letter begins at 'line_start'*/ @@ -370,7 +374,8 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool const char * txt = lv_label_get_text(obj); uint32_t line_start = 0; uint32_t new_line_start = 0; - int32_t max_w = lv_area_get_width(&txt_coords); + int32_t max_w = lv_area_get_width(&txt_coords); + int32_t max_h = lv_area_get_height(&txt_coords); const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN); const int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); const int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN); @@ -381,6 +386,11 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool /*Search the line of the index letter*/; while(txt[line_start] != '\0') { + /*If dots will be shown, break the last visible line anywhere, + *not only at word boundaries.*/ + bool last_line = y + letter_height + line_space + letter_height > max_h; + if(last_line && label->long_mode == LV_LABEL_LONG_DOT) flag |= LV_TEXT_FLAG_BREAK_ALL; + new_line_start += lv_text_get_next_line(&txt[line_start], font, letter_space, max_w, NULL, flag); if(pos.y <= y + letter_height) { @@ -479,7 +489,8 @@ bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos) lv_label_t * label = (lv_label_t *)obj; uint32_t line_start = 0; uint32_t new_line_start = 0; - const int32_t max_w = lv_area_get_width(&txt_coords); + const int32_t max_w = lv_area_get_width(&txt_coords); + const int32_t max_h = lv_area_get_height(&txt_coords); const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN); const int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); const int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN); @@ -490,6 +501,9 @@ bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos) /*Search the line of the index letter*/ int32_t y = 0; while(txt[line_start] != '\0') { + bool last_line = y + letter_height + line_space + letter_height > max_h; + if(last_line && label->long_mode == LV_LABEL_LONG_DOT) flag |= LV_TEXT_FLAG_BREAK_ALL; + new_line_start += lv_text_get_next_line(&txt[line_start], font, letter_space, max_w, NULL, flag); if(pos->y <= y + letter_height) break; /*The line is found (stored in 'line_start')*/ diff --git a/tests/ref_imgs/widgets/label_max_width.png b/tests/ref_imgs/widgets/label_max_width.png index e11629adb..c254b4cd8 100644 Binary files a/tests/ref_imgs/widgets/label_max_width.png and b/tests/ref_imgs/widgets/label_max_width.png differ diff --git a/tests/ref_imgs_vg_lite/widgets/label_max_width.png b/tests/ref_imgs_vg_lite/widgets/label_max_width.png index 7f19d56b4..430cf1e5e 100644 Binary files a/tests/ref_imgs_vg_lite/widgets/label_max_width.png and b/tests/ref_imgs_vg_lite/widgets/label_max_width.png differ diff --git a/tests/src/test_cases/widgets/test_label.c b/tests/src/test_cases/widgets/test_label.c index c778b0308..e393b3238 100644 --- a/tests/src/test_cases/widgets/test_label.c +++ b/tests/src/test_cases/widgets/test_label.c @@ -598,6 +598,8 @@ void test_label_max_width(void) lv_label_set_text(test_label1, long_text); lv_obj_set_width(test_label1, 600); lv_obj_set_style_max_width(test_label1, 200, LV_PART_MAIN); + lv_obj_set_style_bg_color(test_label1, lv_palette_main(LV_PALETTE_GREY), LV_PART_MAIN); + lv_obj_set_style_bg_opa(test_label1, LV_OPA_100, LV_PART_MAIN); lv_obj_t * test_label2 = lv_label_create(lv_screen_active()); lv_label_set_text(test_label2, long_text); @@ -605,6 +607,8 @@ void test_label_max_width(void) lv_obj_set_height(test_label2, 50); lv_obj_set_x(test_label2, 300); lv_obj_set_style_max_width(test_label2, 200, LV_PART_MAIN); + lv_obj_set_style_bg_color(test_label2, lv_palette_main(LV_PALETTE_GREY), LV_PART_MAIN); + lv_obj_set_style_bg_opa(test_label2, LV_OPA_100, LV_PART_MAIN); lv_label_set_long_mode(test_label2, LV_LABEL_LONG_DOT); TEST_ASSERT_EQUAL_SCREENSHOT("widgets/label_max_width.png");