AutoScaling UI on LVGL

During my testing, I discovered a potential enhancement for LVGL that would greatly improve the portability of the same UI across various resolutions without doing many changes. This improvement can be achieved through a straightforward calculation:

Copy code

Size*LV_VER_RES/1000
Size*LV_HOR_RES/1000

Let’s consider a practical example:

lv_obj_set_size(chart, 400*LV_HOR_RES/1000, 200*LV_VER_RES/1000);
lv_obj_align(chart, LV_ALIGN_CENTER, 50*LV_HOR_RES/1000, 50*LV_VER_RES/1000);

However, I believe there is a more elegant solution to achieve this. It would be beneficial to introduce the following functions:

lv_obj_set_size_scaling(Obj, Direction (X or Y), Enabled/Disabled)
lv_obj_set_align_scaling(Obj, Direction (X or Y), Enabled/Disabled)

Also if the obj has the same Vertical and horizontal size or if it is a circle it should scale with only one property like only X or only Y so the obj wont become change the form

For sure we would also need these variables in the lv_conf.h file

/Maximal horizontal resolution/

#define LV_HOR_RES_MAX (480)

/Maximal vertical resolution/

#define LV_VER_RES_MAX (272)

I was thinking about something similar by adding the vw and vh units. In CSS they mean 1%of the viewport (display in our case) vertically or horizontally.

More info here: CSS Units

Indeed, I have been experimenting with converting my projects to utilize that qpercentage-based sizing and positioning, and the results have been quite promising. I hardly needed to rewrite anything except for adjusting the actual sizes and positions.

Another intriguing feature that LVGL could potentially incorporate is the automatic calculation of three optimal built-in fonts. This way, if auto-scaling is enabled, LVGL could dynamically adjust these fonts accordingly.

It it should work the best with some TTF libraries, like FreeType and TinyTTF.

I have successfully adapted one of my screens to be compatible with various resolutions, ensuring it is not designed solely for extremely small displays.

here some photos of it

800 x 480

480 x 272
image

Very nice!

This is cool.

I have thought about adding an automatic sizing feature that would scale everything properly and automatically. It would really be for a higher powered MCU like a raspberry pi 3 or higher and a larger display with a higher resolution something like 800 x 600 or better on a 7" or larger display. Use grab sashes where the user could resize things real time.

To keep processing down during a resize an outline of what is being resized would be displayed when the sash is grabbed and pulled, the outline would move with the resize. When the sash is let go then things would be scaled and resized as needed.

LVGL has the base pieces in place for this with lv_flex and lv_grid.

for structures you would have something along the lines of

typedef struct {
    uint8_t top;
    uint8_t bottom;
    uint8_t left;
    uint8_t right;
} lv_sizer_size_attrib_t;


typedef struct {
    uint8_t proportion;
    lv_sizer_size_attrib_t obj_padding;
    lv_sizer_size_attrib_t cell_outline;
    uint32_t flags;
    lv_obj_t * obj;
    struct _lv_sizer_t * sizer;
} lv_sizer_cell_t;


typedef struct _lv_sizer_t{
    lv_sizer_size_attrib_t cell_spacing;
    uint8_t num_cells;
    lv_sizer_cell_t * cells;
} lv_sizer_t;

typedef enum {
    LV_SIZER_HORIZONTAL = 0,
    LV_SIZER_VERTICAL = 1
} lv_sizer_direction_t;

typedef enum {
    LV_SIZER_TOP = 1,
    LV_SIZER_BOTTOM = 2,
    LV_SIZER_LEFT = 4,
    LV_SIZER_RIGHT = 8,
    LV_SIZER_EXPAND = 16,
    LV_SIZER_ALIGN_LEFT = 32,
    LV_SIZER_ALIGN_RIGHT = 64,
    LV_SIZER_ALIGN_TOP = 128,
    LV_SIZER_ALIGN_BOTTOM = 256
} lv_sizer_flags_t

have functions to set an object or a sizer into a sizer cell. proportions can be given for each cell item so as the sizer grows or shrinks the items in the sizer can grow or shrink at different rates. creating a horizontal sizer will only allow sizing horizontally and a vertical sizer would only grow vertically but if you place a vertical sizer into a horizontal sizer (or vice versa) then sizing in both directions can be done.

It’s fascinating to learn about the LVGL base, but the approach you proposed for auto scaling seems to focus more on constant resizing. If the resolution changes while the application is running, the screen will adapt accordingly. However, this isn’t exactly what I was looking for in this post. The scenario I’m concerned about is when I have an application designed for a 480 x 272 display, and then there’s an update or upgrade that requires a larger display. Without autoscaling, I’d have to rewrite a significant portion of LVGL components to accommodate the new display size.

1 Like

Could we consider it a new layout engine besides flex and grid?

The approach I mentioned above would be for handling sizing real time but it would also serve the function you would need it for as well. It would kill 2 birds with a single stone so to speak. The grab ashes would be able to be turned on and off thus allowing an automatic sizing but without allowing for dynamic size change after the program initially starts. In this use case you would set the minimum size of the first object to be the size of the display and populate out from that first object.

Yeah if it had that ON/OFF function would be killing two birds with a single stone as you said seems good to me also @kisvegabor i was looking for that functionality more like a property of a obj than a engine since this way we could be using the auto-scaling in single objects too

@kdschlosser
I can’t exactly see what is the added value of the proposed feature compared to flex, grid and align. Can you point out the difference?

Also there are any examples for it in other systems? CSS would be the best as we already follow CSS standard with other parts of LVGL already.

In web development, particularly in HTML and CSS, the use of techniques like auto scaling helps achieve consistent website appearance across different resolutions and ensures optimal functionality on various devices.

AutoScaling through these techniques can simplify the process of porting your code to different resolutions. It reduces the need for manual resizing or repositioning of elements, thus streamlining the adaptation of your LVGL-based application to various display sizes without compromising its visual integrity and user experience.

I’m uncertain about whether achieving this is possible using Grid or Flex layouts, and even if it is, I’m not sure if it’s an intuitive approach to do so.

wxWidgets uses a sizer based system.

It is going to be easier for you to login to a VM I have set up. wxPython is a complicated thing to compile. I will key up some code so you can see how the sizers work in that.

If that is something you want to do.

It is easier to see it working then it is to try and describe how it works.

It would be great to see some real life examples.

I’ve already checked out vxWidget’s sizers and I concluded that we can do all these with flex and LVGL’s current functionality in general, but maybe I was missing something.

you telling me to use a flex or a grid container in the whole screen or like in each objects to reach the auto scaling result?

(just so i know exacly what you talking becouse i didint ever used those two widgets)

Yes, nested grid and flex layouts work pretty well and they are quite powerful. In the practice I rarely set any coordinate directly but use:

  • flex: to place similar items (e.g. buttons, cards, icons, etc) next to or below each other (with or without special alignment rules or wrapping)
  • grid: to create complex table like layouts for different items (header, sidebar, footer, main area, etc). Items can be aligned inside the cells too and can span multiple cells as well.
  • LV_SIZE_CONTENT for width and/or height to set the size automatically according to the content
  • sometimes simple lv_align_obj() but usually with 0, 0 offset
  • padding on the parent item to set spacing on the edges
  • lv_pct() unit, usually lv_pct(100) to set full width and/or height items

You can learn more abut flex and grid here: Layouts — LVGL documentation

interesting but it would use more memory than having a *LV_HOR_RES/1000 right?

Yes, but more powerful as well. :slight_smile:

of course so at the end seems like having a new feature is not necessary but using a *LV_HOR_RES/1000 to scale the UI can save some time and for less powerful hardware would fit better?