1# Positions, sizes, and layouts 2 3## Overview 4Similarly to many other parts of LVGL, the concept of setting the coordinates was inspired by CSS. LVGL has by no means a complete implementation of CSS but a comparable subset is implemented (sometimes with minor adjustments). 5 6In short this means: 7- Explicitly set coordinates are stored in styles (size, position, layouts, etc.) 8- support min-width, max-width, min-height, max-height 9- have pixel, percentage, and "content" units 10- x=0; y=0 coordinate means the top-left corner of the parent plus the left/top padding plus border width 11- width/height means the full size, the "content area" is smaller with padding and border width 12- a subset of flexbox and grid layouts are supported 13 14### Units 15- pixel: Simply a position in pixels. An integer always means pixels. E.g. `lv_obj_set_x(btn, 10)` 16- percentage: The percentage of the size of the object or its parent (depending on the property). `lv_pct(value)` converts a value to percentage. E.g. `lv_obj_set_width(btn, lv_pct(50))` 17- `LV_SIZE_CONTENT`: Special value to set the width/height of an object to involve all the children. It's similar to `auto` in CSS. E.g. `lv_obj_set_width(btn, LV_SIZE_CONTENT)`. 18 19### Boxing model 20LVGL follows CSS's [border-box](https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing) model. 21An object's "box" is built from the following parts: 22- bounding box: the width/height of the elements. 23- border width: the width of the border. 24- padding: space between the sides of the object and its children. 25- content: the content area which is the size of the bounding box reduced by the border width and padding. 26 27![The box models of LVGL: The content area is smaller than the bounding box with the padding and border width](/misc/boxmodel.png) 28 29The border is drawn inside the bounding box. Inside the border LVGL keeps a "padding margin" when placing an object's children. 30 31The outline is drawn outside the bounding box. 32 33### Important notes 34This section describes special cases in which LVGL's behavior might be unexpected. 35 36#### Postponed coordinate calculation 37LVGL doesn't recalculate all the coordinate changes immediately. This is done to improve performance. 38Instead, the objects are marked as "dirty" and before redrawing the screen LVGL checks if there are any "dirty" objects. If so it refreshes their position, size and layout. 39 40In other words, if you need to get the coordinate of an object and the coordinates were just changed, LVGL needs to be forced to recalculate the coordinates. 41To do this call `lv_obj_update_layout(obj)`. 42 43The size and position might depend on the parent or layout. Therefore `lv_obj_update_layout` recalculates the coordinates of all objects on the screen of `obj`. 44 45#### Removing styles 46As it's described in the [Using styles](#using-styles) section, coordinates can also be set via style properties. 47To be more precise, under the hood every style coordinate related property is stored as a style property. If you use `lv_obj_set_x(obj, 20)` LVGL saves `x=20` in the local style of the object. 48 49This is an internal mechanism and doesn't matter much as you use LVGL. However, there is one case in which you need to be aware of the implementation. If the style(s) of an object are removed by 50```c 51lv_obj_remove_style_all(obj) 52``` 53 54or 55```c 56lv_obj_remove_style(obj, NULL, LV_PART_MAIN); 57``` 58the earlier set coordinates will be removed as well. 59 60For example: 61```c 62/*The size of obj1 will be set back to the default in the end*/ 63lv_obj_set_size(obj1, 200, 100); /*Now obj1 has 200;100 size*/ 64lv_obj_remove_style_all(obj1); /*It removes the set sizes*/ 65 66 67/*obj2 will have 200;100 size in the end */ 68lv_obj_remove_style_all(obj2); 69lv_obj_set_size(obj2, 200, 100); 70``` 71 72## Position 73 74### Simple way 75To simply set the x and y coordinates of an object use: 76```c 77lv_obj_set_x(obj, 10); //Separate... 78lv_obj_set_y(obj, 20); 79lv_obj_set_pos(obj, 10, 20); //Or in one function 80``` 81 82By default, the x and y coordinates are measured from the top left corner of the parent's content area. 83For example if the parent has five pixels of padding on every side the above code will place `obj` at (15, 25) because the content area starts after the padding. 84 85Percentage values are calculated from the parent's content area size. 86```c 87lv_obj_set_x(btn, lv_pct(10)); //x = 10 % of parent content area width 88``` 89 90### Align 91In some cases it's convenient to change the origin of the positioning from the default top left. If the origin is changed e.g. to bottom-right, the (0,0) position means: align to the bottom-right corner. 92To change the origin use: 93```c 94lv_obj_set_align(obj, align); 95``` 96 97To change the alignment and set new coordinates: 98```c 99lv_obj_align(obj, align, x, y); 100``` 101 102The following alignment options can be used: 103- `LV_ALIGN_TOP_LEFT` 104- `LV_ALIGN_TOP_MID` 105- `LV_ALIGN_TOP_RIGHT` 106- `LV_ALIGN_BOTTOM_LEFT` 107- `LV_ALIGN_BOTTOM_MID` 108- `LV_ALIGN_BOTTOM_RIGHT` 109- `LV_ALIGN_LEFT_MID` 110- `LV_ALIGN_RIGHT_MID` 111- `LV_ALIGN_CENTER` 112 113It's quite common to align a child to the center of its parent, therefore a dedicated function exists: 114```c 115lv_obj_center(obj); 116 117//Has the same effect 118lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0); 119``` 120 121If the parent's size changes, the set alignment and position of the children is updated automatically. 122 123The functions introduced above align the object to its parent. However, it's also possible to align an object to an arbitrary reference object. 124```c 125lv_obj_align_to(obj_to_align, reference_obj, align, x, y); 126``` 127 128Besides the alignments options above, the following can be used to align an object outside the reference object: 129 130- `LV_ALIGN_OUT_TOP_LEFT` 131- `LV_ALIGN_OUT_TOP_MID` 132- `LV_ALIGN_OUT_TOP_RIGHT` 133- `LV_ALIGN_OUT_BOTTOM_LEFT` 134- `LV_ALIGN_OUT_BOTTOM_MID` 135- `LV_ALIGN_OUT_BOTTOM_RIGHT` 136- `LV_ALIGN_OUT_LEFT_TOP` 137- `LV_ALIGN_OUT_LEFT_MID` 138- `LV_ALIGN_OUT_LEFT_BOTTOM` 139- `LV_ALIGN_OUT_RIGHT_TOP` 140- `LV_ALIGN_OUT_RIGHT_MID` 141- `LV_ALIGN_OUT_RIGHT_BOTTOM` 142 143For example to align a label above a button and center the label horizontally: 144```c 145lv_obj_align_to(label, btn, LV_ALIGN_OUT_TOP_MID, 0, -10); 146``` 147 148Note that, unlike with `lv_obj_align()`, `lv_obj_align_to()` can not realign the object if its coordinates or the reference object's coordinates change. 149 150## Size 151 152### Simple way 153The width and the height of an object can be set easily as well: 154```c 155lv_obj_set_width(obj, 200); //Separate... 156lv_obj_set_height(obj, 100); 157lv_obj_set_size(obj, 200, 100); //Or in one function 158``` 159 160Percentage values are calculated based on the parent's content area size. For example to set the object's height to the screen height: 161```c 162lv_obj_set_height(obj, lv_pct(100)); 163``` 164 165The size settings support a special value: `LV_SIZE_CONTENT`. It means the object's size in the respective direction will be set to the size of its children. 166Note that only children on the right and bottom sides will be considered and children on the top and left remain cropped. This limitation makes the behavior more predictable. 167 168Objects with `LV_OBJ_FLAG_HIDDEN` or `LV_OBJ_FLAG_FLOATING` will be ignored by the `LV_SIZE_CONTENT` calculation. 169 170The above functions set the size of an object's bounding box but the size of the content area can be set as well. This means an object's bounding box will be enlarged with the addition of padding. 171```c 172lv_obj_set_content_width(obj, 50); //The actual width: padding left + 50 + padding right 173lv_obj_set_content_height(obj, 30); //The actual width: padding top + 30 + padding bottom 174``` 175 176The size of the bounding box and the content area can be retrieved with the following functions: 177```c 178lv_coord_t w = lv_obj_get_width(obj); 179lv_coord_t h = lv_obj_get_height(obj); 180lv_coord_t content_w = lv_obj_get_content_width(obj); 181lv_coord_t content_h = lv_obj_get_content_height(obj); 182``` 183 184## Using styles 185Under the hood the position, size and alignment properties are style properties. 186The above described "simple functions" hide the style related code for the sake of simplicity and set the position, size, and alignment properties in the local styles of the object. 187 188However, using styles to set the coordinates has some great advantages: 189- It makes it easy to set the width/height/etc. for several objects together. E.g. make all the sliders 100x10 pixels sized. 190- It also makes possible to modify the values in one place. 191- The values can be partially overwritten by other styles. For example `style_btn` makes the object `100x50` by default but adding `style_full_width` overwrites only the width of the object. 192- The object can have different position or size depending on state. E.g. 100 px wide in `LV_STATE_DEFAULT` but 120 px in `LV_STATE_PRESSED`. 193- Style transitions can be used to make the coordinate changes smooth. 194 195 196Here are some examples to set an object's size using a style: 197```c 198static lv_style_t style; 199lv_style_init(&style); 200lv_style_set_width(&style, 100); 201 202lv_obj_t * btn = lv_btn_create(lv_scr_act()); 203lv_obj_add_style(btn, &style, LV_PART_MAIN); 204``` 205 206As you will see below there are some other great features of size and position setting. 207However, to keep the LVGL API lean, only the most common coordinate setting features have a "simple" version and the more complex features can be used via styles. 208 209## Translation 210 211Let's say the there are 3 buttons next to each other. Their position is set as described above. 212Now you want to move a button up a little when it's pressed. 213 214One way to achieve this is by setting a new Y coordinate for the pressed state: 215```c 216static lv_style_t style_normal; 217lv_style_init(&style_normal); 218lv_style_set_y(&style_normal, 100); 219 220static lv_style_t style_pressed; 221lv_style_init(&style_pressed); 222lv_style_set_y(&style_pressed, 80); 223 224lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT); 225lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED); 226 227lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT); 228lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED); 229 230lv_obj_add_style(btn3, &style_normal, LV_STATE_DEFAULT); 231lv_obj_add_style(btn3, &style_pressed, LV_STATE_PRESSED); 232``` 233 234This works, but it's not really flexible because the pressed coordinate is hard-coded. If the buttons are not at y=100, `style_pressed` won't work as expected. Translations can be used to solve this: 235```c 236static lv_style_t style_normal; 237lv_style_init(&style_normal); 238lv_style_set_y(&style_normal, 100); 239 240static lv_style_t style_pressed; 241lv_style_init(&style_pressed); 242lv_style_set_translate_y(&style_pressed, -20); 243 244lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT); 245lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED); 246 247lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT); 248lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED); 249 250lv_obj_add_style(btn3, &style_normal, LV_STATE_DEFAULT); 251lv_obj_add_style(btn3, &style_pressed, LV_STATE_PRESSED); 252``` 253 254Translation is applied from the current position of the object. 255 256Percentage values can be used in translations as well. The percentage is relative to the size of the object (and not to the size of the parent). For example `lv_pct(50)` will move the object with half of its width/height. 257 258The translation is applied after the layouts are calculated. Therefore, even laid out objects' position can be translated. 259 260The translation actually moves the object. That means it makes the scrollbars and `LV_SIZE_CONTENT` sized objects react to the position change. 261 262 263## Transformation 264Similarly to position, an object's size can be changed relative to the current size as well. 265The transformed width and height are added on both sides of the object. This means a 10 px transformed width makes the object 2x10 pixels wider. 266 267Unlike position translation, the size transformation doesn't make the object "really" larger. In other words scrollbars, layouts, and `LV_SIZE_CONTENT` will not react to the transformed size. 268Hence, size transformation is "only" a visual effect. 269 270This code enlarges a button when it's pressed: 271```c 272static lv_style_t style_pressed; 273lv_style_init(&style_pressed); 274lv_style_set_transform_width(&style_pressed, 10); 275lv_style_set_transform_height(&style_pressed, 10); 276 277lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED); 278``` 279 280### Min and Max size 281Similarly to CSS, LVGL also supports `min-width`, `max-width`, `min-height` and `max-height`. These are limits preventing an object's size from becoming smaller/larger than these values. 282They are especially useful if the size is set by percentage or `LV_SIZE_CONTENT`. 283```c 284static lv_style_t style_max_height; 285lv_style_init(&style_max_height); 286lv_style_set_y(&style_max_height, 200); 287 288lv_obj_set_height(obj, lv_pct(100)); 289lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //Limit the height to 200 px 290``` 291 292Percentage values can be used as well which are relative to the size of the parent's content area. 293```c 294static lv_style_t style_max_height; 295lv_style_init(&style_max_height); 296lv_style_set_y(&style_max_height, lv_pct(50)); 297 298lv_obj_set_height(obj, lv_pct(100)); 299lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //Limit the height to half parent height 300``` 301 302## Layout 303 304### Overview 305Layouts can update the position and size of an object's children. They can be used to automatically arrange the children into a line or column, or in much more complicated forms. 306 307The position and size set by the layout overwrites the "normal" x, y, width, and height settings. 308 309There is only one function that is the same for every layout: `lv_obj_set_layout(obj, <LAYOUT_NAME>)` sets the layout on an object. 310For further settings of the parent and children see the documentation of the given layout. 311 312### Built-in layout 313LVGL comes with two very powerful layouts: 314- Flexbox 315- Grid 316 317Both are heavily inspired by the CSS layouts with the same name. 318 319### Flags 320There are some flags that can be used on objects to affect how they behave with layouts: 321- `LV_OBJ_FLAG_HIDDEN` Hidden objects are ignored in layout calculations. 322- `LV_OBJ_FLAG_IGNORE_LAYOUT` The object is simply ignored by the layouts. Its coordinates can be set as usual. 323- `LV_OBJ_FLAG_FLOATING` Same as `LV_OBJ_FLAG_IGNORE_LAYOUT` but the object with `LV_OBJ_FLAG_FLOATING` will be ignored in `LV_SIZE_CONTENT` calculations. 324 325These flags can be added/removed with `lv_obj_add/clear_flag(obj, FLAG);` 326 327### Adding new layouts 328 329LVGL can be freely extended by a custom layout like this: 330```c 331uint32_t MY_LAYOUT; 332 333... 334 335MY_LAYOUT = lv_layout_register(my_layout_update, &user_data); 336 337... 338 339void my_layout_update(lv_obj_t * obj, void * user_data) 340{ 341 /*Will be called automatically if it's required to reposition/resize the children of "obj" */ 342} 343``` 344 345Custom style properties can be added which can be retrieved and used in the update callback. For example: 346```c 347uint32_t MY_PROP; 348... 349 350LV_STYLE_MY_PROP = lv_style_register_prop(); 351 352... 353static inline void lv_style_set_my_prop(lv_style_t * style, uint32_t value) 354{ 355 lv_style_value_t v = { 356 .num = (int32_t)value 357 }; 358 lv_style_set_prop(style, LV_STYLE_MY_PROP, v); 359} 360 361``` 362 363## Examples 364