lvgl/lvgl

Add support for CSS-like Text Leading-Trim

GIldons opened this issue · 5 comments

Problem to solve

Currently, LVGL text alignment within a container is based on the worst-case scenario height of a font as generated: The font height is calculated as the height between the descender and ascender lines, and its total height depends on the characters used to generate the font. For example, all other configs being equal, the generated font height will be different if generated for A-Z vs A-Z, a-z.

As a result, having, for a worst-case example, a label and an image added to a button will result in the label looking off-center and higher than the image if the font used for the label contains a non-zero descender height. This effect, however, can be noticed with just a label and is more noticeable with bigger font sizes.

This article has a quick description of the solution:
https://css-tricks.com/leading-trim-the-future-of-digital-typesetting/

This article has good examples of the problem
https://medium.com/microsoft-design/leading-trim-the-future-of-digital-typesetting-d082d84b202

Success criteria

Being able to archive proper vertical text alignment regardless of the character/font set used.

Solution outline

Add enough information to the generated fonts to allow trimming the text box for purposes of text alignment.

Rabbit holes

This might require a dedicated set of text_align functions, however, I think this might be accomplished using the generic lv_object_align functions.

Testing

Visual inspection of new font alignment including different sets of characters and fonts.

Teaching

Updated documentation code snippets.

Considerations

No response

Hey,

I'm thinking about translating the label with its baseline:

  lv_obj_t * cont = lv_obj_create(lv_screen_active());
  lv_obj_set_size(cont, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
  lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
  lv_obj_set_style_flex_cross_place(cont, LV_FLEX_ALIGN_END, 0);

  LV_IMAGE_DECLARE(emoji_F617);
  lv_obj_t * icon = lv_image_create(cont);
  lv_obj_set_pos(icon, 100, 100);
  lv_image_set_src(icon, &emoji_F617);

  lv_obj_t * label = lv_label_create(cont);
  lv_label_set_text(label, "Agy");
  lv_obj_set_style_text_font(label, &lv_font_montserrat_48, 0);
  lv_obj_set_pos(icon, 100, 100);

image

Adding

  lv_obj_set_style_translate_y(label, lv_font_montserrat_48.base_line, 0); /*offset by 9*/

image

What do you think about it?

I think this would address the initial request we had in the forum topic, however, this would not play well with general alignment.

If instead of calling lv_obj_set_pos, we call lv_obj_set_align on both the icon and the label, and to the result of that we translate the label by base_line, we are still going to be off alignment, as we are not taking into account the cap height.

With that said, I do think that what you proposed here has merit. What would be the strategy for this? Incorporate the translate call to a lv_label_set_pos kind of function?