1.. _styles_overview:
2
3===============
4Styles Overview
5===============
6
7Styles are used to set the appearance of Widgets.  Styles in LVGL are
8heavily inspired by CSS. The concept in a nutshell is that a
9style is an :cpp:type:`lv_style_t` variable which can hold properties like
10border width, font, text color and so on. It's similar to a ``class`` in CSS.
11
12- Styles can be assigned to Widgets to change their appearance. Upon
13  assignment, the target part (pseudo-element_ in CSS) and target state
14  (pseudo-class_ in CSS) can be specified. For example one can add
15  ``style_blue`` to the knob of a slider when it's in pressed state.
16- The same style can be used by any number of Widgets.
17- Styles can be cascaded which means multiple styles may be assigned to a Widget and
18  each style can have different properties. Therefore, not all properties
19  have to be specified in a style. LVGL will search for a property until a
20  style defines it or use a default value if it's not specified by any of the
21  styles. For example ``style_btn`` can result in a default gray button
22  and ``style_btn_red`` can add only a ``background-color=red`` to
23  overwrite the background color.
24- The most recently added style has higher precedence. This means if a property
25  is specified in two styles the newest style in the Widget will be used.
26- Some properties (e.g. text color) can be inherited from a parent(s) if it's not specified in a Widget.
27- Widgets can also have :ref:`local styles <style_local>` with higher precedence than "normal" styles.
28- Unlike CSS (where pseudo-classes_ describe different states, e.g. ``:focus``),
29  in LVGL a property is assigned to a given state.
30- Transitions can be applied when the Widget changes state.
31
32
33
34.. _style_states:
35
36States
37******
38
39The Widgets can be in the combination of the following states:
40
41- :cpp:enumerator:`LV_STATE_DEFAULT`: (0x0000) Normal, released state
42- :cpp:enumerator:`LV_STATE_CHECKED`: (0x0001) Toggled or checked state
43- :cpp:enumerator:`LV_STATE_FOCUSED`: (0x0002) Focused via keypad or encoder or clicked via touchpad/mouse
44- :cpp:enumerator:`LV_STATE_FOCUS_KEY`: (0x0004) Focused via keypad or encoder but not via touchpad/mouse
45- :cpp:enumerator:`LV_STATE_EDITED`: (0x0008) Edit by an encoder
46- :cpp:enumerator:`LV_STATE_HOVERED`: (0x0010) Hovered by mouse
47- :cpp:enumerator:`LV_STATE_PRESSED`: (0x0020) Being pressed
48- :cpp:enumerator:`LV_STATE_SCROLLED`: (0x0040) Being scrolled
49- :cpp:enumerator:`LV_STATE_DISABLED`: (0x0080) Disabled state
50- :cpp:enumerator:`LV_STATE_USER_1`: (0x1000) Custom state
51- :cpp:enumerator:`LV_STATE_USER_2`: (0x2000) Custom state
52- :cpp:enumerator:`LV_STATE_USER_3`: (0x4000) Custom state
53- :cpp:enumerator:`LV_STATE_USER_4`: (0x8000) Custom state
54
55A Widget can be in a combination of states such as being focused and
56pressed at the same time. This is represented as :cpp:expr:`LV_STATE_FOCUSED | LV_STATE_PRESSED`.
57
58A style can be added to any state or state combination. For example,
59setting a different background color for the default and pressed states.
60If a property is not defined in a state the best matching state's
61property will be used. Typically this means the property with
62:cpp:enumerator:`LV_STATE_DEFAULT` is used.˛ If the property is not set even for the
63default state the default value will be used. (See later)
64
65What does the "best matching state's property" mean?
66----------------------------------------------------
67States have a precedence which is shown by their value (see in the above list).
68A higher value means higher precedence. To determine which state's
69property to use let's take an example. Imagine the background color is
70defined like this:
71
72- :cpp:enumerator:`LV_STATE_DEFAULT`: white
73- :cpp:enumerator:`LV_STATE_PRESSED`: gray
74- :cpp:enumerator:`LV_STATE_FOCUSED`: red
75
761. Initially the Widget is in the default state, so it's a simple case:
77   the property is perfectly defined in the Widget's current state as
78   white.
792. When the Widget is pressed there are 2 related properties: default
80   with white (default is related to every state) and pressed with gray.
81   The pressed state has 0x0020 precedence which is higher than the
82   default state's 0x0000 precedence, so gray color will be used.
833. When the Widget has focus the same thing happens as in pressed state
84   and red color will be used. (Focused state has higher precedence than
85   default state).
864. When the Widget has focus and pressed both gray and red would work,
87   but the pressed state has higher precedence than focused so gray
88   color will be used.
895. It's possible to set e.g. rose color for :cpp:expr:`LV_STATE_PRESSED | LV_STATE_FOCUSED`.
90   In this case, this combined state has 0x0020 + 0x0002 = 0x0022 precedence, which is higher than
91   the pressed state's precedence so rose color would be used.
926. When the Widget is in the checked state there is no property to set
93   the background color for this state. So for lack of a better option,
94   the Widget remains white from the default state's property.
95
96Some practical notes:
97
98- The precedence (value) of states is quite intuitive, and it's something the
99  user would expect naturally. Example:  if a Widget has focus the user will still
100  want to see if it's pressed, therefore the pressed state has a higher
101  precedence. If the focused state had a higher precedence it would overwrite
102  the pressed color.
103- If you want to set a property for all states (e.g. red background color)
104  just set it for the default state. If the Widget can't find a property
105  for its current state it will fall back to the default state's property.
106- Use ORed states to describe the properties for complex cases (e.g.
107  pressed + checked + focused).
108- It might be a good idea to use different
109  style elements for different states. For example, finding background
110  colors for released, pressed, checked + pressed, focused, focused +
111  pressed, focused + pressed + checked, etc. states is quite difficult.
112  Instead, for example, use the background color for pressed and checked
113  states and indicate the focused state with a different border color.
114
115
116
117.. _style_cascading:
118
119Cascading Styles
120****************
121
122It's not required to set all the properties in one style. It's possible
123to add more styles to a Widget and have the latter added style modify
124or extend appearance. For example, create a general gray button style
125and create a new one for red buttons where only the new background color
126is set.
127
128This is much like in CSS when used classes are listed like
129``<div class=".btn .btn-red">``.
130
131Styles added later have precedence over ones set earlier. So in the
132gray/red button example above, the normal button style should be added
133first and the red style second. However, the precedence of the states
134are still taken into account. So let's examine the following case:
135
136- the basic button style defines dark-gray color for the default state and
137  light-gray color for the pressed state
138- the red button style defines the background color as red only in the default state
139
140In this case, when the button is released (it's in default state) it
141will be red because a perfect match is found in the most recently added
142style (red). When the button is pressed the light-gray color is a better
143match because it describes the current state perfectly, so the button
144will be light-gray.
145
146
147
148.. _style_inheritance:
149
150Inheritance
151***********
152
153Some properties (typically those related to text) can be inherited from
154the parent Widget's styles. Inheritance is applied only if the given
155property is not set in the Widget's styles (even in default state). In
156this case, if the property is inheritable, the property's value will be
157searched up the parent hierarchy until a Widget specifies a value for the
158property. The parents will use their own state to determine the value.
159So if a button is pressed, and the text color comes from a parent, the
160pressed text color will be used.
161
162
163
164.. _style_parts:
165
166Parts
167*****
168
169Widgets can be composed of *parts* which may each have their own styles.
170
171The following predefined parts exist in LVGL:
172
173- :cpp:enumerator:`LV_PART_MAIN`: A background like rectangle
174- :cpp:enumerator:`LV_PART_SCROLLBAR`: The scrollbar(s)
175- :cpp:enumerator:`LV_PART_INDICATOR`: Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox
176- :cpp:enumerator:`LV_PART_KNOB`: Like a handle to grab to adjust a value
177- :cpp:enumerator:`LV_PART_SELECTED`: Indicate the currently selected option or section
178- :cpp:enumerator:`LV_PART_ITEMS`: Used if the widget has multiple similar elements (e.g. table cells)
179- :cpp:enumerator:`LV_PART_CURSOR`: Mark a specific place e.g. Text Area's or chart's cursor
180- :cpp:enumerator:`LV_PART_CUSTOM_FIRST`: Custom part identifiers can be added starting from here.
181
182For example a :ref:`Slider <lv_slider>` has three parts:
183
184- Main (background)
185- Indicator
186- Knob
187
188This means all three parts of the slider can have their own styles. See
189later how to add styles to Widgets and parts.
190
191
192
193.. _style_initialize:
194
195Initialize Styles and Set/Get Properties
196****************************************
197
198Styles are stored in :cpp:type:`lv_style_t` variables. Style variables should be
199``static``, global or dynamically allocated. In other words they cannot
200be local variables in functions which are destroyed when the function
201exits. Before using a style it should be initialized with
202:cpp:expr:`lv_style_init(&my_style)`. After initializing a style, properties can
203be added or changed.
204
205Property set functions looks like this:
206``lv_style_set_<property_name>(&style, <value>);`` For example:
207
208.. code-block:: c
209
210   static lv_style_t style_btn;
211   lv_style_init(&style_btn);
212   lv_style_set_bg_color(&style_btn, lv_color_hex(0x115588));
213   lv_style_set_bg_opa(&style_btn, LV_OPA_50);
214   lv_style_set_border_width(&style_btn, 2);
215   lv_style_set_border_color(&style_btn, lv_color_black());
216
217   static lv_style_t style_btn_red;
218   lv_style_init(&style_btn_red);
219   lv_style_set_bg_color(&style_btn_red, lv_palette_main(LV_PALETTE_RED));
220   lv_style_set_bg_opa(&style_btn_red, LV_OPA_COVER);
221
222To remove a property use:
223
224.. code-block:: c
225
226   lv_style_remove_prop(&style, LV_STYLE_BG_COLOR);
227
228To get a property's value from a style:
229
230.. code-block:: c
231
232   lv_style_value_t v;
233   lv_result_t res = lv_style_get_prop(&style, LV_STYLE_BG_COLOR, &v);
234   if(res == LV_RESULT_OK) {  /* Found */
235       do_something(v.color);
236   }
237
238:cpp:union:`lv_style_value_t` has 3 fields, only one of which will apply, depending
239on the type of property it is applied to:
240
241- :cpp:member:`num`: for integer, boolean and opacity properties
242- :cpp:member:`color`: for color properties
243- :cpp:member:`ptr`: for pointer properties
244
245To reset a style (free all its data) use:
246
247.. code-block:: c
248
249   lv_style_reset(&style);
250
251Styles can be built as ``const`` as well to save RAM:
252
253.. code-block:: c
254
255   const lv_style_const_prop_t style1_props[] = {
256      LV_STYLE_CONST_WIDTH(50),
257      LV_STYLE_CONST_HEIGHT(50),
258      LV_STYLE_CONST_PROPS_END
259   };
260
261   LV_STYLE_CONST_INIT(style1, style1_props);
262
263Later ``const`` style can be used like any other style but (obviously)
264new properties cannot be added.
265
266
267
268.. _style_add_remove:
269
270Add and remove styles to a widget
271*********************************
272
273A style on its own has no effect until it is added (assigned) to a Widget.
274
275
276Add styles
277----------
278
279To add a style to a Widget use
280``lv_obj_add_style(widget, &style, <selector>)``. ``<selector>`` is an
281OR-ed value of parts and state to which the style should be added. Some
282examples:
283
284- :cpp:expr:`LV_PART_MAIN | LV_STATE_DEFAULT`
285- :cpp:enumerator:`LV_STATE_PRESSED`: The main part in pressed state. :cpp:enumerator:`LV_PART_MAIN` can be omitted
286- :cpp:enumerator:`LV_PART_SCROLLBAR`: The scrollbar part in the default state. :cpp:enumerator:`LV_STATE_DEFAULT` can be omitted.
287- :cpp:expr:`LV_PART_SCROLLBAR | LV_STATE_SCROLLED`: The scrollbar part when the Widget is being scrolled
288- :cpp:expr:`LV_PART_INDICATOR | LV_STATE_PRESSED | LV_STATE_CHECKED` The indicator part when the Widget is pressed and checked at the same time.
289
290Using :cpp:func:`lv_obj_add_style`:
291
292.. code-block:: c
293
294   lv_obj_add_style(btn, &style_btn, 0);                     /* Default button style */
295   lv_obj_add_style(btn, &btn_red, LV_STATE_PRESSED);        /* Overwrite only some colors to red when pressed */
296
297Replace styles
298--------------
299
300To replace a specific style of a Widget use
301:cpp:expr:`lv_obj_replace_style(widget, old_style, new_style, selector)`. This
302function will only replace ``old_style`` with ``new_style`` if the
303``selector`` matches the ``selector`` used in ``lv_obj_add_style``. Both
304``old_style`` and ``new_style`` must not be ``NULL``.  Separate functions exist for
305adding and removing styles.  If the combination of
306``old_style`` and ``selector`` exists multiple times in ``obj``\ 's
307styles, all occurrences will be replaced. The return value of the
308function indicates whether at least one successful replacement took
309place.
310
311Using :cpp:func:`lv_obj_replace_style`:
312
313.. code-block:: c
314
315   lv_obj_add_style(btn, &style_btn, 0);                      /* Add a button style */
316   lv_obj_replace_style(btn, &style_btn, &new_style_btn, 0);  /* Replace the button style with a different one */
317
318Remove styles
319-------------
320
321To remove all styles from a Widget use :cpp:expr:`lv_obj_remove_style_all(widget)`.
322
323To remove specific styles use
324:cpp:expr:`lv_obj_remove_style(widget, style, selector)`. This function will remove
325``style`` only if the ``selector`` matches with the ``selector`` used in
326:cpp:func:`lv_obj_add_style`. ``style`` can be ``NULL`` to check only the
327``selector`` and remove all matching styles. The ``selector`` can use
328the :cpp:enumerator:`LV_STATE_ANY` and :cpp:enumerator:`LV_PART_ANY` values to remove the style from
329any state or part.
330
331Reporting style changes
332-----------------------
333
334If a style which is already assigned to a Widget changes (i.e. a
335property is added or changed), the Widgets using that style should be
336notified. There are 3 options to do this:
337
3381. If you know that the changed properties can be applied by a simple redraw
339   (e.g. color or opacity changes) just call :cpp:expr:`lv_obj_invalidate(widget)`
340   or :cpp:expr:`lv_obj_invalidate(lv_screen_active())`.
3412. If more complex style properties were changed or added, and you know which
342   Widget(s) are affected by that style call :cpp:expr:`lv_obj_refresh_style(widget, part, property)`.
343   To refresh all parts and properties use :cpp:expr:`lv_obj_refresh_style(widget, LV_PART_ANY, LV_STYLE_PROP_ANY)`.
3443. To make LVGL check all Widgets to see if they use a style and refresh them
345   when needed, call :cpp:expr:`lv_obj_report_style_change(&style)`. If ``style``
346   is ``NULL`` all Widgets will be notified about a style change.
347
348Get a style property's value on a Widget
349----------------------------------------
350
351To get the final value of a style's property considering
352
353- cascading,
354- inheritance,
355- local styles and transitions (see below)
356
357property "get" functions like this can be used: ``lv_obj_get_style_<property_name>(widget, <part>)``.
358These functions use the Widget's current state and if no better candidate exists they return the default value.
359For example:
360
361.. code-block:: c
362
363    lv_color_t color = lv_obj_get_style_bg_color(btn, LV_PART_MAIN);
364
365
366
367.. _style_local:
368
369Local Styles
370************
371
372In addition to "normal" styles, Widgets can also store local styles.
373This concept is similar to inline styles in CSS
374(e.g. ``<div style="color:red">``) with some modification.
375
376Local styles are like normal styles, but they can't be shared among
377other Widgets. If used, local styles are allocated automatically, and
378freed when the Widget is deleted. They are useful to add local
379customization to a Widget.
380
381Unlike in CSS, LVGL local styles can be assigned to states
382(pseudo-classes_) and parts (pseudo-elements_).
383
384To set a local property use functions like
385``lv_obj_set_style_<property_name>(widget, <value>, <selector>);``   For example:
386
387.. code-block:: c
388
389    lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED);
390
391
392
393.. _style_properties_overview:
394
395Style Properties Overview
396*************************
397
398For the full list of style properties click :ref:`here <style_properties>`.
399
400
401.. _typical bg props:
402
403Typical background properties
404-----------------------------
405
406In documentation of widgets you will see sentences like "The
407_____ Widget uses the typical background style properties".  These "typical
408background properties" are the properties being referred to:
409
410- Background
411- Border
412- Outline
413- Shadow
414- Padding
415- Width and height transformation
416- X and Y translation
417
418See :ref:`boxing_model` for the meanings of these terms.
419
420
421
422.. _style_transitions:
423
424Transitions
425***********
426
427By default, when a Widget changes state (e.g. it's pressed) the new
428properties from the new state are set immediately. However, with
429transitions it's possible to play an animation on state change. For
430example, on pressing a button its background color can be animated to
431the pressed color over 300 ms.
432
433The parameters of the transitions are stored in the styles. It's
434possible to set
435
436- the time of the transition
437- the delay before starting the transition
438- the animation path (also known as the timing or easing function)
439- the properties to animate
440
441The transition properties can be defined for each state. For example,
442setting a 500 ms transition time in the default state means that when
443the Widget goes to the default state a 500 ms transition time is
444applied. Setting a 100 ms transition time in the pressed state causes a
445100 ms transition when going to the pressed state. This example
446configuration results in going to the pressed state quickly and then
447going back to default slowly.
448
449To describe a transition an :cpp:struct:`lv_transition_dsc_t` variable needs to be
450initialized and added to a style:
451
452.. code-block:: c
453
454   /* Only its pointer is saved so must static, global or dynamically allocated */
455   static const lv_style_prop_t trans_props[] = {
456                                               LV_STYLE_BG_OPA, LV_STYLE_BG_COLOR,
457                                               0, /* End marker */
458   };
459
460   static lv_style_transition_dsc_t trans1;
461   lv_style_transition_dsc_init(&trans1, trans_props, lv_anim_path_ease_out, duration_ms, delay_ms);
462
463   lv_style_set_transition(&style1, &trans1);
464
465
466
467.. _style_opacity_blend_modes_transformations:
468
469Opacity, Blend Modes and Transformations
470****************************************
471
472If the ``opa``, ``blend_mode``, ``transform_angle``, or
473``transform_zoom`` properties are set to a non-default value LVGL
474creates a snapshot of the widget and its children in order to
475blend the whole widget with the set opacity, blend mode and
476transformation properties.
477
478These properties have this effect only on the ``MAIN`` part of the
479widget.
480
481The created snapshot is called "intermediate layer" or simply "layer".
482If only ``opa`` and/or ``blend_mode`` is set to a non-default value LVGL
483can build the layer from smaller chunks. The size of these chunks can be
484configured by the following properties in ``lv_conf.h``:
485
486- :cpp:enumerator:`LV_LAYER_SIMPLE_BUF_SIZE`: [bytes] the optimal target buffer size. LVGL will try to allocate this size of memory.
487- :cpp:enumerator:`LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE`: [bytes] used if :cpp:enumerator:`LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
488
489If transformation properties were also used the layer cannot be
490rendered in chunks, but one larger memory block needs to be allocated. The
491required memory depends on the angle, zoom and pivot parameters, and the
492size of the area to redraw, but it's never larger than the size of the
493widget (including the extra draw size used for shadow, outline, etc).
494
495If the widget can fully cover the area to redraw, LVGL creates an RGB
496layer (which is faster to render and uses less memory). If the opposite
497case ARGB rendering needs to be used, a widget might not cover its area
498if it has radius, ``bg_opa < 255``, has shadow, outline, etc.
499
500The click area of the widget is also transformed accordingly.
501
502
503
504.. _style_color_filter:
505
506Color Filter
507************
508
509TODO
510
511
512
513.. _style_themes:
514
515Themes
516******
517
518Themes are a collection of styles. If there is an active theme LVGL
519applies it to every newly-created widget. This will give a default appearance
520to the UI which can then be modified by adding further styles.
521
522Every display can have a different theme. For example, you could have a
523colorful theme on a TFT and monochrome theme on a secondary monochrome
524display.
525
526To set a theme for a display, two steps are required:
527
5281. Initialize a theme
5292. Assign the initialized theme to a display.
530
531Theme initialization functions can have different prototypes. This
532example shows how to set the "default" theme:
533
534.. code-block:: c
535
536   lv_theme_t * th = lv_theme_default_init(display,                 /* Use DPI, size, etc. from this display */
537                                           LV_COLOR_PALETTE_BLUE,   /* Primary and secondary palette */
538                                           LV_COLOR_PALETTE_CYAN,
539                                           false,                   /* Dark theme?  False = light theme. */
540                                           &lv_font_montserrat_10,  /* Small, normal, large fonts */
541                                           &lv_font_montserrat_14,
542                                           &lv_font_montserrat_18);
543
544   lv_display_set_theme(display, th); /* Assign theme to display */
545
546The included themes are enabled in ``lv_conf.h``. If the default theme
547is enabled by :c:macro:`LV_USE_THEME_DEFAULT` LVGL automatically initializes
548and sets it when a display is created.
549
550Extending themes
551----------------
552
553Built-in themes can be extended. If a custom theme is created, a parent
554theme can be selected. The parent theme's styles will be added before
555the custom theme's styles. Any number of themes can be chained this way.
556E.g. default theme -> custom theme -> dark theme.
557
558:cpp:expr:`lv_theme_set_parent(new_theme, base_theme)` extends the
559``base_theme`` with the ``new_theme``.
560
561There is an example of this below.
562
563.. _styles_example:
564
565Examples
566********
567
568.. include:: ../../../examples/styles/index.rst
569
570
571
572..  Hyperlinks
573
574.. _pseudo-elements:
575.. _pseudo-element:   https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors#pseudo-classes_and_pseudo-elements
576.. _pseudo-classes:
577.. _pseudo-class:     https://developer.mozilla.org/en-US/docs/Glossary/Pseudo-class
578
579
580
581
582.. _styles_api:
583
584API
585***
586