docs(xml): reorganize and extend the XML docs

This commit is contained in:
Gabor Kiss-Vamosi
2025-02-06 18:01:50 +01:00
parent 299e31b9ed
commit ad8a9d9587
27 changed files with 1559 additions and 131 deletions

View File

@@ -0,0 +1,6 @@
.. _xml_animation:
==========
Animations
==========

View File

@@ -0,0 +1,275 @@
.. _xml_api:
===
API
===
The ``<api>`` tag can be used in ``<widget>``s and ``<components>``, although each supports slightly different features.
Properties
**********
Inside ``<prop>`` elements, ``<param>`` elements can be defined to describe the arguments.
For **widgets**, all properties are optional.
If a property is not set on an instance of a widget, it simply won't be applied,
and the created widget's default value will be used (e.g., ``text`` for a label's text).
For **components**, all properties are mandatory; however, default values can be defined
to be used when a property is not set.
If a property has only one parameter (which is usually the case), a shorthand can be applied as shown below.
For example:
.. code-block:: xml
<api>
<prop name="range" default="0 100" help="Set the range.">
<param name="range_min" type="int" help="Sets the minimum value."/>
<param name="range_max" type="int" help="Sets the maximum value."/>
</prop>
<prop name="title" type="string" help="The title of the slider"/>
</api>
When a property is used, all parameters are set as a single attribute value. For example:
.. code-block:: xml
<my_slider range="-100 100" title="Room 1"/>
For **widgets**, each property corresponds to a setter function.
The ``name`` in ``<prop>`` is used to build the name of the setter function like this:
.. code-block:: c
<widget_name>_set_<prop_name>(lv_obj_t * obj, <param1_type> <param1_name>, <param2_type> <param2_name>, ...);
For **components**, the exported code contains only a single ``create`` function
to which all the properties need to be passed:
.. code-block:: c
<component_name>_create(lv_obj_t * parent, <param1_type> <param1_name>, <param2_type> <param2_name>, ...);
``<prop>`` elements have an optional ``<postponed>`` boolean attribute.
By default, it is ``false``, but if set to ``true``, the given property will be applied after all children are created.
A practical example is setting the current tab of a tab view, which cannot be set before the tabs are created.
This feature is not supported yet.
``<enumdef>``
************
Can be used only for widgets.
Used to define new enum types for a given widget.
It should contain ``<enum>`` elements to define the possible options.
Example:
.. code-block:: xml
<!-- my_widget.xml -->
<api>
<enumdef name="my_widget_mode" help="Possible modes">
<enum name="normal" help="Normal mode" value="0x10"/>
<enum name="inverted" help="Inverted mode"/>
</enumdef>
<prop name="mode" help="Set the widget mode">
<param name="mode" type="enum:my_widget_mode"/>
</prop>
</api>
Note that the enum values are not important because:
1. When the code is exported, the enum names will be used, and the compiler will substitute the values.
2. When loaded from XML, the widget's XML parser should convert the enum names to C enum fields.
``<element>``
*************
Also applies only to widgets.
Elements are used to describe sub-widgets or internal parts of widgets.
Examples include the list of a dropdown, the tabs of a tab view, or the series of a chart.
Elements can have ``<arg>`` and ``<prop>`` definitions. ``<arg>`` elements are mandatory (default values are supported)
as they are used to create the element, whereas ``<prop>`` elements are optional as they are mapped to setter functions.
An element in a ``<view>`` can be referenced like this: ``<widget_name-element_name>``.
The widget name and the element name are separated by a ``-``, so ``-`` is not allowed in widget and
element names (only ``_`` can be used).
Example:
.. code-block:: xml
<my_chart-super_series color="0xff0000"/>
An important attribute of elements is ``access``. The possible values are:
- ``add``: Create any number of elements dynamically (e.g., chart series).
- ``get``: Get a pointer to an implicitly created widget or any data (e.g., list of the dropdown).
- ``set``: Select specific parts of the widget with indexes (e.g., table cells).
Elements with ``access="add"`` or ``access="get"`` can have a custom data type defined using ``type="my_data"``.
In these cases, no children can be added. If the ``type`` is ``lv_obj``, the element can have children.
It is not yet possible to describe the ``<view>`` of elements in XML; only the API can be defined.
The actual implementation needs to be done in C.
``access="add"``
----------------
The element is explicitly created with an ``add`` function, e.g., ``lv_tabview_add_tab(obj, "Title");``.
``<arg>`` elements defined directly inside the ``<element>`` are passed to the ``add`` function as arguments.
Example:
.. code-block:: xml
<!-- my_widget.xml -->
<api>
<element name="indicator" type="obj" help="The indicator of my_widget" access="add">
<arg name="color" type="color" help="Help for color"/>
<arg name="max_value" type="int" help="Help for max_value"/>
<prop name="value" help="Set a new value for the indicator">
<param name="value" type="int" help="Help for value"/>
</prop>
</element>
</api>
<view extends="obj">
<button name="btn1"/>
</view>
In a view it can be used like this:
.. code-block:: xml
<!-- complex_widget.xml -->
<view>
<lv_label text="Title"
<my_widget width="100px" y="40px">
<my_widget-indicator name="indic1" color="0xff0000" max_value="120" value="30"/>
</my_widget>
</view>
From the API definition the following functions are generated:
.. code-block:: c
lv_obj_t * my_widget_add_indicator(lv_obj_t * parent, lv_color_t color, int32_t max_value);
void my_widget_set_indicator_value(lv_obj_t * obj, int32_t value);
And this is the related C file where the indicator is created:
.. code-block:: c
lv_obj_t * indic1 = my_widget_add_indicator(parent, color, max_value);
lv_my_widget_set_indicator_value(indic1, value);
``access="get"``
----------------
If the element is created internally and implicitly, it can be retrieved with a function like ``lv_dropdown_get_list(obj);``.
``<arg>`` elements are passed to the ``get`` function as arguments.
Example:
.. code-block:: xml
<!-- my_widget.xml -->
<api>
<element name="control_button" type="obj" help="A control button of my_widget" access="get">
<arg name="index" type="int" help="Zero-based index of the control button"/>
<prop name="title">
<param name="text" type="string"/>
</prop>
</element>
</api>
In a view:
.. code-block:: xml
<!-- complex_widget.xml -->
<view>
<my_widget width="100px">
<my_widget-control_button name="btn1" index="3" title="Hello"/>
</my_widget>
</view>
Generated API:
.. code-block:: c
lv_obj_t * my_widget_get_control_button(lv_obj_t * parent, int32_t index);
void my_widget_set_control_button_title(lv_obj_t * obj, const char * text);
And this is a C file where the control button is retrieved:
.. code-block:: c
lv_obj_t * btn1 = lvmy_widget_get_control_button(parent, index);
my_widget_set_control_button_title(btn1, text);
``access="set"``
----------------
Used when elements are created automatically but need to be selected in API calls,
e.g., ``lv_table_set_cell_value(table, row, col, "text");``.
Example:
.. code-block:: xml
<!-- my_widget.xml -->
<api>
<element name="item" type="obj" help="An item on my_widget" access="set">
<arg name="index" type="int" help="The zero-based index of the item"/>
<prop name="icon" help="Set the icon of an item">
<param name="icon_src" type="img_src" help="The image to set as an icon."/>
</prop>
<prop name="color" help="Set the color">
<param name="color" type="color" help="The color to set for the item."/>
</prop>
</element>
</api>
In a view:
.. code-block:: xml
<!-- complex_widget.xml -->
<view>
<my_widget width="100px">
<my_widget-item index="3" icon_src="image1" color="0xff0000"/>
</my_widget>
</view>
This is the generated header file:
.. code-block:: c
void my_widget_set_item_icon(lv_obj_t * parent, int32_t index, const void * icon_src);
void my_widget_set_item_color(lv_obj_t * parent, int32_t index, lv_color_t color);
And this is the related C file where the item properties are set:
.. code-block:: c
my_widget_set_item_icon(parent, index, image1);
my_widget_set_item_color(parent, index, color);

