docs(xml): reorganize and add better descriptions (#8818)

This commit is contained in:
Gabor Kiss-Vamosi
2025-09-12 11:07:11 +02:00
committed by GitHub
parent 4f40572ac7
commit 115bce48f3
31 changed files with 738 additions and 959 deletions
+3 -3
View File
@@ -1,8 +1,8 @@
.. _freetype:
================
FreeType Support
================
====================
FreeType Font Engine
====================
**FreeType** is a freely available software library to render fonts.
+1 -1
View File
@@ -1,7 +1,7 @@
.. _tiny_ttf:
====================
Tiny TTF font engine
Tiny TTF Font Engine
====================
The lv_tiny_ttf extension allows using TrueType fonts in LVGL using the
+153
View File
@@ -0,0 +1,153 @@
.. _xml_fonts:
=====
Fonts
=====
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
Overview
********
In XML, fonts are considered external resources. A target font engine needs to be selected
and named in order to be referenced in XML files later.
Registering Fonts
*****************
From File
---------
Fonts used directly from a TTF file can be listed in the ``<fonts>`` section
of ``globals.xml``.
Each child of ``<fonts>`` starts with the desired font engine's name, a
``name`` property, and other properties depending on the selected engine.
``as_file`` must be set to ``true`` to indicate that the font is treated as a file.
For example:
.. code-block:: xml
<globals>
<fonts>
<bin as_file="false" name="medium" src="path/to/file.ttf" range="0x20-0x7f" symbols="°" size="24"/>
<tiny_ttf as_file="true" name="big" src_path="path/to/file.ttf" range="0x20-0x7f" size="48"/>
</fonts>
</globals>
When registering ``globals.xml`` with
:cpp:expr:`lv_xml_component_register_from_file("A:path/to/globals.xml")`,
fonts are automatically created with the selected font engine and mapped to the given names.
The fonts can have relative paths in ``globals.xml``. Before registering ``globals.xml``,
:cpp:expr:`lv_xml_set_default_asset_path("path/prefix/")` can be called to set the parent folder.
The font paths will then be appended to this base path.
From Data
---------
If a font is used from C data (arrays) compiled into the firmware, the font's pointer can be registered
to XML like this:
.. code-block:: c
lv_xml_register_font(scope, "font_name", &my_font);
Fonts must be registered before any XML files referencing them are registered, so that the font data
is already known.
In LVGL's UI Editor, when using fonts as data, it's also necessary to add the fonts to
``globals.xml`` with ``as_file=false``, so the Editor can generate the required
C files and also perform validation when referencing data fonts.
Usage in XML
************
Once a font is registered, it can be referenced by its name in styles or even ``<api>`` properties:
.. code-block:: xml
<component>
<api>
<prop name="title_font" type="font" default="my_font_32"/>
</api>
<styles>
<style name="subtitle" text_font="my_font_24"/>
</styles>
<view flex_flow="column">
<lv_label style_text_font="$title_font" text="Title"/>
<lv_label text="I'm the subtitle">
<style name="subtitle"/>
</lv_label>
</view>
Font Engines
************
``<bin>``
---------
Binary fonts can either reference:
1. A ".bin" font file created by LVGL's Font converter from a TTF file (when ``as_file="true"``).
The font will be loaded by :cpp:expr:`lv_binfont_create`.
2. An :cpp:expr:`lv_font_t` pointer compiled into the firmware (``as_file="false"``).
No loading is needed as :cpp:expr:`lv_font_t` can be used directly.
``<bin>`` fonts require these properties:
:``name``: The name to reference the font later
:``src_path``: Path to the font file
:``size``: Font size in px (e.g., "12")
:``bpp``: Bits-per-pixel: 1, 2, 4, or 8
:``as_file``: ``true`` if the font is a ".bin" file, ``false`` if it is an :cpp:expr:`lv_font_t` in C
LVGL's UI Editor always generates a call to :cpp:expr:`lv_xml_register_font` using the set ``name``.
If ``as_file`` is:
- ``false``: It generates a C file with the :cpp:expr:`lv_font_t` structs.
- ``true``: It generates a ".bin" file.
Binary fonts also support selecting a subset of characters:
:``range``: For example, ``"0x30-0x39 0x100-0x200"`` to specify Unicode ranges to include.
The default is ``"0x20-0x7F"`` to cover the ASCII range.
:``symbols``: List of extra characters to add, e.g., ``"°ÁŐÚ"``. Can be used together with ``range``.
Default is empty (no extras).
``<tiny_ttf>``
--------------
TinyTTF fonts use the :ref:`tiny_ttf` engine to load TTF files directly or from data.
Required properties:
:``name``: The name to reference the font later
:``src_path``: Path to the font file
:``size``: Font size in px (e.g., "12")
:``as_file``: ``true`` or ``false``
LVGL's UI Editor generates a call to :cpp:expr:`lv_xml_register_font` using the set ``name``.
If ``as_file`` is:
- ``false``: A C file with raw file data is also generated.
- ``true``: Nothing else is generated, as the TTF file will be used directly.
``<freetype>``
--------------
FreeType fonts use the :ref:`freetype` engine to load TTF files directly. Loading from data is not supported,
so ``as_file`` is always considered ``true``.
Required properties:
:``name``: The name to reference the font later
:``src_path``: Path to the font file
:``size``: Font size in px (e.g., "12")
LVGL's UI Editor generates a call to :cpp:expr:`lv_xml_register_font` using the set ``name``.
+77
View File
@@ -0,0 +1,77 @@
.. _xml_images:
======
Images
======
Overview
********
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
In XML, images are considered external resources that need to be named in order to be referenced in
XML files. Below is how to map images with names.
Registering Images
******************
From File
---------
If the images are used as files (e.g., PNG images loaded from a file system),
they can be simply added to ``globals.xml``:
.. code-block:: xml
<images>
<file name="avatar" src_path="images/avatar1.png"/>
<file name="logo" src_path="images/path/to/my_logo.png"/>
</images>
When registering ``globals.xml`` with
:cpp:expr:`lv_xml_component_register_from_file("A:path/to/globals.xml")`,
names are automatically mapped to the path.
The images can have relative paths in ``globals.xml``. Before registering ``globals.xml``,
:cpp:expr:`lv_xml_set_default_asset_path("path/prefix/")` can be called to set the parent folder.
The path of the image files will be appended to the path set here.
From Data
---------
If the images are converted to arrays and compiled into the firmware, they need to be
registered explicitly using:
.. code-block:: cpp
lv_xml_register_image(NULL, "image_name", &my_image)
where ``my_image`` is an :cpp:type:`lv_image_dsc_t`.
After that, it can be used identically to image files:
.. code-block:: xml
<lv_image src="image_name" align="center"/>
Usage in XML
************
After registration, the images can be referenced by their name:
.. code-block:: xml
<lv_image src="avatar" align="center"/>
Notes for the UI Editor
***********************
When using LVGL's UI Editor, images can be added to ``globals.xml`` using the
``<data>`` tag instead of ``<file>``.
In this case, the Editor will generate the C array (:cpp:type:`lv_image_dsc_t`)
and also generate code to register the images.
It's also possible to set the target ``color_format="..."`` of the images. All typical
color formats are supported, like i1...i8, a1...a8, rgb565, rgb888, argb8888, etc.
@@ -1,134 +0,0 @@
.. _xml_fonts:
=====
Fonts
=====
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
Overview
********
A ``<fonts>`` section can be added in ``globals.xml`` files.
Later, it might be supported in Components and Widgets to define local fonts and keep
the global space cleaner.
Usage
*****
The following section creates a mapping between font names and their paths with various attributes:
.. code-block:: xml
<fonts>
<bin as_file="false" name="medium" src="path/to/file.ttf" range="0x20-0x7f" symbols="°" size="24"/>
<tiny_ttf as_file="true" name="big" src_path="path/to/file.ttf" range="0x20-0x7f" symbols="auto" size="48"/>
<freetype name="chinese" src_path="file.ttf" size="48" custom_freetype_attribute="abc"/>
</fonts>
In ``<styles>`` and ``<view>``, fonts can then be referenced by their name, e.g.,
.. code-block:: xml
<style name="style1" text_font="medium"/>
The tag name determines how the font is loaded. Currently, only ``tiny_ttf as_file="true"`` is supported.
- ``bin``:
- If ``as_file="true"``: Converts the font file to ``bin`` (see `lv_font_conv`)
which will be loaded by ``lv_binfont_create()``.
- If ``as_file="false"`` (default): On export, the font file will be converted to a
C array LVGL font that can be used directly by LVGL.
- ``tiny_ttf``:
- If ``as_file="true"``: Can be loaded directly by ``lv_tiny_ttf_create_file()``.
- If ``as_file="false"`` (default): The font file will be converted to a raw C
array on export that will be loaded by ``lv_tiny_ttf_create_data()``.
- ``freetype``: The file can be loaded directly by ``lv_freetype_font_create()``.
For simplicity, if ``as_file="false"``, fonts will be loaded as files in the preview.
Setting ``as_file="false"`` affects only the C export.
If the UI is created from XML at runtime and a ``globals.xml`` is parsed, the
``as_file="false"`` tags are skipped because it is assumed that the user manually
creates the mapping. This is because the XML parser cannot automatically map an LVGL
font definition like:
.. code-block:: c
lv_font_t my_font_24;
to
.. code-block:: xml
<bin name="my_font_24"/>
Exported Code
-------------
When C code is exported, global ``const lv_font_t * <font_name>`` variables are
created, and in the initialization function of the Component Library (e.g.,
``my_lib_init_gen()``), the actual font is assigned.
.. Note: :cpp:expr: role cannot be used here because it doesn't know how to parse
the ampersand and angle brackets. An alternate approach could be to make the
arguments "style1_p, font_name", but leaving the ampersand there seems more
appropriate due to that IS the normal way to pass a style as an argument.
So it was made into a literal string instead to avoid the parsing error.
In ``lv_style_set_text_font(&style1, <font_name>)``, the created font is referenced.
Default Font
------------
``"lv_font_default"`` can be used to access ``LV_FONT_DEFAULT``. Other built-in fonts
are not exposed by default.
Registering fonts
-----------------
If the UI is created from XML at runtime and a ``globals.xml`` is parsed, the ``<... as_file="false">`` tags are skipped
because it is assumed that the user manually created the mapping.
This is because the XML parser cannot automatically map fonts like:
.. code-block:: c
lv_font_t my_font;
to
.. code-block:: xml
<data name="my_font"/>
To register a font in the XML engine use:
.. code-block:: c
lv_xml_register_font(scope, "font_name", &my_font);
``scope`` is usually ``NULL`` to register the font in the global scope.
To register a font locally for a component you can get its scope with:
.. code-block:: c
lv_xml_component_get_scope("component_name");
After calling this function, when ``"font_name"`` is used as a font in XML, ``&my_font`` will be used.
Notes for the UI Editor
-----------------------
For simplicity, in the UI editor's preview, fonts are always loaded as tinyttf fonts.
It makes the preview dynamic as no code export and compilation is needed when a font changes.
@@ -1,76 +0,0 @@
.. _xml_images:
======
Images
======
Overview
********
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
An ``<images>`` section can be added to ``globals.xml`` files. If present, it
describes how to map images with names.
Usage
*****
.. code-block:: xml
<images>
<file name="avatar" src_path="avatar1.png"/>
<data name="logo" src_path="logo1.png" color-format="rgb565" />
</images>
- ``<file>`` means that the image source is used as a file path:
- ``<data>`` means that the image is converted to a C array on export.
In both cases in the exported C code global ``const void * <image_name>`` variables are created and in the
initialization function of the Component Library (e.g. ``my_lib_init_gen()``) either the path or
the pointer to the converted :cpp:type:`lv_image_dsc_t` pointers are assigned to that variable.
In :cpp:expr:`lv_image_set_src(image, image_name)` ``image_name`` is used
instead of the path or :cpp:type:`lv_image_dsc_t` pointer.
Registering images
------------------
If the UI is created from XML at runtime and a ``globals.xml`` is parsed, the ``<data>`` tags are skipped
because it is assumed that the user manually created the mapping. This is because the XML parser cannot
automatically map an image like:
.. code-block:: c
lv_image_dsc_t my_logo;
to
.. code-block:: xml
<data name="my_logo"/>
To register an image path or data in the XML engine use:
.. code-block:: cpp
lv_xml_register_image(scope, "image_name", data)
``scope`` is usually ``NULL`` to register the image in the global scope.
To register an image locally for a component you can get its scope with:
.. code-block:: cpp
lv_xml_component_get_scope("component_name")
After calling this function, when ``"image_name"`` is used as an image source in XML, ``data``
(can be a path or a pointer to an image descriptor) will be used.
Notes for the UI Editor
-----------------------
For simplicity, in the UI editor's preview, images are always loaded as files.
It makes the preview dynamic so no code export and compilation is needed when an image changes.
-16
View File
@@ -1,16 +0,0 @@
.. _xml_building_uis:
============
Building UIs
============
.. toctree::
:class: toctree-1-deep
:maxdepth: 1
root_elements/index
main_tags/index
assets/index
events
subjects
translation
@@ -1,15 +0,0 @@
.. _xml_main_tags:
=============
Main XML Tags
=============
.. toctree::
:maxdepth: 2
api
consts
styles
view
animations
preview
@@ -1,14 +0,0 @@
.. _xml_root_elements:
=============
Root elements
=============
.. toctree::
:class: toctree-1-deep
:maxdepth: 2
components
widgets
screens
+13
View File
@@ -0,0 +1,13 @@
.. _xml_features:
========
Features
========
.. toctree::
:class: toctree-1-deep
:maxdepth: 2
subjects
tests
translations
+3 -2
View File
@@ -10,6 +10,7 @@ XML - Declarative UI
:maxdepth: 2
overview/index
build_ui/index
test
ui_elements/index
assets/index
features/index
license
@@ -1,154 +0,0 @@
.. _xml_component_library:
=================
Component Library
=================
Overview
********
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
The collection of Components, Widgets, Screens, Images, Fonts, etc., is called a
Component Library.
A Component Library can be fully self-contained, or it can also reference data from
other Component Libraries.
LVGL itself is a Component Library that supplies the built-in Widgets, data types,
etc. You can find the XML files that describe the LVGL Widgets
`here <https://github.com/lvgl/lvgl/tree/master/xmls>`__.
An LVGL firmware project that uses external XML files to define part (or all) of its
user interface (UI) always has at least 2 Component Libraries: that of LVGL as
mentioned above, and at least 1 Component Library where a related set of Screens,
Components, and Widgets of the project are defined. A project may include additional
Component Libraries.
Structure
*********
A typical structure for a Component Library looks like this:
.. code-block:: none
name_of_the_component_library
├── globals.xml
├── components
│ ├── component1.xml
│ ├── component2.xml
│ └── other_folder
│ ├── component3.xml
│ └── component4.xml
├── widgets
│ ├── widget1
│ │ ├── widget1.xml
│ │ ├── widget1.c
│ │ ├── widget1.h
│ │ ├── widget1_gen.c
│ │ ├── widget1_gen.h
│ │ ├── widget1_private_gen.h
│ │ └── widget1_xml_parser.c
│ └── widget2
│ └── ...same as widget1...
├── screens
│ ├── screen1.xml
│ └── screen2.xml
├── fonts
│ ├── font1.ttf
│ └── font2.ttf
└── images
├── image1.png
└── image2.png
Name Visibility
***************
In the context of UI components defined in XML files, there are two namespaces:
:global namespace:
Created from the combined data from the ``globals.xml`` file from each included
Component Library, the names of :ref:`Subjects <observer_subject>`, enumerations,
constants, styles, fonts and images defined therein can be referenced from all
XML files used in a project.
:local namespace:
Names created within all other XML files can only be referenced from within those
XML files. Exception: names of defined Components, Widgets and Screens become
part of the global namespace, and therefore must be unique within the global
namespace. This ensures each Component has a unique name.
All data belonging to the LVGL core Component Library is prefixed by ``lv_``
(e.g., ``lv_label``, ``lv_font_default``).
A custom Component can be prefixed with ``watch_``, ``small_``, ``light_``, or
anything else the development team deems appropriate.
LVGL's UI |nbsp| Editor will show an error if there is a name conflict.
``globals.xml``
***************
A single ``globals.xml`` file should be created in the root directory of each
Component Library. The definitions in it do not belong to any specific Widget but
are available throughout the entire UI, Widgets, and all XML files. The valid tags
in it are:
:<config>: Can specify name and help.
:<api>: Used with ``<enumdefs>`` to show possible values for Widget or Component attributes.
:<subjects>: List of :ref:`Subjects <observer_subject>`; can be considered the API of a Component Library.
:<consts>: Globally available constants.
:<styles>: Globally available styles.
:<fonts>: Globally available fonts.
:<images>: Globally available images.
:<const_variants>: See below.
:<style_variants>: See below.
The ``globals.xml`` must be the only ``globals.xml`` file within the Component
Library's folder tree.
From each ``globals.xml`` file, a ``<config.name>.h`` file is generated, which is
included by all generated header files --- not only in the sub-folders where
``globals.xml`` is created, but in all exported .C and .H files. This ensures that
constants, fonts, and other global data are available for all Widgets and new Widgets.
Example
-------
A ``globals.xml`` file of a Component Library might look like this:
.. code-block:: xml
<globals>
<api>
<enumdef name="mode">
<enum name="slow"/>
<enum name="fast"/>
</enumdef>
</api>
<consts>
<px name="small_unit" value="8"/>
<px name="large_unit" value="16"/>
</consts>
<styles>
<style name="style_red" bg_color="0xff0000">
</styles>
<images>
<file name="arrow_left" src="A:/images/arrow_left.png"/>
</images>
<fonts>
<tiny_ttf name="big" src="A:/fonts/arial.ttf" size="28"/>
</fonts>
</globals>
-2
View File
@@ -9,7 +9,5 @@ Overview
:maxdepth: 2
intro
component_library
project
syntax
+105 -135
View File
@@ -7,132 +7,93 @@ Introduction
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
.. glossary::
Declarative UI
Declarative UI (user interface) is an approach to UI creation in which the
creator describes *what* elements are needed in the UI, what data they are
bound to, and to some degree, what they should look like, but can leave out
details such as their exact position or in what sequence they should be
created at run time.
Imperative UI
Imperative UI is an approach to UI creation in which the creator describes
every detail of how the UI is created at run time. Imperative UI is the
UI-building approach you use when you build your LVGL UI in C code.
The LVGL XML Module implements LVGL's :term:`Declarative UI` by loading UI elements
written in XML. The XML file can be written by hand, but it is considerably more
efficient to write the XML files using `LVGL's UI Editor <https://lvgl.io/editor>`__
and thus highly recommended. This UI Editor provides features like:
- instant preview of the XML files,
- auto-complete,
- syntax highlighting,
- online preview for collaboration and testing,
- `Figma <https://www.figma.com/>`__ integration to efficiently implement Figma
designs in LVGL.
.. warning::
The UI editor and the XML loader are still under development and not
production-ready. Consider them as an open beta or experimental features.
The LVGL XML Module implements LVGL's Declarative UI by making it possible to
describe UIs in XML.
Describing the UI in XML in a declarative manner offers several advantages:
- XML files can be loaded at runtime (e.g. from an SD card) allowing you to change
- XML files can be loaded at runtime (e.g., from an SD card), allowing you to change
the application's UI without changing the firmware.
- XML files can be loaded dynamically as well, which allows for things like creating
UIs from plugins or apps that are downloaded by the firmware.
- XML files can also be loaded dynamically, enabling use cases such as creating
UIs from plugins or apps downloaded by the firmware.
- XML is simpler to write than C, enabling people with different skill sets to create LVGL UIs.
- XML is textual data, making it easy to parse and manipulate with a large number of
programming and scripting languages.
- XML can be used to generate LVGL code in any language.
- XML helps to separate the view from the internal logic.
- The XML syntax uses the same properties as the C API, so it's easy to learn. E.g.
style properties like bg_color, line_width, or widget properties like width,
height, label text, etc.
- A powerful data binding engine allows you to easily bind the widgets to global data.
- XML helps separate the view from the internal logic.
- The XML syntax uses the same properties as the C API, so it's easy to learn. E.g.,
style properties like ``bg_color``, ``line_width``, or widget properties like ``width``,
``height``, label ``text``, etc.
- A powerful data binding engine allows you to easily bind widgets to global data.
The XML file can be written by hand, but it's highly recommended to use `LVGL's
UI editor <https://lvgl.io/editor>`__ to write the XML files. This UI editor
makes UI development much faster by providing features like:
- Instant preview of the XML files (components, screens)
- Inspector mode to visualize widget sizes, paddings, etc.
- Generate C code from XML files
- Autocomplete and syntax highlighting
- Online share/preview for collaboration and testing
- `Figma <https://www.figma.com/>`__ integration to easily reimplement Figma designs
Concept
*******
.. warning::
The XML files are Component-oriented. To be more specific, they are ``Component-Library`` oriented.
That is, they are structured in a way to make it easy to create reusable Component Libraries.
The UI editor and the XML loader are still under development and not
production-ready. Consider them as open beta or experimental features.
For example, a company can have a Component Library for the basic Widgets for all its products
(generic widgets for all smart devices), and create other industry-specific Libraries
(smart-home specific, smart-watch specific, etc.) containing only a few extra Widgets and Components.
Using the XML files
*******************
These Component Libraries are independent, can be reused across many products, and can
be independently versioned and managed. Imagine a Component Library as a collection
of XML files that describe Widgets, Components, Screens, images, fonts, and other
assets stored in a git repository, which can be a submodule in many projects. If
someone finds a bug in the Component Library, they can simply fix it in one place and
push it back to the git repository so that other projects can be updated from it.
If writing XMLs by hand, the concept is very simple:
The built-in Widgets of LVGL are considered ``the core Component Library`` which is
always available.
1. When ``LV_USE_XML`` is enabled, LVGL's built-in widgets and other XML parsers for styles, events,
data bindings, etc., are registered automatically.
2. The XML files created by the user (such as Screens, Components, Images, Fonts, etc.) can be
registered (loaded) at runtime, and screen or component instances can also be created based on the
XML "blueprints".
3. The widgets created from XML look like any normal widgets, so functions of the C API can be applied
to them. E.g., start an animation, add a special style, etc.
A UI Editor project can have any number of Component Libraries but will always
have at least 2:
- LVGL's built-in Widgets, and
- XML-based definitions of Screen contents, along with other project-specific Components.
Widgets, Components, and Screens
********************************
UI Elements
***********
It is important to distinguish between :dfn:`Widgets`, :dfn:`Components`, and :dfn:`Screens`.
Widgets
-------
:dfn:`Widgets` are the core building blocks of the UI and are **not meant to be loaded at runtime**
but rather compiled into the application as C code. The main characteristics of Widgets are:
but rather compiled into the application as C code. The main characteristics of Widgets are:
- In XML, they start with a ``<widget>`` root element.
- They are similar to LVGL's built-in Widgets.
- They are built using ``lv_obj_class`` objects.
- They have custom and complex logic inside.
- They are similar to LVGL's built-in widgets.
- They can contain custom and complex logic.
- They cannot be loaded from XML at runtime because the custom code cannot be loaded.
- They can have a large API with ``set/get/add`` functions.
- They can themselves contain Widgets as children (e.g. ``Tabview``'s tabs, ``Dropdown``'s lists).
Any custom Widgets you create can be accessed from XML by:
1. Defining its API in an XML file.
2. Writing and registering an XML parser for it.
`See examples here. <https://github.com/lvgl/lvgl/tree/master/src/others/xml/parsers>`__
- They can have a large and custom API with ``set/get/add`` functions.
- A custom XML parser is needed to map XML properties to API function calls.
- They can be compound, containing other Widgets (e.g., ``Tabview``'s tabs, ``Dropdown``'s lists).
- In the UI editor, they can also be described in XML to create visuals more quickly and export C code.
Components
----------
:dfn:`Components` are built from Widgets and/or other Components, and **can be loaded at runtime**.
:dfn:`Components` are simpler UI elements and **can be loaded at runtime**.
The main characteristics of Components are:
- In XML, they start with a ``<component>`` root element.
- They are built in XML only and cannot have custom C code.
- They can be loaded from XML as they don't contain custom C code, only XML.
- They are built from Widgets and/or other Components.
- They can be used for styling Widgets and other Components.
- They can contain (as children) Widgets and/or other Components.
- They can have a simple API to pass properties to their children (e.g. ``btn_text`` to a Label's text).
- They are defined only in XML and cannot have custom C code (but they can call C functions as event callbacks).
- They can be loaded from XML since they contain only XML.
- They can be used for styling Widgets and other Components, using data bindings via subjects, defining animations, etc.
- As children, they can contain Widgets and/or other Components.
- They can have a simple API to pass properties to their children (e.g., ``btn_text`` to a Label's text).
Regardless of whether the XML was written manually or by the UI |nbsp| Editor, the XML
files defining Components can be registered in LVGL, and after that, instances can be
created. In other words, LVGL can just read the XML files, "learn" the Components
from them, and thereafter create those components as children of Screens and/or other
Components.
Whether the XML was written manually or by the UI |nbsp| Editor, the files
defining Components can be registered in LVGL, and after that, instances can be created.
In other words, LVGL can read the XML files, "learn" the Components from them, and
thereafter create children as part of Screens and other Components.
Screens
-------
@@ -141,36 +102,56 @@ Screens
- In XML, they start with a ``<screen>`` root element.
- They are built from Widgets and/or other Components to describe the :ref:`Screen <screens>`.
- They can be loaded from XML at runtime as they describe only visual aspects of the UI.
- They can be loaded from XML at runtime since they describe only visual aspects of the UI.
- They do not have an API.
- They can be referenced in Screen-load events.
- They can be referenced in screen load events.
Global data
***********
``globals.xml`` is a special XML file in which globally available
Syntax Teaser
*************
- styles
- constants
- images
- fonts
- subjects for data bindings
Each Widget, Component, or Screen XML file describes a single UI element. The root
element for Widgets, Components, and Screens is ``<widget>``, ``<component>``, and
``<screen>`` respectively. Other than that, the contained XML elements are almost
identical. This is a high-level overview of the most important XML elements that
will be children of these root elements:
can be defined.
:<api>: Describes the properties that can be ``set`` for a Widget or Component.
Properties can be referenced by ``$``. For Widgets, custom enums can
also be defined with the ``<enumdef>`` tag.
Multiple ``globals.xml`` files can be loaded if needed, but each will be saved in the same global scope,
meaning duplicated items will be added only once.
Usage Teaser
************
Each Component or Screen XML file describes a single UI element.
The syntax and supported XML tags are very similar in all three.
Note that for Widgets, XML can be used to export C code in LVGL's UI Editor.
This is a high-level overview of the most important XML elements that
can be children of these root elements:
:<api>: Describes the properties that can be ``set`` in a Component.
Properties can be referenced by ``$``.
:<consts>: Specifies constants (local to the Widget or Component) for colors, sizes,
and other values. Constant values can be referenced using ``#``.
:<styles>: Describes style (``lv_style_t``) objects that can be referenced (and
shared) by Widgets and Components later.
:<view>: Specifies the appearance of the Widget or Component by describing the
:<styles>: Describes style (``lv_style_t``) objects that can be referenced
by Widgets and Components later.
:<view>: Specifies the appearance of the Widget, Component, or Screen by describing the
children and their properties.
An XML component
----------------
This is a simple example illustrating what an LVGL XML Component looks like.
Only basic features are shown.
Note that only the basic features are shown here.
.. code-block:: xml
<!-- my_button.xml -->
<component>
<consts>
<px name="size" value="100"/>
@@ -195,43 +176,32 @@ Only basic features are shown.
</view>
</component>
Load the UI from XML
--------------------
The Component XML can be loaded, and any number of instances can be created at runtime.
Usage Teaser
************
In the simplest case, a Component can be registered with
:cpp:expr:`lv_xml_component_register_from_file("A:path/to/my_button.xml")` and an instance can be created with
:cpp:expr:`lv_obj_t * obj = lv_xml_create(parent, "my_button", NULL)`.
LVGL's UI editor can be used in two different ways.
Note that loading the UI from XML has practically no impact on performance.
Once the XML files are registered and the UI is created, it behaves the same way
as if it were created from C code.
Registering XML files and creating instances is not memory-hungry nor slow. The biggest
memory overhead is that the ``<view>`` of the Components is saved in RAM (typically
12 kB per component).
Export C and H Files
--------------------
The Widgets, Components, Screens, images, fonts, etc., can be converted to .C/.H files having
code that accesses the LVGL API in the same way user-written code does.
By using LVGL's UI Editor, the Widgets, Components, Screens, images, fonts, etc., can be
converted to .C/.H files containing plain LVGL code.
In this case, the XML files are not required anymore to run the C code (unless modifications
are made later and code is exported again).
The exported code works the same way as if it were written by the user.
The XML files were used only during Widget and Component creation to save
recompilation time and optionally to take advantage of other useful UI editor features.
In this case, the XML files are not required anymore to run the C code.
Load the UI from XML
--------------------
Although Widgets' XML always needs to be exported in C and compiled into the
application (just like the built-in LVGL Widgets' C code is compiled into the
application), the XML for Components can be loaded (learned) at runtime, and
thereafter any number of instances of them can be created.
In the simplest case, a Component can be registered with
:cpp:expr:`lv_xml_component_register_from_file(path)` and an instance can be created with
:cpp:expr:`lv_obj_t * obj = lv_xml_create(parent, "my_button", NULL)`.
Note that loading UI components from XML has virtually no impact on performance.
Once the XML files are registered and the UI is created, the performance, appearance
and behavior are exactly the same as if it were created from C code.
Registering XML Components and creating instances are neither memory hungry nor slow.
The biggest memory overhead is that the ``<view>`` of the Components is saved in RAM
(typically 12 kB/component).
The XML files are used only during the editing/implementation of the Widgets, Components, and Screens to save
recompilation time and optionally leverage other useful UI |nbsp| Editor features.
-55
View File
@@ -1,55 +0,0 @@
.. _xml_project:
=======
Project
=======
Overview
********
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
A single ``project.xml`` file should be created for each project where the following
content is specified:
:<folders>: Specifies the list of paths to Component Libraries. LVGL's base Widgets are
always loaded automatically, and therefore do not need to be specified
in this list.
:<targets>: Describes various hardware configurations, allowing the UI |nbsp| Editor
to check if the UI is out of resources and to select different previews
for each Screen according to the specified displays.
In LVGL's Editor the ``folders``, ``memory`` and `` <display color_format="..."/>`` are not supported yet.
Example
*******
.. code-block:: xml
<project>
<folders>
<folder path="../widget_lib1"/>
<folder path="/home/user/work/ui_libs/modern"/>
<folder path="https://github.com/user/repo"/>
</folders>
<targets>
<target name="small">
<display width="320" height="240" color_format="RGB565"/>
<memory name="int_ram" size="128K"/>
<memory name="ext_ram" size="2M"/>
<memory name="int_flash" size="512K"/>
<memory name="ext_flash" size="32M"/>
</target>
<target name="large">
<display width="1024" height="768" color_format="XRGB8888"/>
<memory name="int_ram" size="128K"/>
<memory name="ext_ram" size="2M"/>
<memory name="int_flash" size="512K"/>
<memory name="ext_flash" size="32M"/>
</target>
</targets>
</project>
+35 -40
View File
@@ -11,15 +11,15 @@ Naming conventions
:trim:
- A standard XML syntax is used.
- Lowercase letters with ``'_'`` separators are used for attribute names.
- Tag names follow the usual C variable-name rules: they must start with a letter or
- Lowercase letters with ``_`` separation are used for attribute names.
- Tag names follow the usual variable-name rules: they must start with a letter or
``'_'`` and the rest of the name may be comprised of letters, ``'_'`` and digits.
- The LVGL API is followed as much as possible, e.g., ``align="center"``, ``bg_color="0xff0000"``.
- For colors, all these syntaxes are supported (similar to CSS colors): ``0x112233``,
``#112233``, ``112233``, ``0x123``, ``#123``, ``123``. Note that like CSS,
``0x123``, ``#123`` and ``123`` all mean ``#112233``.
- ``params`` can be referenced using ``$`` as a name prefix.
- ``consts`` can be referenced using ``#`` as a name prefix.
- ``params`` can be referenced with ``$``.
- ``consts`` can be referenced with ``#``.
- ``styles`` can be attached to states and/or parts like this:
``styles="style1 style2:pressed style3:focused:scrollbar"``.
- Local styles (i.e. styles that are stored within the Component and thus not shared
@@ -28,10 +28,10 @@ Naming conventions
Data Types
**********
Types
*****
All of the data types can be used as API property types, but only a subset of them can be
All of the types can be used as API property types, but only a subset of them can be
used as constant and :ref:`Subject <observer_subject>` types.
@@ -42,10 +42,10 @@ The following simple built-in types are supported:
:bool: a ``true`` or ``false``.
:int: Integer number in the range of roughly -2 billion to 2 billion by default.
:int: Integer number in the range of roughly -2B to 2B by default.
(Same as ``int32_t`` in C.)
:px: Simple pixel units. The unit suffix ``px`` can be omitted from the numeric value.
:px: Simple pixel units. The unit ``px`` can be omitted.
:%: Percentage. ``%`` must be appended to the value as the unit.
(Means the same as :cpp:expr:`lv_pct()`.)
@@ -53,8 +53,7 @@ The following simple built-in types are supported:
:content: Means ``LV_SIZE_CONTENT``.
:string: Simple NUL-terminated string. When multiple strings are used in a
property or string array, ``'`` should be used. E.g. ``foo="'a' 'b'"``
represents an array of 2 strings.
property or string array, ``'`` should be used. E.g. ``foo="'a' 'b'"``.
:color: A color stored as 24-bit RGB (:cpp:expr:`lv_color_t`).
@@ -65,50 +64,47 @@ The following simple built-in types are supported:
:screen: Pointer to a screen (also :cpp:expr:`lv_obj_t *`).
:time_ms: Means some time in milliseconds
:time_ms: Means some time in milliseconds unit
:deg_0.1: Degrees with 0.1 resolution
:scale_1/256: Scale/Zoom, where 256 means 100%, 128 means 50%, 512 means 200% etc.
Name-based types
----------------
In XML files, fonts, images, styles, etc., are used by their names, rather than by
pointers as they are in C. For example, a style is defined like ``<style name="red"
bg_color="0xff0000"/>``. Later, it can be referenced by its name: "red".
In XML files, fonts, images, styles, etc., are not used by pointer but by string
names. For example, a style is defined like ``<style name="red" bg_color="0xff0000"/>``.
Later, they can be referenced by their names.
This means that the actual objects need to be bound to the names when the UI is loaded
from XML files so LVGL knows what each name means.
This means that the actual values need to be bound to the names when the UI is loaded
from XML, otherwise, LVGL wouldn't know what a name means.
Most of these connections are done automatically (e.g., for styles, fonts, images,
animations, gradients, etc.), but others need to be connected manually in C code
(e.g., event callbacks where the callback itself is available only in C code).
animations, gradients, etc.), but others need to be connected manually (e.g., event
callbacks where the callback itself is available only in the code).
For fonts and images, the connections are created automatically if the source is an
XML file. If the font or image is compiled into the application (as a C array), the
user needs to specify which variable a given name refers to.
For fonts and images, the connections are created automatically if the source is a file.
If the font or image is compiled into the application (as a C array), the user needs
to specify which variable a given name refers to.
To create these connections, functions like
- :cpp:expr:`lv_xml_register_image(scope, name, pointer)`
- :cpp:expr:`lv_xml_register_font(scope, name, pointer)`
- :cpp:expr:`lv_xml_register_event_cb(scope, name, callback)`
- ``lv_xml_register_image(scope, name, pointer)``
- ``lv_xml_register_font(scope, name, pointer)``
- ``lv_xml_register_event_cb(scope, name, callback)``
- etc.
can be used. Later, a pointer to the object can be retrieved by
- :cpp:expr:`lv_xml_get_image(scope, name)`
- :cpp:expr:`lv_xml_get_font(scope, name)`
- :cpp:expr:`lv_xml_get_event_cb(scope, name)`
- ``lv_xml_get_image(scope, name)``
- ``lv_xml_get_font(scope, name)``
- ``lv_xml_get_event_cb(scope, name)``
- etc.
``scope`` can be ``NULL`` to use the global scope or :cpp:expr:`lv_xml_component_get_scope("my_component")`
returns the a component's local scope.
The passed ``name`` strings can be bound to:
:style: Name of a style. :cpp:expr:`lv_xml_get_style_by_name(&ctx, name)` returns an :cpp:expr:`lv_style_t *`.
:font: Name of a font. :cpp:expr:`lv_xml_get_font(&ctx, name)` returns an :cpp:expr:`lv_font_t *`.
:image: Name of an image. :cpp:expr:`lv_xml_get_image(&ctx, name)` returns an :cpp:expr:`const void *`,
@@ -117,8 +113,7 @@ The passed ``name`` strings can be bound to:
:subject: Name of a :ref:`Subject <observer_subject>`. :cpp:expr:`lv_xml_get_subject(&ctx, name)` returns an :cpp:expr:`lv_subject_t *`.
:grad: Name of a gradient. :cpp:expr:`lv_xml_get_grad(&ctx, name)` returns an :cpp:expr:`lv_grad_dsc_t *`.
:event_cb: Name of an event callback. :cpp:expr:`lv_xml_get_event_cb(&ctx, name)` returns an :cpp:expr:`lv_event_cb_t`.
:screen_create_cb: In XML it's the name of a screen's XML file. In exported code it's a function like ``lv_obj_t * my_screen_create(void)``
:screen_create_cb: In XML it's the name of a screen XML file. In exported code it's a function like ``lv_obj_t * my_screen_create(void)``
Arrays
------
@@ -126,7 +121,7 @@ Arrays
An array of any type can be defined in four ways:
:int[N]: An integer array with ``N`` elements.
In the exported code ``N`` is passed as a parameter after the array.
In the exported code ``N`` is passed a parameter after the array.
:string[...NULL]: An array terminated with a ``NULL`` element. ``NULL`` can be
replaced by any value.
:string[5]: An array that must have exactly 5 elements. In the exported code only the array will be passed
@@ -151,7 +146,7 @@ For example:
<enum name="inverted" help="Inverted mode"/>
</enumdef>
<prop name="mode" help="help" type="enum:my_widget_mode" help="help"/>
<prop name="mode" help="help"type="enum:my_widget_mode" help="help"/>
</api>
When used as a type, a ``+`` suffix means multiple values can be selected and ORed.
@@ -162,19 +157,19 @@ For example: ``type="axis+"``. In this case, the options should be separated by
Compound types
--------------
Types can be compound, meaning multiple options/types are possible. Example for
Types can be compound, meaning multiple options/types are possible. For example, for
width: ``type="px|%|content"``.
Limiting accepted values
------------------------
**Not supported yet; the examples below illustrate the planned syntax.**
It is also possible to limit the possible options the user can select from an enum.
For example:
- Enums: ``type="dir(top bottom)"``
- Colors: ``type="color(0xff0000 0x00ff00 0x0000ff)"``
- Strings: ``type="string('Ok' 'Cancel')"``
Limiting accepted values is not supported yet, however in the UI |nbsp| Editor if
an invalid option is selected, it will be highlighted as an error.
- Strings: ``type="string('Ok' 'Cancel')``
@@ -1,4 +1,4 @@
.. _xml_animations:
.. _xml_animations:
==========
Animations
@@ -13,7 +13,7 @@ Timelines are composed of simple animations. For example: *"change the ``bg_opa`
of ``my_button_2`` from 0 to 255 in 500 ms."*
Each component can define its own timeline animations, which can then be played by the
component itself or by any parent components.
component itself or by any parent component.
Defining Timelines
------------------
@@ -26,31 +26,33 @@ Example:
.. code-block:: xml
<animations>
<component>
<animations>
<!-- Show the component and its children -->
<timeline name="load">
<animation prop="translate_x" target="self" start="-30" end="0" duration="500"/>
<animation prop="opa" target="icon" start="0" end="255" duration="500"/>
<animation prop="opa" target="text" start="0" end="255" duration="500" delay="200"/>
</timeline>
<!-- Show the component and its children -->
<timeline name="load">
<animation prop="translate_x" target="self" start="-30" end="0" duration="500"/>
<animation prop="opa" target="icon" start="0" end="255" duration="500"/>
<animation prop="opa" target="text" start="0" end="255" duration="500" delay="200"/>
</timeline>
<!-- Shake horizontally -->
<timeline name="shake">
<animation prop="translate_x" target="self" start="0" end="-30" duration="150"/>
<animation prop="translate_x" target="self" start="-30" end="30" duration="300" delay="150"/>
<animation prop="translate_x" target="self" start="30" end="0" duration="150" delay="450"/>
</timeline>
</animations>
<!-- Shake horizontally -->
<timeline name="shake">
<animation prop="translate_x" target="self" start="0" end="-30" duration="150"/>
<animation prop="translate_x" target="self" start="-30" end="30" duration="300" delay="150"/>
<animation prop="translate_x" target="self" start="30" end="0" duration="150" delay="450"/>
</timeline>
</animations>
<view>
<lv_button width="200">
<my_icon name="icon" src="image1"/>
<lv_label name="text" text="Click me"/>
</lv_button>
</view>
<view>
<lv_button width="200">
<my_icon name="icon" src="image1"/>
<lv_label name="text" text="Click me"/>
</lv_button>
</view>
</component>
In summary: inside ``<animations>``, you can define ``<timeline>``\ s, each with a unique name
In summary: inside ``<animations>``, you can define ``<timeline>``\s, each with a unique name
that you can reference later.
Inside a ``<timeline>``, you add ``<animation>``\ s to describe each step.
@@ -83,29 +85,30 @@ Example:
</custom_button>
</view>
You set a ``target`` UI element and select one of its ``timeline``s to play.
You set a ``target`` UI element and select one of its ``timeline``\ s to play.
If ``target="self"``, the timeline is looked up in the current component/widget/screen
(i.e. in the current XML file).
You can also set ``delay`` and ``reverse="true"`` when playing a timeline.
You can also set a ``delay`` and ``reverse="true"`` when playing a timeline.
Under the Hood
--------------
Understanding how timelines work internally helps use them effectively.
Understanding how timelines work internally helps in using them effectively.
When an XML file is registered, the contents of the ``<animations>`` section are parsed,
and the animation data is stored as a blueprint.
When an instance of a component or screen is created, ``lv_anim_timeline``\ s are
created and initialized from the saved blueprint. Each instance gets its own copy.
When an instance of a component or screen is created, ``lv_anim_timeline``\s are
created and initialized from the saved blueprint. Each instance gets its own copy of the timelines.
When a ``<play_timeline_event>`` is added to a UI element, the target and timeline
names are saved as strings. (It can't use pointers as the event can reference UI elements
that will be created only later in the ``<view>``.)
Finally, when the trigger event happens, LVGL finds the target widget by the saved name,
Finally, when the play timeline event is triggered, LVGL finds the target widget by the saved name,
retrieves the specified timeline, and starts it.
Since each instance has its own timeline, you can have multiple components (e.g. 10 ``<list_item>``\ s)
Since each instance has its own timeline, you can have multiple components (e.g. 10 ``<list_item>``\s)
and play their ``load`` timelines independently with different delays.
@@ -13,8 +13,6 @@ The only common point is that both Widgets and Components support having
However, as Widgets and Components work very differently (Widgets have C code,
but Components are pure XML), even properties are interpreted differently.
Components
**********
@@ -23,8 +21,8 @@ Overview
While Widgets can have complex ``set``/``get`` APIs, Components are very simple.
When their XML is converted to a C file, only a ``create`` function is generated,
where all the ``<prop>``\ s are arguments. For example:
When a component's XML is converted to C files, only a ``create`` function is generated,
where all the ``<prop>``\s are arguments. For example:
.. code-block:: xml
@@ -33,7 +31,29 @@ where all the ``<prop>``\ s are arguments. For example:
<prop name="prop2" type="string"/>
</api>
This generates the following C function:
Referencing properties
----------------------
``<prop>``\ s are simply forwarded to Widget or Component APIs.
For example, if a component has ``<prop name="button_label" type="string"/>``,
it can be used in a label child as ``<lv_label text="$button_label"/>``.
In the code generated by LVGL's UI Editor, these are passed as arguments in create/set functions.
Default values
--------------
Since each property is passed as an argument to the create function, each must have a value.
This can be ensured by:
- Simply setting them in the XML instance
- Providing a default value in the ``<api>``, e.g., ``<prop name="title" type="string" default="my_default_text"/>``
Code generation
---------------
LVGL's UI Editor can also generate code from the component's XML. Depending on the ``<api>``, a function like
this is generated:
.. code-block:: c
@@ -43,34 +63,12 @@ These properties are set once (at creation time), and there are no specific
``set`` functions to modify the property later. LVGL's general API can still be
used to modify any widget in the component, but no dedicated API functions are generated.
Referencing properties
----------------------
``<prop>``\ s are simply forwarded to widget or component APIs.
For example, if a component has ``<prop name="button_label" type="string"/>``,
it can be used in a label as ``<lv_label text="$button_label"/>``.
In the generated code, these are passed as arguments in create/set functions.
Default values
--------------
Since each property is passed as an argument to the create function, each must have a value.
This can be ensured by:
- Simply setting them in the XML instance
- Providing a default value in the ``<api>``, e.g., ``<prop name="foo" type="string" default="bar"/>``
Limitations
-----------
Note that none of the Widget API features such as ``<param>``, ``<enumdef>``, or ``<element>``
can be used for Components. Only simple properties that are forwarded are supported.
Example
-------
@@ -98,12 +96,9 @@ Example
</view>
</component>
Widgets
*******
Properties
----------
@@ -115,7 +110,6 @@ Properties are the core part of describing a Widget's API.
<prop name="text" type="string" help="Text of the label."/>
</api>
Parameters
----------
@@ -147,7 +141,6 @@ Unset parameters fall back to:
- Their default value (if defined)
- Type-specific defaults (e.g., 0, false, NULL)
Mapping
-------
@@ -155,11 +148,10 @@ Each ``<prop>`` is mapped to a ``set`` function. This mapping is implemented
in the Widget's XML parser.
See `the LVGL XML parsers <https://github.com/lvgl/lvgl/tree/master/src/others/xml/parsers>`_.
If ``<param>``s are used, they are passed to the same ``set`` function.
If ``<param>``\ s are used, they are passed to the same ``set`` function.
If a property is not set on a Widget instance, it is skipped and the Widget's
built-in default is used.
<enumdef>
---------
@@ -177,41 +169,59 @@ Only used with Widgets, this tag defines enums for parameter values.
</prop>
</api>
Enum values are ignored in export; the names are used and resolved by the compiler.
XML parsers must handle mapping enum names to C enums.
The actual values of the enum fields are not important during code export as only the names are used and resolved by the compiler.
XML parsers must handle mapping enum string names (e.g. ``"normal"``) to C enums (e.g. ``MY_WIDGET_MODE_NORMAL``).
.. _xml_widget_element:
<element>
---------
``<element>``
-------------
Also exclusive to Widgets, elements define sub-widgets or internal structures
(e.g., chart series, dropdown list, tab views).
(e.g., chart series, dropdown lists, tab views).
They support ``<arg>`` and ``<prop>``:
Elements are also very useful to create "slots" (similar to tabview tabs), like a content and header area for a window widget, where
children can be created directly.
- ``<arg>``\ s are required and used when creating/getting the element.
- ``<prop>``\ s are optional and mapped to setters.
Elements are described inside the ``<api>`` tag, and they can have ``<arg>`` and ``<prop>`` children:
Elements are referenced as ``<widget-element>`` in views.
- ``<arg>``\s are required and used when creating/getting the element.
- ``<prop>``\s are optional and mapped to setters.
Name parts are separated by `-` ( as `-` is not allowed inside names).
Here's an example to define an "indicator" that can be added dynamically to a widget. It will create `my_indicator_t *`
elements, the same way as, for example, :cpp:expr:`lv_chart_add_series` works.
Element `access` types:
.. code-block:: xml
- ``add``: Create multiple elements dynamically.
- ``get``: Access implicitly created elements.
- ``set``: Access indexed parts (e.g., table cells).
- ``custom``: Map custom C function to XML.
<api>
<element name="indicator" type="my_indicator_t" help="The indicator of my_widget" access="add">
<!-- args are passed when the element is created -->
<arg name="color" type="color"/>
<arg name="max_value" type="int"/>
As ``add`` and ``get`` elements return an object they also have a type.
This type can be any custom type, for example, `type="my_data"`. In the exported code the
<!-- props can be set by setters at any time -->
<prop name="value" type="int"/>
</element>
</api>
Element `access` types can be:
- ``add``: Create multiple elements dynamically. For example, tabview tabs.
- ``get``: Access implicitly created elements. For example, dropdown lists.
- ``set``: Access indexed parts. For example, table cells.
- ``custom``: Map custom C functions to XML, e.g. ``bind_state_is_eq``
As ``add`` and ``get`` elements return an object, they also have a type.
This type can be any custom type, for example, `type="my_data"`. In the exported code, the
return value will be saved in a ``my_data_t *`` variable.
If the type is ``type="lv_obj"`` it allows the element to have children widgets or components.
If the type is ``type="lv_obj"``, it allows the element to have child widgets or components.
Note that, only the API can be defined in XML for elements; implementations must be in C.
Elements are referenced as ``<widget-element>`` in the ``<view>``.
The parts of the name are separated by `-`. As `-` is not allowed inside names, it's safe to use
as a separator.
Note that only the API can be defined in XML for elements; implementations must be in C.
access="add"
~~~~~~~~~~~~
@@ -238,7 +248,7 @@ Used in a view:
<my_widget-indicator name="indic1" color="0xff0000" max_value="120" value="30"/>
</my_widget>
Generates:
LVGL's UI Editor generates this:
.. code-block:: c
@@ -267,7 +277,7 @@ Used in a view:
<my_widget-control_button name="btn1" index="3" title="Hello"/>
</my_widget>
Generates:
LVGL's UI Editor generates this:
.. code-block:: c
@@ -297,7 +307,7 @@ Used in a view:
<my_widget-item index="3" icon_src="image1" color="0xff0000"/>
</my_widget>
Generates:
LVGL's UI Editor generates this:
.. code-block:: c
@@ -308,7 +318,7 @@ access="custom"
~~~~~~~~~~~~~~~
Used to describe any custom API functions with a custom name.
"custom" elements can have only arguments and no `type` so they are pure setters.
"custom" elements can have only arguments and no `type`, so they are pure setters.
.. code-block:: xml
@@ -326,8 +336,9 @@ Used in a view:
<my_widget-bind_color subject="subject_1" color="0xff0000" ref_value="15"/>
</my_widget>
Generates:
LVGL's UI Editor generates this:
.. code-block:: c
void my_widget_bind_color(lv_obj_t * parent, lv_subject_t * subject, lv_color_t color, int32_t ref_value);
@@ -9,48 +9,47 @@ Overview
Components are one of the main building blocks for creating new UI elements.
``<component>`` elements may contain the following child elements:
``<component>``\ s support the following child XML tags:
- :ref:`<consts> <xml_consts>`
- :ref:`<api> <xml_api>`
- :ref:`<styles> <xml_styles>`, and
- :ref:`<styles> <xml_styles>`
- :ref:`<view> <xml_view>`
- :ref:`<previews> <xml_preview>`
Although they can't contain C code, they are very powerful:
- They can extend another Component or Widget (an "inherited" base Component or
Widget can be specified).
- Components can be built from Widgets and/or other Components.
- A custom API can be defined.
- Local styles can be defined, and global styles can be referenced.
- Local constants can be defined, and global constants can be referenced.
- Events can be added as function calls, or responses to changes of Subject values,
or responses to Screens being created or loaded. See :ref:`XML Events <xml_events>`.
- Previews can be defined to preview the components in various settings.
- They can extend another Component or Widget (the base can be defined)
- Components can be built from Widgets and other Components
- A custom API can be defined
- Local styles can be defined, and global styles can be used
- Local constants can be defined, and global constants can be used
- Function calls, subject changes, or screen load/create events can be added. See :ref:`XML Events <xml_events>`
- Previews can be defined to preview the components in various settings in the UI Editor
When a Component is created, it can extend another Component or Widget like ``<view extends="lv_slider">``.
If a Widget is extended, the component can use the Widget's API, e.g., ``<view extends="lv_slider" min_value="20">``.
If a Component is extended, the ``<api>`` properties can be used: ``<view extends="my_button" button_text="Apply">``.
Unlike Widgets (which are always compiled into the application), Components can either:
1. be loaded at runtime from XML, or
2. be exported to C code and compiled with the application.
Using Components from XML
*************************
2. be exported to C code by LVGL's UI Editor and compiled with the application.
Using the XML files
*******************
In XML Files
------------
Using Components in XMLs is very intuitive. The name of the components can be used as
the name of the XML tag in the ``<view>`` of other Components, Screens, and Widgets.
Using Components in XML is very intuitive. The name of the Component can be used as an XML tag
in the ``<view>`` of other Components, Screens, and Widgets.
The Component properties are just XML attributes.
To load Components from file, it's assumed that the XML files are saved to the device
either as data (byte array) or as a file. Once the data is saved, each component
can be registered, after which instances of that Component can be created.
To load Components from files, it's assumed that the XML files are saved to the device
either as data (byte array) or as files. Once the data is saved, each Component
can be registered, and instances can be created after that.
.. code-block:: xml
@@ -62,9 +61,8 @@ can be registered, after which instances of that Component can be created.
</view>
</component>
:ref:`Styles <xml_styles>`, :ref:`Constants <xml_consts>`, and a
:ref:`custom API <component_custom_properties>` can also be described in the XML files.
:ref:`Styles <xml_styles>`, :ref:`Constants <xml_consts>`, and :ref:`custom API <component_custom_api>`
can also be described in the XML files.
Registration
------------
@@ -74,18 +72,15 @@ Once a Component is created (e.g., ``my_button``), it can be registered by calli
- :cpp:expr:`lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml")`
- :cpp:expr:`lv_xml_component_register_from_data("my_button", xml_data_of_my_button)`
These registration functions process the XML data and store relevant information
internally by name. When loaded from a file, the file name is used as the Component
name.
These registration functions process the XML data and store relevant information internally.
This is required to make LVGL recognize the Component by name.
During registration, the ``<view>`` of the Component is saved in RAM as a template for
creating instances of that Component.
Note that the "A:" in the above path is a file system "driver identifier letter" from
:ref:`file_system` and used accordingly. See that documentation for details.
.. note::
Note that the "A:" in the above path is a file system "driver identifier letter" from
:ref:`file_system` and used accordingly. See that documentation for details.
When loaded from a file, the file name is used as the Component name.
During registration, the ``<view>`` of the Component is saved in RAM.
Instantiation
-------------
@@ -96,7 +91,7 @@ After registration, a new instance of any registered Component can be created wi
lv_obj_t * obj = lv_xml_create(lv_screen_active(), "my_button", NULL);
The created Widget is a normal LVGL Widget that can be used like any other Widget.
The created Widget is a normal LVGL Widget that can be used like any other manually-created Widget.
The last parameter can be ``NULL`` or an attribute list, like this:
@@ -112,55 +107,45 @@ The last parameter can be ``NULL`` or an attribute list, like this:
lv_obj_t * btn1 = lv_xml_create(lv_screen_active(), "my_button", my_button_attrs);
Using the Exported Code
***********************
If loading XML at runtime is not needed, LVGL's UI Editor can be used to export C and H files from the XML files of the Components.
The resulting code is completely self-sufficient and the XML files are not needed anymore. The resulting code is similar to what one could write by hand as well.
Using Components from Exported C Code
*************************************
From each Component XML file, a C and H file is exported with a single function inside:
The exported code looks like this:
.. code-block:: c
lv_obj_t * component_name_create(lv_obj_t * parent, ...api properties...);
where 'component_name' (in the function above) is replaced by the Component's XML
where ``component_name`` is replaced by the Component's XML
file name.
When a Component is used in another Component's XML code and the code is exported,
this ``create`` function will be called. This means that Components do not have a
detailed set/get API but can be created with a fixed set of parameters.
detailed set/get API, but are created with a fixed set of parameters.
If the user needs to access or modify values dynamically, it is recommended to use a
:ref:`Data bindings via Subject <xml_subjects>`.
If the user needs to access or modify values dynamically, it is recommended to use
:ref:`Data bindings via Subject <xml_subjects>`.
The user can also call these ``..._create()`` functions at any time from application code
to create new components on demand.
to create new Components on demand.
Extending
*********
When a Component is defined as "extending" a Widget, it effectively inherits that
Widget's attributes, and they can be used with that Component.
(See ``<view extends="...">`` in the code examples below.)
.. _component_custom_properties:
.. _component_custom_api:
Custom Properties
*****************
The properties of child elements can be set directly, such as:
The properties of child elements can be adjusted, such as:
.. code-block:: xml
<my_button x="10" width="200"/>
It is also possible to define custom properties in the ``<api>`` tag.
Those properties then can thereafter be referenced in any properties of the children
by using a ``$`` prefix with its name. Example:
However, it's also possible to define custom properties in the ``<api>`` tag.
These properties can then be passed to any properties of the children by
referencing them using ``$``. For example:
.. code-block:: xml
@@ -175,7 +160,7 @@ by using a ``$`` prefix with its name. Example:
</view>
</component>
And it can be used by other Components like this:
And it can be used like:
.. code-block:: xml
@@ -188,22 +173,20 @@ And it can be used by other Components like this:
</view>
</component>
In this setup, the ``btn_text`` property is mandatory, however it can be made optional
by providing a default value like this:
In this setup, the ``btn_text`` property is mandatory. However, it can be made optional
by setting a default value:
.. code-block:: xml
<prop name="btn_text" type="string" default="Title"/>
See :ref:`<api> <xml_api>` for more details, and :ref:`XML Syntax <xml_syntax>` for all the supported types.
See :ref:`<api> <xml_api>` for more details and :ref:`XML Syntax <xml_syntax>` for all the supported types.
Examples
********
The following example demonstrates parameter passing and the use of the
``text`` label property in a Component. Styles and Constants are also shown.
``text`` label property on a Component. Styles and Constants are also shown.
.. code-block:: xml
@@ -241,28 +224,16 @@ The following example demonstrates parameter passing and the use of the
lv_xml_component_register_from_file("A:path/to/h3.xml");
lv_xml_component_register_from_file("A:path/to/red_button.xml");
/* Create a button with "None" text. */
/* Creates a button with "None" text */
lv_xml_create(lv_screen_active(), "red_button", NULL);
/* Use attributes to set the button text. */
/* Use attributes to set the button text */
const char * attrs[] = {
"btn_text", "Click here",
NULL, NULL,
};
lv_xml_create(lv_screen_active(), "red_button", attrs);
Live Example
*************
.. include:: ../../../../../../examples/others/xml/index.rst
API
***
.. API startswith: lv_xml_component_
.. API equals: lv_xml_create
@@ -17,7 +17,6 @@ The supported types are:
- ``opa``
- ``bool``
Usage
*****
@@ -33,10 +32,11 @@ Constants can be used in:
- Style properties
- Widget and Component properties
And they can be used like this:
Constant values can be referenced by ``#constant_name``. For example:
.. code-block:: xml
<styles>
<style name="style1" bg_color="#color1"/>
</styles>
@@ -51,16 +51,13 @@ For example, ``callback="my_callback_1"`` will be exported as:
The ``user_data`` is optional. If omitted, ``NULL`` will be passed.
.. _xml_events_screen:
Screen Load and Create events
*****************************
By using the ``<screen_load_event>`` and ``<screen_create_event>`` tags as a child
of a widget or component, screens can be loaded or created on a trigger (e.g. click).
By using the ``<screen_load_event>`` and ``<screen_create_event>`` tags as children
of a widget or component, screens can be loaded or created on a trigger (e.g., click).
The difference between load and create is that:
@@ -71,8 +68,8 @@ The difference between load and create is that:
Both tags support the following optional attributes:
- ``trigger``: Event code that triggers the action (e.g. ``"clicked"``, ``"long_pressed"``, etc). Default: ``"clicked"``.
- ``anim_type``: Describes how the screen is loaded (e.g. ``"move_right"``, ``"fade_in"``). Default: ``"none"``.
- ``trigger``: Event code that triggers the action (e.g., ``"clicked"``, ``"long_pressed"``, etc.). Default: ``"clicked"``.
- ``anim_type``: Describes how the screen is loaded (e.g., ``"move_right"``, ``"fade_in"``). Default: ``"none"``.
- ``duration``: Length of the animation in milliseconds. Default: ``0``. Only used if ``anim_type`` is not ``"none"``.
- ``delay``: Wait time before loading the screen in milliseconds. Default: ``0``.
@@ -107,7 +104,7 @@ This is a simple example of both load and create:
lv_xml_component_register_from_data("screen1", screen1_xml);
lv_xml_component_register_from_data("screen2", screen2_xml);
/*Create an instance of screen_1 so that it can loaded from screen2.*/
/* Create an instance of screen1 so that it can be loaded from screen2. */
lv_obj_t * screen1 = lv_xml_create(NULL, "screen1", NULL);
lv_screen_load(screen1);
@@ -153,3 +150,4 @@ If ``step`` is **negative**, the subject's value will be decremented.
Only integer ``step`` values are supported now.
**Note:** Only integer subjects are supported by ``<subject_increment>``.
@@ -0,0 +1,20 @@
.. _xml_ui_elements:
===========
UI Elements
===========
.. toctree::
:class: toctree-1-deep
:maxdepth: 2
components
widgets
screens
animations
api
consts
events
preview
styles
view
@@ -16,13 +16,12 @@ These are **not** exported to code and are **not** loaded from XML.
They are used only by the UI |nbsp| Editor to describe the context of the Component.
For example, you might want to:
- Change the background of the Editor's preview to dark.
- Center the Component.
- Set margins.
- Change the size of the preview.
``style_radius`` can be used to make preview rounded.
- change the background of the Editor's preview to dark,
- center the Component,
- set margins,
- change the size of the preview.
``style_radius`` can be used to make the preview rounded.
Usage
*****
@@ -36,7 +35,18 @@ You can think of a ``<preview>`` tag as an ``lv_obj`` where the following proper
It is also possible to define multiple previews, and in the UI |nbsp| Editor, you can
select one of them.
For Screens
-----------
Screens don't support the :ref:`<preview> <xml_preview>` tag because it doesn't make
sense to preview each screen in different resolutions.
As Screens are related to the target hardware in the ``project.xml`` file, multiple
``<display>`` elements can be defined. In the UI |nbsp| Editor, when a Screen is being developed,
the user can select from all the defined displays in the Preview, and the Screen will be shown with
the given resolution and color depth.
This is useful for verifying responsive designs.
Example
*******
@@ -62,3 +72,4 @@ Example
</view>
</component>
@@ -15,34 +15,35 @@ Screens work very similarly to Components. Both can be:
- Loaded from XML
- Contain Widgets and Components as children
Screens have ``<screen>`` as their root element and are used to organize
Screens are wrapped in the ``<screen>`` XML root element and used to organize
the content of the UI.
``<screen>`` elements may contain only the following child elements:
Screens can have only the following child XML tags:
- :ref:`<consts> <xml_consts>`
- :ref:`<styles> <xml_styles>`, and
- :ref:`<styles> <xml_styles>`
- :ref:`<view> <xml_view>`
That is, Screens **cannot** have :ref:`<api> <xml_api>` or :ref:`<preview> <xml_preview>`
elements.
That is, Screens **cannot** have:
- :ref:`<api> <xml_api>`: Screens are always created as they are, with no parameters.
- :ref:`<preview> <xml_preview>`: In LVGL's UI Editor, ``<preview>`` is used to set the style, size, and other parameters of the previewing "screen". For Screens, the
preview options are defined in ``project.xml``. Learn more in :ref:`Screen preview <xml_screen_preview>`
Usage
*****
Each Screen XML file defines a :ref:`Screen <screens>`. The name of the XML file will
be the name of the Screen.
Each XML file describes a :ref:`Screen <screens>`. The name of the XML file will
also be the name of the Screen.
This example illustrates a Screen in XML. In the example, a ``<my_header>``
and a ``<my_main_cont>`` component is used to keep the screen simple.
This example illustrates a screen in XML. In the example, a ``<my_header>``
and a ``<my_main_cont>`` component are used to keep the screen simple.
.. code-block:: xml
<screen>
<consts>
<string name="title" value="Main Menu"/>
<string name="title" value="Main menu"/>
</consts>
<styles>
@@ -62,17 +63,15 @@ and a ``<my_main_cont>`` component is used to keep the screen simple.
</view>
</screen>
Code Export
Code export
***********
When C code is exported from the UI |nbsp| Editor, ``screen_name_gen.c/h`` files are exported,
LVGL's UI Editor can export C code for Screens as well. It generates ``screen_name_gen.c/h`` files,
containing only a single ``lv_obj_t * screen_name_create(void)`` create function.
By using this function, any number of screen instances can be created and loaded as needed.
.. _xml_screen_preview:
Preview
*******
@@ -80,19 +79,17 @@ Preview
Screens don't support the :ref:`<preview> <xml_preview>` tag because it doesn't make
sense to preview each screen in different resolutions.
Since Screens are related to target hardware specified in the ``project.xml`` file, multiple
As Screens are related to the target hardware in the ``project.xml`` file, multiple
``<display>`` elements can be defined. In the UI |nbsp| Editor, when a Screen is being developed,
the user can select from all the defined displays in the Preview, and the Screen will be shown with
the given resolution and color depth.
This is useful for verifying responsive designs.
Events
******
It is very common to load or create Screens from a button-click or other type of event.
It's very common to load or create Screens on a button click or other events.
Both are supported by adding special XML tags as children of Components or Widgets:
@@ -102,15 +99,16 @@ Both are supported by adding special XML tags as children of Components or Widge
<lv_button>
<lv_label text="Click or Long press me"/>
<!-- Load an already created screen named "first".
<!-- Load an already created screen that has the name "first".
Note that here the name of the instance is used,
not the name of the XML file. -->
and not the name of the XML file. -->
<screen_load_event screen="first" trigger="clicked" anim_type="fade"/>
<!-- Create an instance of "about" Screen and load it.
Note that the name of the XML file is used. -->
<!-- Create an instance of "about" and load it.
Note that here the name of the XML file is used. -->
<screen_create_event screen="about" trigger="long_pressed"/>
</lv_button>
</view>
Learn more on the :ref:`XML Events <xml_events_screen>` page.
@@ -9,7 +9,6 @@ Overview
In XML files, both style sheets (:cpp:expr:`lv_style_t`) and local styles can be used.
Style Sheets
************
@@ -22,7 +21,8 @@ In the ``<styles>`` section, styles and their properties can be defined like thi
border_width="2px"
border_color="0xff0000"/>
Styles can be referenced like this in the ``<view>``\ :
Styles can be referenced like this in the ``<view>``:
.. code-block:: xml
@@ -30,22 +30,53 @@ Styles can be referenced like this in the ``<view>``\ :
<lv_slider value="20">
<style name="main"/>
<style name="red" selector="knob"/>
<style name="blue" selector="knob focused"/>
<style name="blue" selector="knob|focused"/>
</lv_slider>
</view>
As shown in the example, parts and states can be set as ``selector``\ .
As shown in the example, parts and states can be set using ``selector``.
Style binding
*************
Instead of directly adding styles to the UI elements it's also possible to add them conditionally
when a :ref:`Subject <observer_how_to_use>`\ 's value equals to a reference value.
It works at runtime and it's a great way to check the appearace or event the layout based on a condition.
A typical use case is the light/dark theme switching. It requires
- a subject such as ``dark_theme_on``
- some default style that are added normally with the ``<style>`` tag
- some dark styles to check the required colors to dark
Here is an example:
.. code-block:: xml
<component>
<styles>
<style name="style_base" bg_color="0xeee" text_color="0x111" radius="20" />
<style name="style_dark" bg_color="0x333" text_color="0xeee" radius="20" />
</styles>
<view extends="lv_button">
<style name="style_base" />
<bind_style name="style_dark" subject="dark_theme_on" ref_value="1"/>
<lv_label text="Apply"/>
</view>
</component>
Local Styles
************
Local styles can be used directly in a Widget, for example:
Local styles can be used directly, for example:
.. code-block:: xml
<lv_label style_bg_opa="200" style_bg_opa:disabled="100"/>
<lv_label style_bg_opa="200" style_bg_color="0x123456"/>
Selectors are not supported for local style properties yet.
Gradients
*********
@@ -65,11 +96,12 @@ or
<lv_button style_bg_grad="grad1"/>
Note that gradients are not supported in LVGL's UI Editor yet.
Horizontal or Vertical Gradient
-------------------------------
To define a simple ``<horizontal>`` or ``<vertical>`` gradients:
To define a simple ``<horizontal>`` or ``<vertical>`` gradient:
.. code-block:: xml
@@ -80,7 +112,6 @@ To define a simple ``<horizontal>`` or ``<vertical>`` gradients:
</horizontal>
</gradients>
Linear Gradient
---------------
@@ -95,7 +126,6 @@ To define a skewed gradient from two points:
</linear>
</gradients>
Radial Gradient
---------------
@@ -110,7 +140,6 @@ To define a radial gradient:
</radial>
</gradients>
Conical Gradient
----------------
@@ -124,3 +153,4 @@ To define a conical gradient:
<stop color="#00ff00" opa="100%"/>
</conical>
</gradients>
@@ -7,15 +7,15 @@ View
Overview
********
The ``<view>`` tag can be used as a child of the following tags:
The ``<view>`` tag can be used in:
- ``<component>``
- ``<widget>``
- ``<screen>``
- ``<test>``
- ``<component>``\ s
- ``<widget>``\ s
- ``<screen>``\ s
- ``<test>``\ s
to describe how these items look. Inside ``<view>``, children can be added in a nested way
using already defined ``widget``\ s and ``component``\ s. For example:
using already defined ``widget``\s and ``component``\s. For example:
.. code-block:: xml
@@ -26,8 +26,6 @@ using already defined ``widget``\ s and ``component``\ s. For example:
</lv_button>
</view>
Extends
*******
@@ -45,9 +43,10 @@ By adding properties to the ``<view>``, the extended type can be customized. For
<lv_label bind_text="subject_1"/>
</view>
Rules for the allowed values of ``extends``:
Rules for allowed values of ``extends``:
- ``<component>``: can extend both ``<widget>``\ s and ``<component>``\ s
- ``<widget>``: can extend only ``<widget>``\ s
- ``<screen>``: cannot extend anything
- ``<test>``: can extend ``<widget>``, ``<component>``, or ``<screen>``
@@ -10,88 +10,61 @@ Overview
.. |nbsp| unicode:: U+000A0 .. NO-BREAK SPACE
:trim:
Besides components and Screens, Widgets are the other main building blocks of UIs.
XML files defining Widgets have ``<widget>`` as their XML root element.
Besides Components and Screens, Widgets are the other main building blocks of UIs.
``<widget>`` elements may contain the following child elements:
The XML file of a Widget is wrapped in a ``<widget>`` XML root element.
``<widget>``\s support the following child XML tags:
- :ref:`<consts> <xml_consts>`
- :ref:`<api> <xml_api>`
- :ref:`<styles> <xml_styles>`, and
- :ref:`<styles> <xml_styles>`
- :ref:`<view> <xml_view>`
- :ref:`<previews> <xml_preview>`
Just like Components, Widgets can also be the children of other Widgets and Components.
The main difference is that Widgets are written in C and compiled into the
application. This means, unlike Components, Widgets can contain custom C code. For
example, when a property is set, any complex C code can run to set that value.
To connect the C code to XML, XML parser functions need to be implemented and registered. It is
pretty simple since LVGL already provides all the helper functions and the required libraries. Also there
are `many XML parser examples here <https://github.com/lvgl/lvgl/tree/master/src/others/xml/parsers>`__.
Just like Components, Widgets can also be children of other Widgets and Components.
Note that Widgets cannot be loaded from XML directly, but it's possible to write and register
simple XML parsers for Widgets. When a Widget is referenced in a Component's or Screen's XML,
the XML parser will be called to map the properties to C function calls.
LVGL already provides all the helper functions and required libraries. There are also
`many XML parser examples here <https://github.com/lvgl/lvgl/tree/master/src/others/xml/parsers>`__
for the built-in LVGL Widgets.
Built-in Widgets
****************
LVGL already has XML parsers for LVGL's built-in widgets (e.g. :ref:`lv_slider`,
:ref:`lv_label`, :ref:`lv_chart`, etc.), which makes them available in XML.
The built-in LVGL widgets (e.g., :ref:`lv_slider`, :ref:`lv_label`, :ref:`lv_chart`, etc.) already
have XML parsers and are therefore available in XML.
Example:
For example:
.. code-block:: xml
<view>
<lv_label x="10" text="Hello"/>
</view>
<component>
<view>
<lv_label x="10" text="Hello"/>
</view>
</component>
The built-in widgets are:
The built-in widgets consist of:
- pure C code
(e.g. `lv_slider.c <https://github.com/lvgl/lvgl/tree/master/src/widgets/slider/lv_slider.c>`__)
- an XML file to define only the API
(e.g. `lv_slider.xml <https://github.com/lvgl/lvgl/blob/master/xmls/lv_slider.xml>`__)
(used only in the UI |nbsp| Editor to validate and autocomplete properties)
- an XML parser C file to map the XML attributes to C functions.
(e.g. `lv_xml_slider_parser.c <https://github.com/lvgl/lvgl/blob/master/src/others/xml/parsers/lv_xml_slider_parser.c>`__)
Creating New Widgets
********************
It is possible to create new Widgets that can be treated in the same way as built-in
LVGL Widgets.
However, using the UI |nbsp| Editor it's much faster and simpler. When an XML file is created and
the ``<widget>`` root element is used, the following .C/.H files are generated automatically:
:<widget_name>_gen.h: Contains the generated API implementation of the widget
(overwritten on each code export).
:<widget_name>_private_gen.h: Contains private API and the data for the widget
(overwritten on each code export).
:<widget_name>_gen.c: Contains the internals of the Widget, e.g. constructor with the children,
destructors, event handler, etc. (overwritten on each code export).
:<widget_name>.h: Includes ``<widget_name>_gen.h`` and allows the user to
define custom APIs. Only a skeleton is exported once.
:<widget_name>.c: Contains hooks from ``<widget_name>_gen.c`` and allows
the user to write custom code. Only a skeleton is
exported once.
:<widget_name>_xml_parser.c: Processes the XML strings and calls the required
functions according to the set attributes. Only a
skeleton is exported once.
Usage
*****
- Pure C code
(e.g., `lv_slider.c <https://github.com/lvgl/lvgl/tree/master/src/widgets/slider/lv_slider.c>`__)
- An XML file to define only the API
(e.g., `lv_slider.xml <https://github.com/lvgl/lvgl/blob/master/xmls/lv_slider.xml>`__),
used only in the UI |nbsp| Editor to validate and autocomplete properties
- An XML parser C file to map the XML attributes to C functions
(e.g., `lv_xml_slider_parser.c <https://github.com/lvgl/lvgl/blob/master/src/others/xml/parsers/lv_xml_slider_parser.c>`__)
XML Parser
----------
**********
To make the Widgets accessible from XML, an XML parser needs to be created and
Write a parser
--------------
To make Widgets accessible from XML, an XML parser needs to be created and
registered for each Widget. The XML parser for the label Widget looks like this:
.. code-block:: c
@@ -117,7 +90,7 @@ registered for each Widget. The XML parser for the label Widget looks like this:
if(lv_streq("text", name)) lv_label_set_text(obj, value);
if(lv_streq("long_mode", name)) lv_label_set_long_mode(obj, long_mode_text_to_enum(value));
/* Process more props here */
/* Process more props here ... */
}
}
@@ -131,7 +104,13 @@ registered for each Widget. The XML parser for the label Widget looks like this:
return 0; /* Return 0 in the absence of a better option. */
}
A Widget XML processor can be registered like this:
By using lines like ``if(lv_streq("text", name)) lv_label_set_text(obj, value);``,
any ``set`` function can be mapped to XML properties.
Register a widget
-----------------
A Widget XML processor can be registered as follows:
.. code-block:: c
@@ -147,9 +126,9 @@ After registration, a Widget can be created like this from C code:
NULL, NULL,
};
lv_xml_create(lv_screen_active(), "lv_label", attrs);
lv_obj_t * label = lv_xml_create(lv_screen_active(), "lv_label", attrs);
And in XML it can be used like this:
And in XML, it can be used like this:
.. code-block:: xml
@@ -157,18 +136,43 @@ And in XML it can be used like this:
<lv_label width="100" text="I'm a label!" wrap="scroll"/>
</view>
Usage in LVGL's UI Editor
*************************
New widget
----------
It's possible to create new widgets by writing C code manually (the same way as built-in LVGL widgets are created),
however, using the UI |nbsp| Editor is much faster and simpler.
When an XML file is created and the ``<widget>`` root element is used, the following .C/.H files are generated automatically:
:<widget_name>_gen.h: Contains the generated API implementation of the Widget
(overwritten on each code export)
:<widget_name>_private_gen.h: Contains private API and data for the Widget
(overwritten on each code export)
:<widget_name>_gen.c: Contains the internals of the Widget, e.g., constructor with children,
destructor, event handler, etc. (overwritten on each code export)
:<widget_name>.h: Includes ``<widget_name>_gen.h`` and allows the user to
define custom APIs. Only a skeleton is exported once
:<widget_name>.c: Contains hooks from ``<widget_name>_gen.c`` and allows
the user to write custom code. Only a skeleton is
exported once
:<widget_name>_xml_parser.c: Processes the XML strings and calls the required
functions according to the set attributes. Only a
skeleton is exported once
Adding Custom Code
------------------
``<widget_name>.c`` contains three hooks:
- **Constructor hook**: Called when the Widget and all its children are created. Any
modifications to the children can be done here.
- **Destructor hook**: Called when the Widget is deleted. All manually allocated
memory needs to be freed here.
- **Constructor hook**: Called when the Widget and all its children are created.
Any modifications can be done on the children here.
- **Destructor hook**: Called when the Widget is deleted.
All manually allocated memory needs to be freed here.
- **Event hook**: Called at the beginning of the Widget's event callback to perform
any custom actions.
any custom action.
In this C file, the ``set`` functions for each API ``<prop>`` also need to be
implemented. The declaration of these functions is automatically exported in
@@ -176,23 +180,14 @@ implemented. The declaration of these functions is automatically exported in
Besides these, any custom code and functions can be freely implemented in this file.
Elements
--------
Elements are internal parts of the widget that can be accessed and/or created dynamically.
For example, tabs of a tabview, list of a dropdown, series of a chart, etc..
Elements are internal parts of the Widget that can be accessed and/or created dynamically.
For example: tabs of a tabview, list of a dropdown, series of a chart, etc.
Just like any other Widget API properties, Elements also can be defined within the
``<api>`` element of the Widget's XML.
Just like any other Widget API properties, Elements can also be defined in the ``<api>``
tag of the Widget's XML.
Learn more about Elements under the :ref:`<api> element documentation <xml_widget_element>`.
Learn more about Elements in the documentation page for :ref:`<api> <xml_widget_element>`.
API
***
.. API startswith: lv_xml_widget_
.. API equals: lv_xml_create