acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

coords.md (15079B)

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