View File

@@ -0,0 +1,147 @@
.. _xml_component_library:
=================
Component Library
=================
Overview
********
The collection of Components, Widgets, Screens, Images, Fonts, etc., is called a component library.
A component library can be fully self-sufficient, but it can also reference data from other component libraries.
LVGL itself is a component library that supplies the built-in widgets, types, etc., so typically, component libraries use
at least the core LVGL data. You can find the XML files that describe the LVGL widgets `here <https://github.com/lvgl/lvgl/tree/master/xmls>`_.
A project is also a component library, where the screens, components, and widgets of the project are implemented.
In light of that, a project can contain multiple component libraries (its own project component library, LVGL, and possibly others).
Structure
*********
A typical structure for a component library looks like this:
- ``name_of_the_component_library``
- ``globals.xml``
- ``component``
- ``component1.xml``
- ``component2.xml``
- ``other_folders``
- ``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``
Visibility
**********
A component library can use images, fonts, components, widgets, etc., from other component libraries.
It is the user's responsibility to avoid naming conflicts by prefixing names. For example, all
data belonging to the LVGL core component library is prefixed by ``lv_`` (e.g., ``lv_label``, ``lv_montserrat_22``).
A custom component can be prefixed with ``watch_``, ``small_``, ``light_``, or anything else that the developer finds appropriate.
LVGL's UI editor will show an error if there is a naming conflict.
globals.xml
***********
A ``globals.xml`` file should be created in 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>``: Only for ``<enumdefs>``.
- ``<subjects>``: List of subjects. 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.
``globals.xml`` files cannot be nested, meaning that there cannot be another ``globals.xml`` file in a subfolder.
From each ``globals.xml`` file, an ``<config.name>.h`` file is generated,
which is included in all generated header files — not only in the subfolders 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.
Variants
--------
``<const_variant>`` can be used by constants to create variants that can be selected at compile time.
This is useful for selecting a different display size, color scheme, etc.
``<style_variant>`` can be used by styles only, to modify styles at runtime.
To select the current style variant, an integer subject ``<style_variant.name>_variant`` is created.
Styles can subscribe to this, and the style properties can be changed according to the
selected variant.
In ``globals.xml``, the possible variants should be described.
Example
-------
A ``globals.xml`` file of a component library can look like this:
.. code-block:: xml
<globals>
<config name="mylib" help="This is my great component library"/>
<const_variants>
<const_variant name="size" help="Select the size">
<case name="small" help="Assets for 320x240 screen"/>
<case name="large" help="Assets for 1280x768 screen"/>
</const_variant>
</const_variants>
<style_variants>
<style_variant name="color" help="Select the color of the UI">
<case name="red" help="Select a red theme"/>
<case name="blue" help="Select a blue theme"/>
</style_variant>
</style_variants>
<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="card" bg_color="0xeee" radius="#small_unit" padding="12px"/>
</styles>
<images>
<file name="arrow_left" src="A:/images/arrow_left.png"/>
</images>
<fonts>
<tinyttf name="big" src="A:/fonts/arial.ttf" size="28"/>
</fonts>
</globals>

