1# Styles 2 3*Styles* are used to set the appearance of objects. Styles in lvgl are heavily inspired by CSS. The concept in a nutshell is as follows: 4- A style is an `lv_style_t` variable which can hold properties like border width, text color and so on. It's similar to a `class` in CSS. 5- Styles can be assigned to objects to change their appearance. Upon assignment, the target part (*pseudo-element* in CSS) and target state (*pseudo class*) can be specified. 6For example one can add `style_blue` to the knob of a slider when it's in pressed state. 7- The same style can be used by any number of objects. 8- Styles can be cascaded which means multiple styles may be assigned to an object and each style can have different properties. 9Therefore, not all properties have to be specified in a style. LVGL will search for a property until a style defines it or use a default if it's not specified by any of the styles. 10For example `style_btn` can result in a default gray button and `style_btn_red` can add only a `background-color=red` to overwrite the background color. 11- The most recently added style has higher precedence. This means if a property is specified in two styles the newest style in the object will be used. 12- Some properties (e.g. text color) can be inherited from a parent(s) if it's not specified in an object. 13- Objects can also have local styles with higher precedence than "normal" styles. 14- Unlike CSS (where pseudo-classes describe different states, e.g. `:focus`), in LVGL a property is assigned to a given state. 15- Transitions can be applied when the object changes state. 16 17 18## States 19The objects can be in the combination of the following states: 20- `LV_STATE_DEFAULT` (0x0000) Normal, released state 21- `LV_STATE_CHECKED` (0x0001) Toggled or checked state 22- `LV_STATE_FOCUSED` (0x0002) Focused via keypad or encoder or clicked via touchpad/mouse 23- `LV_STATE_FOCUS_KEY` (0x0004) Focused via keypad or encoder but not via touchpad/mouse 24- `LV_STATE_EDITED` (0x0008) Edit by an encoder 25- `LV_STATE_HOVERED` (0x0010) Hovered by mouse (not supported now) 26- `LV_STATE_PRESSED` (0x0020) Being pressed 27- `LV_STATE_SCROLLED` (0x0040) Being scrolled 28- `LV_STATE_DISABLED` (0x0080) Disabled state 29- `LV_STATE_USER_1` (0x1000) Custom state 30- `LV_STATE_USER_2` (0x2000) Custom state 31- `LV_STATE_USER_3` (0x4000) Custom state 32- `LV_STATE_USER_4` (0x8000) Custom state 33 34An object can be in a combination of states such as being focused and pressed at the same time. This is represented as `LV_STATE_FOCUSED | LV_STATE_PRESSED`. 35 36A style can be added to any state or state combination. 37For example, setting a different background color for the default and pressed states. 38If a property is not defined in a state the best matching state's property will be used. Typically this means the property with `LV_STATE_DEFAULT` is used.˛ 39If the property is not set even for the default state the default value will be used. (See later) 40 41But what does the "best matching state's property" really mean? 42States have a precedence which is shown by their value (see in the above list). A higher value means higher precedence. 43To determine which state's property to use let's take an example. Imagine the background color is defined like this: 44- `LV_STATE_DEFAULT`: white 45- `LV_STATE_PRESSED`: gray 46- `LV_STATE_FOCUSED`: red 47 481. Initially the object is in the default state, so it's a simple case: the property is perfectly defined in the object's current state as white. 492. When the object is pressed there are 2 related properties: default with white (default is related to every state) and pressed with gray. 50The pressed state has 0x0020 precedence which is higher than the default state's 0x0000 precedence, so gray color will be used. 513. When the object is focused the same thing happens as in pressed state and red color will be used. (Focused state has higher precedence than default state). 524. When the object is focused and pressed both gray and red would work, but the pressed state has higher precedence than focused so gray color will be used. 535. It's possible to set e.g. rose color for `LV_STATE_PRESSED | LV_STATE_FOCUSED`. 54In this case, this combined state has 0x0020 + 0x0002 = 0x0022 precedence, which is higher than the pressed state's precedence so rose color would be used. 556. When the object is in the checked state there is no property to set the background color for this state. So for lack of a better option, the object remains white from the default state's property. 56 57Some practical notes: 58- The precedence (value) of states is quite intuitive, and it's something the user would expect naturally. E.g. if an object is focused the user will still want to see if it's pressed, therefore the pressed state has a higher precedence. 59If the focused state had a higher precedence it would overwrite the pressed color. 60- If you want to set a property for all states (e.g. red background color) just set it for the default state. If the object can't find a property for its current state it will fall back to the default state's property. 61- Use ORed states to describe the properties for complex cases. (E.g. pressed + checked + focused) 62- It might be a good idea to use different style elements for different states. 63For example, finding background colors for released, pressed, checked + pressed, focused, focused + pressed, focused + pressed + checked, etc. states is quite difficult. 64Instead, for example, use the background color for pressed and checked states and indicate the focused state with a different border color. 65 66## Cascading styles 67It's not required to set all the properties in one style. It's possible to add more styles to an object and have the latter added style modify or extend appearance. 68For example, create a general gray button style and create a new one for red buttons where only the new background color is set. 69 70This is much like in CSS when used classes are listed like `<div class=".btn .btn-red">`. 71 72Styles added later have precedence over ones set earlier. So in the gray/red button example above, the normal button style should be added first and the red style second. 73However, the precedence of the states are still taken into account. 74So let's examine the following case: 75- the basic button style defines dark-gray color for the default state and light-gray color for the pressed state 76- the red button style defines the background color as red only in the default state 77 78In this case, when the button is released (it's in default state) it will be red because a perfect match is found in the most recently added style (red). 79When the button is pressed the light-gray color is a better match because it describes the current state perfectly, so the button will be light-gray. 80 81## Inheritance 82Some properties (typically those related to text) can be inherited from the parent object's styles. 83Inheritance is applied only if the given property is not set in the object's styles (even in default state). 84In this case, if the property is inheritable, the property's value will be searched in the parents until an object specifies a value for the property. The parents will use their own state to determine the value. 85So if a button is pressed, and the text color comes from here, the pressed text color will be used. 86 87## Forced value inheritance/default value 88Sometimes you may want to force a child object to use the parent's value for a given style property. To do this you can use 89one of the following (depending on what type of style you're using): 90 91```c 92/* regular style */ 93lv_style_set_prop_meta(&style, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT); 94/* local style */ 95lv_obj_set_local_style_prop_meta(child, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT, LV_PART_MAIN); 96``` 97 98This acts like a value has been set on the style, so setting the value of the property afterwards will remove the flag. 99 100You may also want to force the default value of a property to be used, without needing to hardcode it in your application. 101To do this you can use the same API but with `LV_STYLE_PROP_META_INITIAL` instead. In future versions of LVGL, this 102will use the value based upon the current theme, but for now it just selects the internal default regardless of theme. 103 104 105## Parts 106Objects can be composed of *parts* which may each have their own styles. 107 108The following predefined parts exist in LVGL: 109- `LV_PART_MAIN` A background like rectangle 110- `LV_PART_SCROLLBAR` The scrollbar(s) 111- `LV_PART_INDICATOR` Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox 112- `LV_PART_KNOB` Like a handle to grab to adjust a value 113- `LV_PART_SELECTED` Indicate the currently selected option or section 114- `LV_PART_ITEMS` Used if the widget has multiple similar elements (e.g. table cells) 115- `LV_PART_TICKS` Ticks on scales e.g. for a chart or meter 116- `LV_PART_CURSOR` Mark a specific place e.g. text area's or chart's cursor 117- `LV_PART_CUSTOM_FIRST` Custom part identifiers can be added starting from here. 118 119 120For example a [Slider](/widgets/core/slider) has three parts: 121- Background 122- Indicator 123- Knob 124 125This means all three parts of the slider can have their own styles. See later how to add styles to objects and parts. 126 127## Initialize styles and set/get properties 128 129Styles are stored in `lv_style_t` variables. Style variables should be `static`, global or dynamically allocated. 130In other words they cannot be local variables in functions which are destroyed when the function exits. 131Before using a style it should be initialized with `lv_style_init(&my_style)`. 132After initializing a style, properties can be added or changed. 133 134Property set functions looks like this: `lv_style_set_<property_name>(&style, <value>);` For example: 135```c 136static lv_style_t style_btn; 137lv_style_init(&style_btn); 138lv_style_set_bg_color(&style_btn, lv_color_hex(0x115588)); 139lv_style_set_bg_opa(&style_btn, LV_OPA_50); 140lv_style_set_border_width(&style_btn, 2); 141lv_style_set_border_color(&style_btn, lv_color_black()); 142 143static lv_style_t style_btn_red; 144lv_style_init(&style_btn_red); 145lv_style_set_bg_color(&style_btn_red, lv_plaette_main(LV_PALETTE_RED)); 146lv_style_set_bg_opa(&style_btn_red, LV_OPA_COVER); 147``` 148 149To remove a property use: 150 151```c 152lv_style_remove_prop(&style, LV_STYLE_BG_COLOR); 153``` 154 155To get a property's value from a style: 156```c 157lv_style_value_t v; 158lv_res_t res = lv_style_get_prop(&style, LV_STYLE_BG_COLOR, &v); 159if(res == LV_RES_OK) { /*Found*/ 160 do_something(v.color); 161} 162``` 163 164`lv_style_value_t` has 3 fields: 165- `num` for integer, boolean and opacity properties 166- `color` for color properties 167- `ptr` for pointer properties 168 169To reset a style (free all its data) use: 170```c 171lv_style_reset(&style); 172``` 173 174Styles can be built as `const` too to save RAM: 175```c 176const lv_style_const_prop_t style1_props[] = { 177 LV_STYLE_CONST_WIDTH(50), 178 LV_STYLE_CONST_HEIGHT(50), 179 LV_STYLE_PROP_INV, 180}; 181 182LV_STYLE_CONST_INIT(style1, style1_props); 183``` 184 185Later `const` style can be used like any other style but (obviously) new properties can not be added. 186 187 188## Add and remove styles to a widget 189A style on its own is not that useful. It must be assigned to an object to take effect. 190 191### Add styles 192To add a style to an object use `lv_obj_add_style(obj, &style, <selector>)`. `<selector>` is an OR-ed value of parts and state to which the style should be added. Some examples: 193- `LV_PART_MAIN | LV_STATE_DEFAULT` 194- `LV_STATE_PRESSED`: The main part in pressed state. `LV_PART_MAIN` can be omitted 195- `LV_PART_SCROLLBAR`: The scrollbar part in the default state. `LV_STATE_DEFAULT` can be omitted. 196- `LV_PART_SCROLLBAR | LV_STATE_SCROLLED`: The scrollbar part when the object is being scrolled 197- `0` Same as `LV_PART_MAIN | LV_STATE_DEFAULT`. 198- `LV_PART_INDICATOR | LV_STATE_PRESSED | LV_STATE_CHECKED` The indicator part when the object is pressed and checked at the same time. 199 200Using `lv_obj_add_style`: 201```c 202lv_obj_add_style(btn, &style_btn, 0); /*Default button style*/ 203lv_obj_add_style(btn, &btn_red, LV_STATE_PRESSED); /*Overwrite only some colors to red when pressed*/ 204``` 205 206### Remove styles 207To remove all styles from an object use `lv_obj_remove_style_all(obj)`. 208 209To remove specific styles use `lv_obj_remove_style(obj, style, selector)`. This function will remove `style` only if the `selector` matches with the `selector` used in `lv_obj_add_style`. 210`style` can be `NULL` to check only the `selector` and remove all matching styles. The `selector` can use the `LV_STATE_ANY` and `LV_PART_ANY` values to remove the style from any state or part. 211 212 213### Report style changes 214If a style which is already assigned to an object changes (i.e. a property is added or changed), the objects using that style should be notified. There are 3 options to do this: 2151. If you know that the changed properties can be applied by a simple redraw (e.g. color or opacity changes) just call `lv_obj_invalidate(obj)` or `lv_obj_invalidate(lv_scr_act())`. 2162. If more complex style properties were changed or added, and you know which object(s) are affected by that style call `lv_obj_refresh_style(obj, part, property)`. 217To refresh all parts and properties use `lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY)`. 2183. To make LVGL check all objects to see if they use a style and refresh them when needed, call `lv_obj_report_style_change(&style)`. If `style` is `NULL` all objects will be notified about a style change. 219 220### Get a property's value on an object 221To get a final value of property - considering cascading, inheritance, local styles and transitions (see below) - property get functions like this can be used: 222`lv_obj_get_style_<property_name>(obj, <part>)`. 223These functions use the object's current state and if no better candidate exists they return a default value. 224For example: 225```c 226lv_color_t color = lv_obj_get_style_bg_color(btn, LV_PART_MAIN); 227``` 228 229## Local styles 230In addition to "normal" styles, objects can also store local styles. This concept is similar to inline styles in CSS (e.g. `<div style="color:red">`) with some modification. 231 232Local styles are like normal styles, but they can't be shared among other objects. If used, local styles are allocated automatically, and freed when the object is deleted. 233They are useful to add local customization to an object. 234 235Unlike in CSS, LVGL local styles can be assigned to states (*pseudo-classes*) and parts (*pseudo-elements*). 236 237To set a local property use functions like `lv_obj_set_style_<property_name>(obj, <value>, <selector>);` 238For example: 239```c 240lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED); 241``` 242## Properties 243For the full list of style properties click [here](/overview/style-props). 244 245### Typical background properties 246In the documentation of the widgets you will see sentences like "The widget uses the typical background properties". These "typical background properties" are the ones related to: 247- Background 248- Border 249- Outline 250- Shadow 251- Padding 252- Width and height transformation 253- X and Y translation 254 255 256## Transitions 257By default, when an object changes state (e.g. it's pressed) the new properties from the new state are set immediately. However, with transitions it's possible to play an animation on state change. 258For example, on pressing a button its background color can be animated to the pressed color over 300 ms. 259 260The parameters of the transitions are stored in the styles. It's possible to set 261- the time of the transition 262- the delay before starting the transition 263- the animation path (also known as the timing or easing function) 264- the properties to animate 265 266The transition properties can be defined for each state. For example, setting a 500 ms transition time in the default state means that when the object goes to the default state a 500 ms transition time is applied. 267Setting a 100 ms transition time in the pressed state causes a 100 ms transition when going to the pressed state. 268This example configuration results in going to the pressed state quickly and then going back to default slowly. 269 270To describe a transition an `lv_transition_dsc_t` variable needs to be initialized and added to a style: 271```c 272/*Only its pointer is saved so must static, global or dynamically allocated */ 273static const lv_style_prop_t trans_props[] = { 274 LV_STYLE_BG_OPA, LV_STYLE_BG_COLOR, 275 0, /*End marker*/ 276}; 277 278static lv_style_transition_dsc_t trans1; 279lv_style_transition_dsc_init(&trans1, trans_props, lv_anim_path_ease_out, duration_ms, delay_ms); 280 281lv_style_set_transition(&style1, &trans1); 282``` 283 284## Opacity, Blend modes and Transformations 285If the `opa`, `blend_mode`, `transform_angle`, or `transform_zoom` properties are set to their non-default value LVGL creates a snapshot about the widget and all its children in order to blend the whole widget with the set opacity, blend mode and transformation properties. 286 287These properties have this effect only on the `MAIN` part of the widget. 288 289The created snapshot is called "intermediate layer" or simply "layer". If only `opa` and/or `blend_mode` is set to a non-default value LVGL can build the layer from smaller chunks. The size of these chunks can be configured by the following properties in `lv_conf.h`: 290 - `LV_LAYER_SIMPLE_BUF_SIZE`: [bytes] the optimal target buffer size. LVGL will try to allocate this size of memory. 291 - `LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE`: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated. 292 293If transformation properties were also used the layer can not be rendered in chunks, but one larger memory needs to be allocated. The required memory depends on the angle, zoom and pivot parameters, and the size of the area to redraw, but it's never larger than the size of the widget (including the extra draw size used for shadow, outline, etc). 294 295If the widget can fully cover the area to redraw, LVGL creates an RGB layer (which is faster to render and uses less memory). If the opposite case ARGB rendering needs to be used. A widget might not cover its area if it has radius, `bg_opa != 255`, has shadow, outline, etc. 296 297The click area of the widget is also transformed accordingly. 298 299 300## Color filter 301TODO 302 303 304## Themes 305Themes are a collection of styles. If there is an active theme LVGL applies it on every created widget. 306This will give a default appearance to the UI which can then be modified by adding further styles. 307 308Every display can have a different theme. For example, you could have a colorful theme on a TFT and monochrome theme on a secondary monochrome display. 309 310To set a theme for a display, two steps are required: 3111. Initialize a theme 3122. Assign the initialized theme to a display. 313 314Theme initialization functions can have different prototypes. This example shows how to set the "default" theme: 315```c 316lv_theme_t * th = lv_theme_default_init(display, /*Use the DPI, size, etc from this display*/ 317 LV_COLOR_PALETTE_BLUE, LV_COLOR_PALETTE_CYAN, /*Primary and secondary palette*/ 318 false, /*Light or dark mode*/ 319 &lv_font_montserrat_10, &lv_font_montserrat_14, &lv_font_montserrat_18); /*Small, normal, large fonts*/ 320 321lv_disp_set_theme(display, th); /*Assign the theme to the display*/ 322``` 323 324 325The included themes are enabled in `lv_conf.h`. If the default theme is enabled by `LV_USE_THEME_DEFAULT 1` LVGL automatically initializes and sets it when a display is created. 326 327### Extending themes 328 329Built-in themes can be extended. 330If a custom theme is created, a parent theme can be selected. The parent theme's styles will be added before the custom theme's styles. 331Any number of themes can be chained this way. E.g. default theme -> custom theme -> dark theme. 332 333`lv_theme_set_parent(new_theme, base_theme)` extends the `base_theme` with the `new_theme`. 334 335There is an example for it below. 336 337## Examples 338 339```eval_rst 340 341.. include:: ../../examples/styles/index.rst 342 343``` 344 345## API 346```eval_rst 347 348.. doxygenfile:: lv_style.h 349 :project: lvgl 350 351.. doxygenfile:: lv_theme.h 352 :project: lvgl 353 354.. doxygenfile:: lv_obj_style_gen.h 355 :project: lvgl 356 357.. doxygenfile:: lv_style_gen.h 358 :project: lvgl 359 360 361``` 362