Width calculation wrong in lv_txt_get_next_word

Width calculation handles letter_space not correct in lv_txt.c lv_txt_get_next_word

Target System

STM32F103 controller; not related to this issue though

Problem

When a styles text.letterspace is not 0 (e. g. 1, like mono theme does), the last letter is not printed.

Expectation:

When mono theme is used, a text on a button should be rendered completely

Code to reproduce

I used this code:

	th = lv_theme_mono_init(0, NULL);
	lv_theme_set_current(th);

	btn1 = lv_btn_create(lv_scr_act(), NULL);
	lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, -50);
	lv_obj_set_width(btn1, 100);
	label = lv_label_create(btn1, NULL);
	lv_label_set_static_text(label, "Button");

Possible cause

Commit f54ecc reordered code in lv_txt_get_next_word to address other problems in this field. This should be reviewed for a different solution

Use lv_label_set_text() instead of lv_label_set_static_text().

If you would like to use lv_label_set_static_text(),
you must create a static char* and link this var to lv_label_set_static_text().

Please note that the lv_label_set_text usage leads to the same problem. You may know that common compilers used for STM32 architectures put text literals into flash which are then static char arrays anyway.

The calculation in lv_txt_get_next_word sums up glyph widths and letter spaces, but does not take into account that the label width was calculated without the last letter spacing.

Compare:

static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font,
                              lv_coord_t letter_space, lv_coord_t max_width,
                              lv_txt_flag_t flag, uint32_t *word_w_ptr, lv_txt_cmd_state_t * cmd_state, bool force)
{
[...]
        letter_w = lv_font_get_glyph_width(font, letter, letter_next);
        cur_w += letter_w;

        if(letter_w > 0) {
            cur_w += letter_space;
        }

        /* Test if this character fits within max_width */
        if(break_index == NO_BREAK_FOUND && cur_w > max_width) {
            break_index = i; 
            break_letter_count = word_len - 1;
            /* break_index is now pointing at the character that doesn't fit */
        }
[...]
}

and

lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, const lv_font_t * font, lv_coord_t letter_space,
                            lv_txt_flag_t flag)
{
 [...]
        if(width > 0) {
            width -= letter_space; /*Trim the last letter space. Important if the text is center
                                      aligned */
        }
    }

    return width;
}

Consider the following patch as a workaround for this problem:

@@ -203,11 +203,11 @@ static uint16_t lv_txt_get_next_word(const char * txt, const lv_font_t * font,
         if(letter_w > 0) {
             cur_w += letter_space;
         }
 
         /* Test if this character fits within max_width */
-        if(break_index == NO_BREAK_FOUND && cur_w > max_width) {
+        if(break_index == NO_BREAK_FOUND && (cur_w - letter_space) > max_width) {
             break_index = i; 
             break_letter_count = word_len - 1;
             /* break_index is now pointing at the character that doesn't fit */
         }

Can you send a Pull request with these updates?

Here you go:

I’ve merged it, thank you!