View File

@@ -0,0 +1,136 @@
.. _xml_components:
==========
Components
==========
Overview
--------
``<component>`` can have ``<consts>``, ``<api>``, ``<styles>``, and ``<view>`` tags inside.
Unlike widgets (which are always compiled into the application), components can either:
1. Be loaded at runtime from XML.
2. Be exported to C code.
Usage from exported code
------------------------
From each component XML file, a C and H file is exported with a single function inside:
.. code-block:: c
lv_obj_t * component_name_create(lv_obj_t * parent, ...api properties...);
When a component is used in another components 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.
If the user needs to access or modify values dynamically, it is recommended to use a :ref:`subject <observer>`.
The user can also call these ``_create_`` functions at any time from the application code.
Usage from XML
--------------
Registration
^^^^^^^^^^^^
Once a component is created (e.g., ``my_button``), it can be registered by calling either:
- ``lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml");``
- ``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.
This is required to make LVGL recognize the component by name.
When loaded from a file, the file name is used as the component name.
Instantiation
^^^^^^^^^^^^^
After registration, a new instance of any registered component can be created with:
.. code-block:: c
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 manually created widget.
The last parameter can be ``NULL`` or an attribute list, like this:
.. code-block:: c
/* Can be local */
char * my_button_attrs[] = {
"x", "10",
"y", "-10",
"align", "bottom_left",
"btn_text", "New button",
NULL, NULL,
};
lv_obj_t * btn1 = lv_xml_create(lv_screen_active(), "my_button", my_button_attrs);
Parameters
----------
The properties of child elements can be adjusted, such as:
.. code-block:: xml
<lv_label x="10" text="Hello"/>
These parameters can be set to a fixed value. However, with the help of ``<prop>`` elements inside the ``<api>`` tag,
they can also be passed when an instance is created. Only the whole property can be passed, but not individual ``<param>`` elements.
Additionally, when a component is created, it can use the extended widget's attributes
(see ``<view extends="...">``).
This means that components inherit the API of the extended widget as well.
The following example demonstrates parameter passing and the use of the
``text`` label property on a component:
.. code-block:: xml
<!-- h3.xml -->
<component>
<view extends="lv_label"/>
</component>
.. code-block:: xml
<!-- red_button.xml -->
<component>
<api>
<prop type="string" name="btn_text" default="None"/>
</api>
<view extends="lv_button" style_radius="0" style_bg_color="0xff0000">
<h3 text="Some text"/>
<h3 text="$btn_text" y="40"/>
</view>
</component>
.. code-block:: c
lv_xml_component_register_from_file("A:path/to/h3.xml");
lv_xml_component_register_from_file("A:path/to/red_button.xml");
/* Creates a button with "None" text */
lv_xml_create(lv_screen_active(), "red_button", NULL);
/* 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);
Example
*******
.. include:: ../../examples/others/xml/index.rst
API
***

View File

@@ -0,0 +1,69 @@
.. _xml_consts:
=========
Constants
=========
Overview
********
Constants can be defined to replace any value with a selected type or to be used as special values.
The supported types are:
- ``color``
- ``px``
- ``percentage``
- ``string``
- ``opa``
- ``bool``
Usage
*****
.. code-block:: xml
<consts>
<color name="color1" value="0xff0000" help="Primary color"/>
<px name="pad_xs" value="8" help="Small padding"/>
</consts>
Constants can be used in:
- Style properties
- Widget and component properties
And they can be used like this:
.. code-block:: xml
<styles>
<style name="style1" bg_color="#color1"/>
</styles>
Variants
********
Constants support a ``<variant>`` attribute to change the constants at compile time. For example:
.. code-block:: xml
<consts>
<px name="pad" value="8" help="General padding">
<variant name="size" case="small" value="4"/>
<variant name="size" case="large" value="12"/>
</px>
</consts>
From which the following C code can be exported:
.. code-block:: c
#if SIZE == SMALL
#define PAD 4
#elif SIZE == LARGE
#define PAD 12
#else
#define PAD 8
#endif
Where ``SMALL`` and ``LARGE`` are just preprocessor defines with incremental values.

View File

@@ -0,0 +1,7 @@
.. _xml_events:
======
Events
======
TODO

View File

@@ -0,0 +1,90 @@
.. _xml_fonts:
=====
Fonts
=====
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 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 ``tinyttf 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.
- ``tinyttf``:
- 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.
In :cpp:expr:`lv_style_set_text_font(&style1, <font_name>)`, the created font is referenced.
Constants
---------
Constants can also be used with fonts.
.. code-block:: xml
<consts>
<int name="font_size" value="32">
<variant name="size" case="small" value="24"/>
</int>
</consts>
<fonts>
<bin name="medium" src_path="file.ttf" range="0x20-0x7f" symbols="°" size="#font_size"/>
</fonts>
Default Font
------------
``"lv_font_default"`` can be used to access ``LV_FONT_DEFAULT``. Other built-in fonts are not exposed by default.

View File

@@ -0,0 +1,78 @@
.. _xml_images:
======
Images
======
Overview
********
An ``<images>`` section can be added to ``globals.xml`` files.
Later, it might also be supported in components and widgets to define local images and keep the global space cleaner.
This ``<images>`` section describes how to map images with names.
Only ``<file>`` is currently supported, and ``<convert>`` is not yet implemented.
Usage
*****
.. code-block:: xml
<images>
<file name="avatar" src_path="avatar1.png">
<convert path="raw/avatar.svg" width="100px" color_format="L8"/>
</file>
<data name="logo" src_path="logo1.png">
<convert path="https://foo.com/image.png" width="50%" height="80%"
color_format="RGB565" memory="RAM2"/>
</data>
</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:expr:`lv_image_dsc_t` pointers are assigned to that variable.
In :cpp:expr:`lv_image_set_src(image, <image_name>)` is used
instead of the path or :cpp:expr:`lv_image_dsc_t` pointer directly.
For simplicity, in the UI Editor preview, images are always loaded as files.
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 creates 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"/>
Constants
---------
Constants can be used with images as well.
.. code-block:: xml
<consts>
<int name="icon_size" value="32">
<variant name="size" case="small" value="16"/>
</int>
</consts>
<images>
<data name="icon_apply" src_path="apply.png">
<convert path="raw/apply.png" width="#icon_size"/>
</data>
</images>

View File

@@ -0,0 +1,29 @@
.. _others:
================
Other Components
================
.. toctree::
:maxdepth: 1
intro
component_library
project
syntax
components
screens
widgets
preview
api
styles
consts
view
fonts
images
events
subjects
animations

View File

@@ -0,0 +1,178 @@
.. _xml_intro:
============
Introduction
============
Overview
********
LVGL is capable of loading UI elements written in XML. The XML file can be written by hand, but
it's highly recommended to use LVGL's UI Editor to write the XML files. The UI Editor provides
features like:
- Instant preview the XML files
- Autocomplete and Syntax highlight
- Online preview for collaboration and testing
- Figma integration to easily reimplement the designs
``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.
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) to change the application build.
- 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 scripts.
- XML can be used to generate LVGL code in any language.
- XML helps to separate the view from the logic.
Currently supported features:
- Load XML components at runtime from file or data
- Nest components and widgets any deep
- Dynamically create instances of XML components in C
- Register images and font that can be accessed by name later in the XMLs (only from file, no C file is generated for image and fonts)
- Constants are working for widget and style properties
- Parameters can be defined and passed and used for components
- Most of the built-in widgets, even the complex ones (``label``, ``slider``, ``bar``, ``button``, ``chart``, ``scale``, ``button matrix``, ``table``, etc.)
- Style sheets and local styles that can be assigned to parts and states supporting almost all style properties
Limitations:
- Screens are not supported yet (only components)
- Events are not supported yet.
- Animations are not supported yet.
- Subjects are not supported yet.
- The documentation is not complete yet.
Concept
*******
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.
For example, a company can have a component library for the basic widgets for all its products
(smart home, smart watch, smart oven, etc.), and create other industry-specific libraries
(smart home-specific, smart watch-specific, etc.) containing only a few extra widgets.
These component libraries are independent, can be reused across many products, and can be freely versioned and managed.
You can imagine a component library as a collection of XML files, 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 just fix it and push it back to the git
repository so that other projects can pull it.
The built-in widgets of LVGL are also considered a ``component library`` which is always available.
Widgets, Components, and Screens
********************************
It's important to distinguish between ``widgets`` and ``components``:
**Widgets** are the core building blocks of the UI and are not meant to be loaded at runtime
but rather compiled into the application. The main characteristics of widgets are:
- In XML, they start with a ``<widget>`` root element.
- Similar to LVGL's built-in widgets.
- Built from ``lv_obj_class``-es.
- Have custom and complex logic inside.
- Cannot be loaded from XML at runtime because the custom code cannot be loaded.
- Have a large API with ``set/get/add`` functions.
- Support "internal widgets" (e.g., ``tabview``'s tabs, ``dropdown``'s list).
Any handwritten widget can be accessed from XML by:
1. Defining its API in an XML file.
2. Writing and registering an XML parser for it. See some examples here.
**Components** are built from other components and widgets and can be loaded at runtime.
The main characteristics of components are:
- In XML, they start with a ``<component>`` root element.
- Built in XML only and cannot have custom C code.
- Can be loaded from XML at runtime as they describe only the visuals.
- Built from widgets or other components.
- Can be used for styling widgets.
- Can contain widgets or other components.
- Can have a simple API to pass properties to the children (e.g., ``btn_text`` to label's text).
Regardless of whether the XML was written manually or by the UI Editor, the XMLs of the 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, so that it can create components accordingly.
**Screens** are similar to components:
- In XML, they start with a ``<screen>`` root element.
- Built from widgets or other components to describe the screen.
- Can be loaded from XML at runtime as they describe only the visuals.
- Do not have an API.
- Can be referenced in screen load events.
Syntax teaser
*************
Each widget or component XML file describes a single widget or component.
The root element for widgets, components, and screens are ``<widget>``, ``<component>``, and ``<screen>`` respectively.
Other than that, the other XML elements inside are almost identical.
This is the high-level overview of the most important XML tags inside these root elements:
- ``<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.
- ``<consts>``: Specifies constants (local to the widget or component) for colors, sizes, and other values.
Constant values can be referenced by ``#``.
- ``<styles>``: Describes styles (``lv_style_t``) that can be referenced by widgets and components later.
- ``<view>``: Specifies the appearance of the widget or component by describing the
children and their properties.
This is a simple example illustrating how an LVGL XML component looks like.
Note that only the basic features are shown here.
.. code-block:: xml
<component>
<consts>
<px name="size" value="100"/>
<color name="orange" value="0xffa020"/>
</consts>
<api>
<prop name="btn_text" default="Apply" type="string"/>
</api>
<styles>
<style name="blue" bg_color="0x0000ff" radius="2"/>
<style name="red" bg_color="0xff0000"/>
</styles>
<view extends="lv_button" width="#size" styles="blue red:pressed">
<my_h3 text="$btn_text" align="center" color="#orange" style_text_color:checked="0x00ff00"/>
</view>
</component>
Usage teaser
************
LVGL's UI Editor can be used in two different ways.
Export C and H files
--------------------
The widgets, components, images, fonts, etc., can be converted to C/H files
with plain LVGL code. The exported code works the same way as if it was written by the user.
In this case, the XML files are not required anymore. The XML files were used only during
editing/implementing the widgets and components to save recompilation time and
optionally leverage other useful Editor features.
Load the UI from XML
--------------------
Although the widgets' code always needs to be exported in C and compiled into the
application (just like the built-in LVGL widgets are also part of the application), the components'
XML can be loaded and any number of instances can be created at runtime. In the simplest case,
a component can be registered with ``lv_xml_component_register_from_file(path)`` and
an instance can be created with ``lv_obj_t * obj = lv_xml_create(parent, "my_button", NULL);``.

View File

@@ -0,0 +1,40 @@
.. _xml_preview:
=======
Preview
=======
Overview
********
In ``<component>`` and ``<widget>``, it is possible to define ``<preview>`` tags.
These are **not** exported to code and are **not** loaded from XML.
They are used only by the UI 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.
Usage
*****
You can think of a ``<preview>`` tag as an ``lv_obj`` where the following properties can be used:
- ``width``, ``height``
- Any local style properties, for example, ``style_bg_color="0x333"``
- ``flex`` and ``flex_flow``
It is also possible to define multiple previews, and in the UI Editor, you can select one of them.
Example
*******
.. code-block:: xml
<previews>
<preview name="small_dark" width="200" height="100" style_bg_color="0x333" style_pad_all="32"/>
<preview name="centered" width="200" height="100" flex="row center"/>
<preview name="large_light" width="1980" height="1080" style_bg_color="0xeeeeee"/>
</previews>

View File

@@ -0,0 +1,47 @@
.. _xml_project:
=======
Project
=======
Overview
********
A single ``project.xml`` file should be created for each project where the following content is specified:
- ``<folders>``: Specifies the path to component libraries. LVGL's base widgets are always loaded automatically.
- ``<targets>``: Describes various hardware configurations, allowing the UI Editor to check if the UI is out of resources and to
select different previews for each screen according to the specified displays.
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>
<renesas-RA8D1-EK gpu="true"/>
<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>

View File

@@ -0,0 +1,53 @@
.. _xml_screens:
=======
Screens
=======
Overview
********
Screens work very similarly to components. Both can be:
- Loaded from XML
- Contain widgets and components as children
- Have ``<styles>``
- Have ``<consts>``
- Have a ``<view>``
However, screens **cannot** have an ``<api>``.
Usage
*****
Each XML file describes a screen. The name of the XML file will also be the name of the screen.
In the ``project.xml`` file, multiple ``<display>`` elements can be defined. In the UI 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
*******
.. code-block:: xml
<screen>
<consts>
<string name="title" value="Main menu"/>
</consts>
<styles>
<style name="dark" bg_color="0x333"/>
</styles>
<view>
<header label="#title"/>
<selector_container styles="dark">
<button text="Weather" icon="cloudy"/>
<button text="Messages" icon="envelope"/>
<button text="Settings" icon="cogwheel"/>
<button text="About" icon="questionmark"/>
</selector_container>
</view>
</screen>

View File

@@ -0,0 +1,136 @@
.. _xml_styles:
======
Styles
======
Overview
********
In XML files, both style sheets (:cpp:expr:`lv_style_t`) and local styles can be used.
Style variants are also supported to change style properties at runtime.
Style Sheets
************
In the ``<styles>`` section, styles and their properties can be defined like this:
.. code-block:: xml
<style name="red"
help="What is this style about?"
border_width="2px"
border_color="0xff0000"/>
Styles can be referenced like this in the ``<view>``:
.. code-block:: xml
<view>
<slider styles="main red:indicator red:knob:focused"/>
</view>
As shown in the example, parts and states are appended after a ``:`` to the style's name.
Local Styles
************
Local styles can be used directly in a widget, for example:
.. code-block:: xml
<lv_label style_bg_opa="200" style_bg_opa:disabled="100"/>
Style Variants
**************
The ``<style>`` tags can have ``<variant>`` child tags:
.. code-block:: xml
<styles>
<style name="big_button" bg_color="0xf00" border_width="1px" pad_left="10px">
<variant name="color" case="red" bg_color="0xf00"/>
<variant name="color" case="green" bg_color="0x0f0"/>
<variant name="color" case="blue" bg_color="0x00f"/>
</style>
</styles>
``<variant>`` elements allow altering styles at runtime.
The ``variant_<name>`` subjects of the component library are used for each setting, and an observer callback is generated with all the style properties valid for that variant. The observer callback first resets the style and then sets all the properties.
This feature is not supported yet.
Gradients
*********
Before the ``<styles>`` tag, the ``<gradients>`` tag can be used to describe various gradients, which can later be referenced in styles.
When a gradient is created, it can be referenced by its name, like:
.. code-block:: xml
<style bg_grad="grad1"/>
or
.. code-block:: xml
<lv_button style_bg_grad="grad1"/>
Horizontal or Vertical Gradient
-------------------------------
Define simple ``<horizontal>`` or ``<vertical>`` gradients:
.. code-block:: xml
<gradients>
<horizontal name="grad1">
<stop color="#ff0000" offset="20%" opa="40%"/>
<stop color="#00ff00" offset="128" opa="100%"/>
</horizontal>
</gradients>
Linear Gradient
---------------
Define a skewed gradient from two points:
.. code-block:: xml
<gradients>
<linear name="grad1" start="50 50" end="100 80">
<stop color="#ff0000" offset="20%" opa="100%"/>
<stop color="#00ff00" offset="240" opa="100%"/>
</linear>
</gradients>
Radial Gradient
---------------
Define a radial gradient:
.. code-block:: xml
<gradients>
<radial name="grad1" center="100 50%" edge="200 50" focal_center="50 80%" focal_edge="55 80%">
<stop color="#ff0000" opa="100%"/>
<stop color="#00ff00" opa="100%"/>
</radial>
</gradients>
Conical Gradient
----------------
Define a conical gradient:
.. code-block:: xml
<gradients>
<conical name="grad1" center="80 50%" angle="45 270">
<stop color="#ff0000" opa="100%"/>
<stop color="#00ff00" opa="100%"/>
</conical>
</gradients>

View File

@@ -0,0 +1,7 @@
.. _xml_subjects:
========
Subjects
========
TODO

View File

@@ -0,0 +1,115 @@
.. _xml:
======
Syntax
======
Naming conventions
******************
- A standard XML syntax is used.
- Lowercase letters with ``_`` separation are used for attribute names.
- The usual variable name rules apply for attribute and tag names: only letters, numbers, ``'_'`` and cannot start with a number.
- LVGL API is followed as much as possible, e.g., ``align="center"``, ``bg_color="0xff0000"``.
- For colors, all these options are supported: ``0x112233``, ``#112233``, ``112233``, ``0x123``, ``#123``, ``123``.
- ``params`` can be referenced with ``$``.
- ``consts`` can be referenced with ``#``.
- ``styles`` can be attached to states and/or parts like ``styles="style1 style2:pressed style3:focused:scrollbar"``.
- Local styles can be used like ``<lv_label style_text_color="0xff0000" style_text_color:checked="0x00ff00"/>``.
Types
*****
All of the types can be used as API property types, but only a subset of them can be used as constant and subject types.
Simple types
------------
The following simple built-in types are supported:
- ``bool``: ``true`` or ``false``.
- ``int``: Integer number in the range of -2M to 2M by default. (``int32_t`` in C)
- ``px``: Simple pixel unit. The unit ``px`` can be omitted.
- ``%``: Percentage. ``%`` must be appended as a unit. (Means :cpp:expr:`lv_pct()`)
- ``content``: Means ``LV_SIZE_CONTENT``.
- ``string``: Simple ``\0`` terminated string. When multiple strings are used in a 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`)
- ``opa``: Opacity value in the range of 0 to 255 or 0 to 100%.
- ``lv_obj``: Pointer to a widget (:cpp:expr:`lv_obj_t *`).
- ``point``: A point with ``x`` and ``y`` values. (:cpp:expr:`lv_point_t`)
- ``arglist``: Just list all the parameters as arguments. Supports only ``int`` and ``string``. E.g. ``foo="1 23 'hello' 'a'"``.
Name-based types
----------------
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, these can be referenced by their names.
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 (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 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 ``lv_xml_register_image/font/event_cb/etc(name, pointer)`` can be used.
Later, the set pointer can be retrieved by ``lv_xml_get_image/font/event_cb(name)``.
- ``style``: The name of a style. :cpp:expr:`lv_xml_get_style(name)` returns an :cpp:expr:`lv_style_t *`.
- ``font``: The name of a font. :cpp:expr:`lv_xml_get_font(name)` returns an :cpp:expr:`lv_font_t *`.
- ``image``: The name of an image. :cpp:expr:`lv_xml_get_image(name)` returns an :cpp:expr:`const void *`, which can be :cpp:expr:`lv_image_dsc_t *` or a path to a file.
- ``animation``: The name of an animation descriptor. :cpp:expr:`lv_xml_get_anim(name)` returns an :cpp:expr:`lv_anim_t *`.
- ``subject``: The name of a subject. :cpp:expr:`lv_xml_get_subject(name)` returns an :cpp:expr:`lv_subject_t *`.
- ``grad``: The name of a gradient. :cpp:expr:`lv_xml_get_grad(name)` returns an :cpp:expr:`lv_grad_dsc_t *`.
- ``event_cb``: The name of an event callback. :cpp:expr:`lv_xml_get_event_cb(name)` returns an :cpp:expr:`lv_event_cb_t`.
Arrays
------
Any type can be an array in four ways:
- ``int[N]``: An integer array with ``N`` elements, and the count is passed as the next parameter.
- ``string[...NULL]``: An array terminated with ``NULL``. ``NULL`` can be replaced by any value, e.g., ``grid_template_last``.
- ``string[5]``: An array that must have exactly 5 elements.
- ``string[]``: No ``NULL`` termination and no count parameter.
Enums
-----
``<enumdef>`` can be used in the ``<api>`` tags to create custom enums for **widgets**. It is not supported for components.
For example:
.. code-block:: xml
<api>
<enumdef name="my_widget_mode" help="Possible modes" help-zh="Chinese help">
<enum name="normal" help="Normal mode" help-zh="Normal mode in Chinese" value="0x10"/>
<enum name="inverted" help="Inverted mode"/>
</enumdef>
<prop name="mode" help="help">
<param name="mode" type="enum:my_widget_mode" help="help"/>
</prop>
</api>
When used as a type, a ``+`` suffix means multiple values can be selected and ORed. For example: ``type="axis+"``.
In this case, the options should be separated by ``|``, for example: ``axis=primary_x|secondary_y``.
Compound types
--------------
Types can be compound, meaning multiple options/types are possible. For example, for width: ``type="px|%|content"``.
Limit the possible values
-------------------------
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')``
These are checked in the UI Editor, and if an invalid option is selected, it will be highlighted as an error.

View File

@@ -0,0 +1,7 @@
.. _xml_translations:
============
Translations
============
TODO

View File

@@ -0,0 +1,7 @@
.. _xml_view:
=========
View
=========
TODO

View File

@@ -0,0 +1,101 @@
.. _xml_widgets:
=======
Widgets
=======
Overview
********
Widgets are written in C and compiled into the application.
They can be referenced from components, and their API can be used via the exposed attributes
(e.g., label text or slider value).
Using the UI Editor, all the following C/H files can be exported from the XML of the widgets:
- ``<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. 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
*****
XML Parser
----------
To make the 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
void * lv_xml_label_create(lv_xml_parser_state_t * state, const char ** attrs)
{
/* Create the label */
void * obj = lv_label_create(lv_xml_state_get_parent(state));
return obj;
}
void lv_xml_label_apply(lv_xml_parser_state_t * state, const char ** attrs)
{
void * obj = lv_xml_state_get_item(state);
/* Apply the common properties, e.g., width, height, styles, flags, etc. */
lv_xml_obj_apply(state, attrs);
/* Process the label-specific attributes */
for(int i = 0; attrs[i]; i += 2) {
const char * name = attrs[i];
const char * value = attrs[i + 1];
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));
}
}
/* Helper to convert the string to enum values */
static lv_label_long_mode_t long_mode_text_to_enum(const char * txt)
{
if(lv_streq("wrap", txt)) return LV_LABEL_LONG_WRAP;
if(lv_streq("scroll", txt)) return LV_LABEL_LONG_SCROLL;
LV_LOG_WARN("%s is an unknown value for label's long_mode", txt);
return 0; /* Return 0 in the absence of a better option. */
}
A widget XML processor can be registered like this:
.. code-block:: c
lv_xml_widget_register("lv_label", lv_xml_label_create, lv_xml_label_apply);
After registration, a widget can be created like this:
.. code-block:: c
const char * attrs[] = {
"text", "Click here",
"align", "center",
NULL, NULL,
};
lv_xml_create(lv_screen_active(), "lv_label", attrs);
LVGL automatically registers its built-in widgets,
so only custom widgets need to be registered manually.
Adding Custom Code
------------------
``<widget_name>.c`` contains three hooks:
- **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 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 ``<widget_name>_gen.h``.
Besides these, any custom code and functions can be freely implemented in this file.