1.. _lvgl_basics: 2 3=========== 4LVGL Basics 5=========== 6 7LVGL (Light and Versatile Graphics Library) is a free and open-source graphics 8library providing everything you need to create an embedded GUI with easy-to-use 9graphical elements, beautiful visual effects, and a low memory footprint. 10 11How does it do this? 12 13 14 15.. _basic_data_flow: 16 17Overview of LVGL's Data Flow 18**************************** 19 20.. figure:: /misc/intro_data_flow.png 21 :scale: 75 % 22 :alt: LVGL Data Flow 23 :align: center 24 :figwidth: image 25 26 Overview of LVGL Data Flow 27 28 29You create one :ref:`display` for each physical display panel, create 30:ref:`basics_screen_widgets` on them, add :ref:`basics_widgets` onto those Screens. 31To handle touch, mouse, keypad, etc., you :ref:`create an Input Device <indev_creation>` 32for each. The :ref:`tick_interface` tells LVGL what time is it. :ref:`timer_handler` 33drives LVGL's timers which, in turn, perform all of LVGL's time-related tasks: 34 35- periodically refreshes displays, 36- reads input devices, 37- fires events, 38- runs any animations, and 39- runs user-created timers. 40 41 42.. _applications_job: 43 44Application's Job 45----------------- 46 47After initialization, the application's job is merely to create Widget Trees when 48they are needed, manage events those Widgets generate (by way of user interaction 49and other things), and delete them when they are no longer needed. LVGL takes care 50of the rest. 51 52 53 54.. _basics_major_concepts: 55 56Major Concepts 57************** 58 59 60.. _display-vs-screen: 61 62Display vs Screen 63----------------- 64Before we get into any details about Widgets, let us first clarify the difference 65between two terms that you will hereafter see frequently: 66 67- A **Display** or **Display Panel** is the physical hardware displaying the pixels. 68- A :ref:`display` object is an object in RAM that represents a **Display** meant 69 to be used by LVGL. 70- A **Screen** is the "root" Widget in the Widget Trees mentioned above, and are 71 "attached to" a particular :ref:`display`. 72 73 74Default Display 75--------------- 76When the first :ref:`display` object is created, it becomes the Default Display. 77Many functions related to Screen Widgets use the default display. 78See :ref:`default_display` for more information. 79 80 81.. _basics_screen_widgets: 82 83Screen Widgets 84-------------- 85In this documentation, the term "Screen Widget" is frequently shortened to just 86"Screen". But it is important to understand that a "Screen" is simply any 87:ref:`Widget <widgets>` created without a parent --- the "root" of each Widget Tree. 88 89See :ref:`screens` for more details. 90 91 92Active Screen 93------------- 94 95The Active Screen is the screen (and its child Widgets) currently being displayed. 96See :ref:`active_screen` for more information. 97 98 99.. _basics_widgets: 100 101Widgets 102------- 103After LVGL is initialized (see :ref:`initializing_lvgl`), to create an interactive 104user interface, an application next creates a tree of Widgets that LVGL can render to 105the associated display, and with which the user can interact. 106 107Widgets are "intelligent" LVGL graphical elements such as :ref:`Base Widgets 108<base_widget_overview>` (simple rectangles and :ref:`screens`), Buttons, Labels, 109Checkboxes, Switches, Sliders, Charts, etc. Go to :ref:`widgets` to see the full 110list. 111 112To build this Widget Tree, the application first acquires a pointer to a Screen Widget. 113A system designer is free to use the default Screen created with the :ref:`display` 114and/or create his own. To create a new Screen Widget, simply create a Widget passing 115NULL as the parent argument. Technically, this can be any type of Widget, but in 116most cases it is a :ref:`base_widget_overview`. (An example of another type of 117Widget being used as a Screen is an :ref:`lv_image` Widget to supply an image for the 118background.) 119 120The application then adds Widgets to this Screen as children in the tree. Widgets 121are automatically added as children to their parent Widgets at time of creation --- 122the Widget's parent is passed as the first argument to the function that creates 123the Widget. After being so added, we say that the parent Widget "contains" the 124child Widget. 125 126Any Widget can contain other Widgets. For example, if you want a Button to have 127text, create a Label Widget and add it to the Button as a child. 128 129Each child Widget becomes "part of" its parent Widget. Because of this relationship: 130 131- when the parent Widget moves, its children move with it; 132- when the parent Widget is deleted, its children are deleted with it; 133- a child Widget is only visible within its parent's boundaries; any part of a child 134 outside its parent's boundaries is clipped (i.e. not rendered). 135 136Screens (and their child Widgets) can be created and deleted at any time *except* 137when the Screen is the :ref:`active_screen`. If you want to delete the current Screen 138as you load a new one, call :cpp:func:`lv_screen_load_anim` and pass ``true`` for the 139``auto_del`` argument. If you want to keep the current Screen in RAM when you load a 140new Screen, pass ``false`` for the ``auto_del`` argument, or call 141:cpp:func:`lv_screen_active` to load the new screen. 142 143A system designer is free to keep any number of Screens (and their child Widgets) in 144RAM (e.g. for quick re-display again later). Doing so: 145 146- requires more RAM, but 147- can save the time of repeatedly creating the Screen and its child Widgets; 148- can be handy when a Screen is complex and/or can be made the :ref:`active_screen` frequently. 149 150If multiple Screens are maintained in RAM simultaneously, it is up to the system 151designer as to how they are managed. 152 153 154.. _basics_creating_widgets: 155 156Creating Widgets 157~~~~~~~~~~~~~~~~ 158Widgets are created by calling functions that look like this:: 159 160 lv_<type>_create(parent) 161 162The call will return an :cpp:type:`lv_obj_t` ``*`` pointer that can be used later to 163reference the Widget to set its attributes. 164 165For example: 166 167.. code-block:: c 168 169 lv_obj_t * slider1 = lv_slider_create(lv_screen_active()); 170 171 172.. _basics_modifying_widgets: 173 174Modifying Widgets 175~~~~~~~~~~~~~~~~~ 176Attributes common to all Widgets are set by functions that look like this:: 177 178 lv_obj_set_<attribute_name>(widget, <value>) 179 180For example: 181 182.. code-block:: c 183 184 lv_obj_set_x(slider1, 30); 185 lv_obj_set_y(slider1, 10); 186 lv_obj_set_size(slider1, 200, 50); 187 188Along with these attributes, widgets can have type-specific attributes which are 189set by functions that look like this:: 190 191 lv_<type>_set_<attribute_name>(widget, <value>) 192 193For example: 194 195.. code-block:: c 196 197 lv_slider_set_value(slider1, 70, LV_ANIM_ON); 198 199To see the full API visit the documentation of the Widget in question under 200:ref:`widgets` or study its related header file in the source code, e.g. 201 202- lvgl/src/widgets/slider/lv_slider.h 203 204or view it on GitHub, e.g. 205 206- https://github.com/lvgl/lvgl/blob/master/src/widgets/slider/lv_slider.h . 207 208 209.. _basics_deleting_widgets: 210 211Deleting Widgets 212~~~~~~~~~~~~~~~~ 213To delete any widget and its children:: 214 215 lv_obj_delete(lv_obj_t * widget) 216 217 218 219.. _basics_events: 220 221Events 222------ 223 224Events are used to inform the application that something has happened with a Widget. 225You can assign one or more callbacks to a Widget which will be called when the 226Widget is clicked, released, dragged, being deleted, etc. 227 228A callback is assigned like this: 229 230.. code-block:: c 231 232 lv_obj_add_event_cb(btn, my_btn_event_cb, LV_EVENT_CLICKED, NULL); 233 234 ... 235 236 void my_btn_event_cb(lv_event_t * e) 237 { 238 printf("Clicked\n"); 239 } 240 241:cpp:enumerator:`LV_EVENT_ALL` can be used instead of :cpp:enumerator:`LV_EVENT_CLICKED` 242to invoke the callback for all events. (Beware: there are a LOT of events! This can 243be handy for debugging or learning what events occur for a given Widget, or indeed 244if the application needs to process all events for some reason.) 245 246Event callbacks receive the argument :cpp:expr:`lv_event_t * e` containing the 247current event code and other event-related information. The current event code can 248be retrieved with: 249 250.. code-block:: c 251 252 lv_event_code_t code = lv_event_get_code(e); 253 254The Widget that triggered the event can be retrieved with: 255 256.. code-block:: c 257 258 lv_obj_t * obj = lv_event_get_target(e); 259 260To learn all features of the events go to the :ref:`events` section. 261 262 263.. _basics_parts: 264 265Parts 266----- 267 268Widgets are built from one or more *parts*. For example, a button 269has only one part called :cpp:enumerator:`LV_PART_MAIN`. However, a 270:ref:`lv_slider` has :cpp:enumerator:`LV_PART_MAIN`, :cpp:enumerator:`LV_PART_INDICATOR` 271and :cpp:enumerator:`LV_PART_KNOB`. 272 273By using parts you can apply different styles to sub-elements of a widget. (See below.) 274 275Read the Widget's documentation to learn which parts it uses. 276 277 278.. _basics_states: 279 280States 281------ 282 283Widgets can be in a combination of the following states: 284 285- :cpp:enumerator:`LV_STATE_DEFAULT`: Normal, released state 286- :cpp:enumerator:`LV_STATE_CHECKED`: Toggled or checked state 287- :cpp:enumerator:`LV_STATE_FOCUSED`: Focused via keypad or encoder or clicked via touchpad/mouse 288- :cpp:enumerator:`LV_STATE_FOCUS_KEY`: Focused via keypad or encoder but not via touchpad/mouse 289- :cpp:enumerator:`LV_STATE_EDITED`: Edit by an encoder 290- :cpp:enumerator:`LV_STATE_HOVERED`: Hovered by mouse 291- :cpp:enumerator:`LV_STATE_PRESSED`: Being pressed 292- :cpp:enumerator:`LV_STATE_SCROLLED`: Being scrolled 293- :cpp:enumerator:`LV_STATE_DISABLED`: Disabled 294 295For example, if you press a Widget it will automatically go to the 296:cpp:enumerator:`LV_STATE_FOCUSED` and :cpp:enumerator:`LV_STATE_PRESSED` states and when you 297release it the :cpp:enumerator:`LV_STATE_PRESSED` state will be removed while the 298:cpp:enumerator:`LV_STATE_FOCUSED` state remains active. 299 300To check if a Widget is in a given state use 301:cpp:expr:`lv_obj_has_state(widget, LV_STATE_...)`. It will return ``true`` if the 302Widget is currently in that state. 303 304To manually add or remove states use: 305 306.. code-block:: c 307 308 lv_obj_add_state(widget, LV_STATE_...); 309 lv_obj_remove_state(widget, LV_STATE_...); 310 311 312.. _basics_styles: 313 314Styles 315------ 316 317A style instance contains properties such as background color, border 318width, font, etc. that describe the appearance of Widgets. 319 320Styles are carried in :cpp:struct:`lv_style_t` objects. Only their pointer is saved 321in the Widgets so they need to be defined as static or global variables. Before 322using a style it needs to be initialized with :cpp:expr:`lv_style_init(&style1)`. 323After that, properties can be added to configure the style. For example: 324 325.. code-block:: c 326 327 static lv_style_t style1; 328 lv_style_init(&style1); 329 lv_style_set_bg_color(&style1, lv_color_hex(0xa03080)) 330 lv_style_set_border_width(&style1, 2)) 331 332See :ref:`style_properties_overview` for more details. 333 334See :ref:`style_properties` to see the full list. 335 336Styles are assigned using the OR-ed combination of a Widget's part and 337state. For example to use this style on the slider's indicator when the 338slider is pressed: 339 340.. code-block:: c 341 342 lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR | LV_STATE_PRESSED); 343 344If the *part* is :cpp:enumerator:`LV_PART_MAIN` it can be omitted: 345 346.. code-block:: c 347 348 lv_obj_add_style(btn1, &style1, LV_STATE_PRESSED); /* Equal to LV_PART_MAIN | LV_STATE_PRESSED */ 349 350Similarly, :cpp:enumerator:`LV_STATE_DEFAULT` can be omitted: 351 352.. code-block:: c 353 354 lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR); /* Equal to LV_PART_INDICATOR | LV_STATE_DEFAULT */ 355 356For :cpp:enumerator:`LV_STATE_DEFAULT` | :cpp:enumerator:`LV_PART_MAIN` simply pass ``0``: 357 358.. code-block:: c 359 360 lv_obj_add_style(btn1, &style1, 0); /* Equal to LV_PART_MAIN | LV_STATE_DEFAULT */ 361 362Styles can be cascaded (similarly to CSS). This means you can add more 363styles to a part of a Widget. For example ``style_btn`` can set a 364default button appearance, and ``style_btn_red`` can overwrite the 365background color to make the button red: 366 367.. code-block:: c 368 369 lv_obj_add_style(btn1, &style_btn, 0); 370 lv_obj_add_style(btn1, &style1_btn_red, 0); 371 372If a property is not set for the current state, the style with 373:cpp:enumerator:`LV_STATE_DEFAULT` will be used. A default value is used if the 374property is not defined in the default state. 375 376Some properties (particularly the text-related ones) can be inherited. This 377means if a property is not set in a Widget it will be searched for in 378its parents. For example, you can set the font once in the screen's 379style and all text on that screen will inherit it by default. 380 381Local style properties also can be added to Widgets. This creates a 382style which resides inside the Widget and is used only by that Widget: 383 384.. code-block:: c 385 386 lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED); 387 388To learn all the features of styles see :ref:`styles`. 389 390 391.. _basics_themes: 392 393Themes 394------ 395 396Themes are the default styles for Widgets. Styles from a theme are 397applied automatically when Widgets are created. 398 399The theme for your application is a compile time configuration set in 400``lv_conf.h``. 401 402 403.. _basics_micropython: 404 405MicroPython 406----------- 407 408LVGL can even be used with :ref:`micropython`. 409 410.. code-block:: python 411 412 # Initialize 413 import display_driver 414 import lvgl as lv 415 416 # Create a button with a label 417 scr = lv.obj() 418 btn = lv.button(scr) 419 btn.align(lv.ALIGN.CENTER, 0, 0) 420 label = lv.label(btn) 421 label.set_text('Hello World!') 422 lv.screen_load(scr) 423 424 425 426.. _going_deeper: 427 428Going Deeper 429************* 430 431There are several good ways ways to gain deeper knowledge of LVGL. Here is one 432recommended order of documents to read and things to play with while you are 433advancing your knowledge: 434 4351. If not already read, start with :ref:`introduction` page of 436 the documentation. (5 minutes) 4372. Check out the `Online Demos`_ to see LVGL in action. (3 minutes) 4383. If not already done, read the :ref:`lvgl_basics` (above). (15 minutes) 4394. Set up an LVGL :ref:`simulator`. (10 minutes) 4405. Have a look at some :ref:`examples` and their code. 4416. Add LVGL to your project. See :ref:`add_lvgl_to_your_project` or check out 442 the `ready-to-use Projects`_. 4437. Read the :ref:`main_components` pages to get a better understanding of the library. (2-3 hours) 4448. Skim the documentation of :ref:`widgets` to see what is available. 4459. If you have questions go to the `Forum`_. 44610. Read the :ref:`contributing` guide to see how you can help to improve LVGL. (15 minutes) 447 448 449.. _online demos: https://lvgl.io/demos 450.. _ready-to-use projects: https://github.com/lvgl?q=lv_port_&type=&language= 451.. _forum: https://forum.lvgl.io/ 452 453 454 455.. _basics_examples: 456 457Basic Examples 458************** 459 460Below are several basic examples. They include the application code that produces 461the Widget Tree needed to make LVGL render the examples shown. Each example assumes 462a LVGL has undergone normal initialization, meaning that a ``lv_display_t`` object 463was created and therefore has an :ref:`active_screen`. 464 465 466.. include:: ../examples/get_started/index.rst 467 468 469