feat(docs): batch 14 of proofread/edited docs (#7477)

This commit is contained in:
Victor Wheeler
2025-01-15 00:48:25 -07:00
committed by GitHub
parent b1728f85b3
commit 5f5c74c088
7 changed files with 307 additions and 129 deletions

View File

@@ -188,27 +188,28 @@ and attach them to LVGL via the *Image decoder* interface.
An image decoder consists of 4 callbacks: An image decoder consists of 4 callbacks:
- **info** get some basic info about the image (width, height and color format). :info: get some basic info about the image (width, height and color format).
- **open** open an image: :open: open an image:
- store a decoded image - store a decoded image
- set it to ``NULL`` to indicate the image can be read line-by-line. - set it to ``NULL`` to indicate the image can be read line-by-line.
- **get_area** if *open* didn't fully open an image this function should give back part of image as decoded data. :get_area: if *open* didn't fully open an image this function should give back part of image as decoded data.
- **close** close an opened image, free the allocated resources. :close: close an opened image, free the allocated resources.
You can add any number of image decoders. When an image needs to be You can add any number of image decoders. When an image needs to be
drawn, the library will try all the registered image decoders until it drawn, the library will try all the registered image decoders until it
finds one which can open the image, i.e. one which knows that format. finds one which can open the image, i.e. one which knows that format.
The following formats are understood by the built-in decoder: The following formats are understood by the built-in decoder:
- ``LV_COLOR_FORMAT_I1``
- ``LV_COLOR_FORMAT_I2`` - :cpp:enumerator:`LV_COLOR_FORMAT_I1`
- ``LV_COLOR_FORMAT_I4`` - :cpp:enumerator:`LV_COLOR_FORMAT_I2`
- ``LV_COLOR_FORMAT_I8`` - :cpp:enumerator:`LV_COLOR_FORMAT_I4`
- ``LV_COLOR_FORMAT_RGB888`` - :cpp:enumerator:`LV_COLOR_FORMAT_I8`
- ``LV_COLOR_FORMAT_XRGB8888`` - :cpp:enumerator:`LV_COLOR_FORMAT_RGB888`
- ``LV_COLOR_FORMAT_ARGB8888`` - :cpp:enumerator:`LV_COLOR_FORMAT_XRGB8888`
- ``LV_COLOR_FORMAT_RGB565`` - :cpp:enumerator:`LV_COLOR_FORMAT_ARGB8888`
- ``LV_COLOR_FORMAT_RGB565A8`` - :cpp:enumerator:`LV_COLOR_FORMAT_RGB565`
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB565A8`
Custom image formats Custom image formats
@@ -230,8 +231,8 @@ library. In other words, the image decoder must decode the *Raw* images
to *True color* according to the format described in the :ref:`overview_image_color_formats` section. to *True color* according to the format described in the :ref:`overview_image_color_formats` section.
Register an image decoder Registering an image decoder
------------------------- ----------------------------
Here's an example of getting LVGL to work with PNG images. Here's an example of getting LVGL to work with PNG images.

View File

@@ -18,19 +18,21 @@ Such concept also has some similarities to `UiViewController on
iOS <https://developer.apple.com/documentation/uikit/uiviewcontroller>`__. iOS <https://developer.apple.com/documentation/uikit/uiviewcontroller>`__.
Fragment Manager is a manager holding references to fragments attached Fragment Manager is a manager holding references to fragments attached
to it, and has an internal stack to achieve navigation. You can use to it, and has an internal stack to achieve forward and backwards navigation. You can use
fragment manager to build navigation stack, or multi pane application fragment manager to build a navigation stack, or a multi-pane application
easily. easily.
.. _fragment_usage: .. _fragment_usage:
Usage Usage
----- *****
Enable :c:macro:`LV_USE_FRAGMENT` in ``lv_conf.h``. Enable :c:macro:`LV_USE_FRAGMENT` in ``lv_conf.h``.
Create Fragment Class Create Fragment Class
~~~~~~~~~~~~~~~~~~~~~ ---------------------
.. code-block:: c .. code-block:: c
@@ -51,7 +53,7 @@ Create Fragment Class
}; };
Use ``lv_fragment_manager`` Use ``lv_fragment_manager``
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------
.. code-block:: c .. code-block:: c
@@ -61,7 +63,7 @@ Use ``lv_fragment_manager``
lv_fragment_manager_replace(manager, &sample_cls, init_argument); lv_fragment_manager_replace(manager, &sample_cls, init_argument);
Fragment Based Navigation Fragment Based Navigation
~~~~~~~~~~~~~~~~~~~~~~~~~ -------------------------
.. code-block:: c .. code-block:: c
@@ -73,14 +75,18 @@ Fragment Based Navigation
/* Remove the top most fragment from the stack, and bring back previous one. */ /* Remove the top most fragment from the stack, and bring back previous one. */
lv_fragment_manager_pop(manager); lv_fragment_manager_pop(manager);
.. _fragment_example: .. _fragment_example:
Example Example
------- *******
.. include:: ../../examples/others/fragment/index.rst .. include:: ../../examples/others/fragment/index.rst
.. _fragment_api: .. _fragment_api:
API API
--- ***

View File

@@ -4,10 +4,10 @@
Grid navigation Grid navigation
=============== ===============
Grid navigation (gridnav for short) is a feature that changes the Grid navigation (gridnav for short) is a feature that moves focus among a set
currently focused child Widget as arrow keys are pressed. of child Widgets via arrow-key presses.
If the children are arranged into a grid-like layout then the up, down, If the child Widgets are arranged into a grid-like layout then the up, down,
left and right arrows move focus to the nearest sibling in the left and right arrows move focus to the nearest sibling in the
respective direction. respective direction.
@@ -17,8 +17,8 @@ manually positioned children, as well as :ref:`flex` and
:ref:`grid` layouts. :ref:`grid` layouts.
Gridnav also works if the children are arranged into a single row or Gridnav also works if the children are arranged into a single row or
column. That makes it useful, for example, to simplify navigation on a column. This is useful, for example, to simplify navigation among items in a
:ref:`List widget <lv_list>`. :ref:`List Widget <lv_list>`.
Gridnav assumes that the Widget to which gridnav is added is part of a Gridnav assumes that the Widget to which gridnav is added is part of a
:ref:`group <indev_groups>`. This way, if the Widget with :ref:`group <indev_groups>`. This way, if the Widget with
@@ -34,15 +34,18 @@ key on keyboard as usual.
If the container is scrollable and the focused child is out of the view, If the container is scrollable and the focused child is out of the view,
gridnav will automatically scroll the child into view. gridnav will automatically scroll the child into view.
.. _gridnav_usage: .. _gridnav_usage:
Usage Usage
----- *****
To add the gridnav feature to a Widget use To add gridnav behavior to any Widget (e.g. one serving as a container for
:cpp:expr:`lv_gridnav_add(cont, flags)`. child Widgets that the end user will navigate among using arrow keys) use
:cpp:expr:`lv_gridnav_add(container, flags)`.
``flags`` control the behavior of gridnav: The ``flags`` argument controls the navigation behavior:
- :cpp:enumerator:`LV_GRIDNAV_CTRL_NONE`: Default settings - :cpp:enumerator:`LV_GRIDNAV_CTRL_NONE`: Default settings
- :cpp:enumerator:`LV_GRIDNAV_CTRL_ROLLOVER`: If there is no next/previous Widget in a - :cpp:enumerator:`LV_GRIDNAV_CTRL_ROLLOVER`: If there is no next/previous Widget in a
@@ -51,33 +54,40 @@ To add the gridnav feature to a Widget use
- :cpp:enumerator:`LV_GRIDNAV_CTRL_SCROLL_FIRST`: If an arrow is pressed and the focused - :cpp:enumerator:`LV_GRIDNAV_CTRL_SCROLL_FIRST`: If an arrow is pressed and the focused
Widget can be scrolled in that direction then it will be scrolled instead of Widget can be scrolled in that direction then it will be scrolled instead of
going to the next/previous Widget. If there is no more room for scrolling the going to the next/previous Widget. If there is no more room for scrolling the
next/previous Widget will be focused normally next/previous Widget will receive focus normally.
- :cpp:enumerator:`LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY`: Only use the left/right keys - :cpp:enumerator:`LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY`: Only use the left/right keys
for grid navigation. Up/down key events will be sent to the focused Widget. for grid navigation. Up/down key events will be sent to the Widget that has focus.
- :cpp:enumerator:`LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY`: Only use the up/down keys - :cpp:enumerator:`LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY`: Only use the up/down keys
for grid navigation. Left/right key events will be sent to the focused Widget. for grid navigation. Left/right key events will be sent to the Widget that has focus.
While the above behaviors can be combined by bit-wise OR-ing the above values together,
:cpp:enumerator:`LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY` and :cpp:enumerator:`LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY` :cpp:enumerator:`LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY` and :cpp:enumerator:`LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY`
should not be used together. should not be used together.
:cpp:expr:`lv_gridnav_remove(cont)` Removes gridnav from a Widget. :cpp:expr:`lv_gridnav_remove(container)` Removes gridnav behavior from a Widget.
Focusable Widgets Focusable Widgets
----------------- *****************
A Widget needs to be clickable or click focusable A Widget needs to be clickable or click focusable
(:cpp:enumerator:`LV_OBJ_FLAG_CLICKABLE` or :cpp:enumerator:`LV_OBJ_FLAG_CLICK_FOCUSABLE`) and not (:cpp:enumerator:`LV_OBJ_FLAG_CLICKABLE` or :cpp:enumerator:`LV_OBJ_FLAG_CLICK_FOCUSABLE`) and not
hidden (:cpp:enumerator:`LV_OBJ_FLAG_HIDDEN`) to be focusable by gridnav. hidden (:cpp:enumerator:`LV_OBJ_FLAG_HIDDEN`) to receive focus via gridnav.
.. _gridnav_example: .. _gridnav_example:
Example Examples
------- ********
.. include:: ../../examples/others/gridnav/index.rst .. include:: ../../examples/others/gridnav/index.rst
.. _gridnav_api: .. _gridnav_api:
API API
--- ***

View File

@@ -4,47 +4,48 @@
Pinyin IME Pinyin IME
========== ==========
Pinyin IME provides API to provide Chinese Pinyin input method (Chinese Pinyin IME provides an API to provide Chinese Pinyin input method (Chinese
input) for keyboard object, which supports 26 key and 9 key input modes. input) for a Keyboard Widget, which supports both 26-key and 9-key input modes.
You can think of ``lv_ime_pinyin`` as a Pinyin input method plug-in for You can think of ``lv_ime_pinyin`` as a Pinyin input method plug-in for
keyboard objects. the Keyboard Widget.
Normally, an environment where :ref:`lv_keyboard` can Normally, an environment where :ref:`lv_keyboard` can
run can also run ``lv_ime_pinyin``. There are two main influencing run can also run ``lv_ime_pinyin``. There are two main influencing
factors: the size of the font file and the size of the dictionary. factors: the size of the font file and the size of the dictionary.
.. _ime_pinyin_usage: .. _ime_pinyin_usage:
Usage Usage
----- *****
Enable :c:macro:`LV_USE_IME_PINYIN` in ``lv_conf.h``. Enable :c:macro:`LV_USE_IME_PINYIN` in ``lv_conf.h``.
First use :cpp:expr:`lv_ime_pinyin_create(lv_screen_active())` to create a Pinyin First use :cpp:expr:`lv_ime_pinyin_create(lv_screen_active())` to create a Pinyin
input method plug-in, then use input-method plug-in, then use
:cpp:expr:`lv_ime_pinyin_set_keyboard(pinyin_ime, kb)` to add the ``keyboard`` :cpp:expr:`lv_ime_pinyin_set_keyboard(pinyin_ime, kb)` to add the Keyboard Widget
you created to the Pinyin input method plug-in. You can use you created to the Pinyin input method plug-in. You can use
:cpp:expr:`lv_ime_pinyin_set_dict(pinyin_ime, your_dict)` to use a custom :cpp:expr:`lv_ime_pinyin_set_dict(pinyin_ime, your_dict)` to use a custom
dictionary (if you don't want to use the built-in dictionary at first, dictionary. If you don't want to use the built-in dictionary,
you can disable :c:macro:`LV_IME_PINYIN_USE_DEFAULT_DICT` in ``lv_conf.h``, you can disable :c:macro:`LV_IME_PINYIN_USE_DEFAULT_DICT` in ``lv_conf.h``,
which can save a lot of memory space). which can save a lot of memory space.
The built-in thesaurus is customized based on the The built-in thesaurus is customized based on the
**LV_FONT_SIMSUN_16_CJK** font library, which currently only has more **LV_FONT_SIMSUN_16_CJK** font library, which currently has more
than ``1,000`` most common CJK radicals, so it is recommended to use than 1,000 of the most common CJK radicals, so it is recommended to use a
custom fonts and thesaurus. custom font and thesaurus.
In the process of using the Pinyin input method plug-in, you can change In the process of using the Pinyin input method plug-in, you can change
the keyboard and dictionary at any time. the Keyboard and dictionary at any time.
Custom dictionary
-----------------
If you don't want to use the built-in Pinyin dictionary, you can use the Custom Dictionary
custom dictionary. Or if you think that the built-in phonetic dictionary *****************
consumes a lot of memory, you can also use a custom dictionary.
If you don't want to use the built-in Pinyin dictionary, or if you feel that the
built-in phonetic dictionary consumes too much memory, you can use a custom dictionary.
Customizing the dictionary is very simple. Customizing the dictionary is very simple.
@@ -54,11 +55,11 @@ Then, write a dictionary in the following format.
Dictionary format Dictionary format
~~~~~~~~~~~~~~~~~ -----------------
The arrangement order of each pinyin syllable is very important. You The arrangement order of each pinyin syllable is very important. If you
need to customize your own thesaurus according to the Hanyu Pinyin need to customize your own thesaurus according to the Hanyu Pinyin
syllable table. You can read syllable table, you can read
`here <https://baike.baidu.com/item/%E6%B1%89%E8%AF%AD%E6%8B%BC%E9%9F%B3%E9%9F%B3%E8%8A%82/9167981>`__ `here <https://baike.baidu.com/item/%E6%B1%89%E8%AF%AD%E6%8B%BC%E9%9F%B3%E9%9F%B3%E8%8A%82/9167981>`__
to learn about the Hanyu Pinyin syllables and the syllable table. to learn about the Hanyu Pinyin syllables and the syllable table.
@@ -78,14 +79,14 @@ Then, write your own dictionary according to the following format:
{ "zuo", "昨左佐做作坐座撮琢柞"}, { "zuo", "昨左佐做作坐座撮琢柞"},
{NULL, NULL} {NULL, NULL}
**The last item** must end with ``{null, null}``, or it will not work **The last item** must be ``{null, null}``, or it will not work
properly. properly.
.. _ime_pinyin_apply_new_dictionary: .. _ime_pinyin_apply_new_dictionary:
Apply new dictionary Applying a new dictionary
~~~~~~~~~~~~~~~~~~~~ -------------------------
After writing a dictionary according to the above dictionary format, you After writing a dictionary according to the above dictionary format, you
only need to call this function to set up and use your dictionary: only need to call this function to set up and use your dictionary:
@@ -96,32 +97,36 @@ only need to call this function to set up and use your dictionary:
lv_100ask_pinyin_ime_set_dict(pinyin_ime, your_pinyin_dict); lv_100ask_pinyin_ime_set_dict(pinyin_ime, your_pinyin_dict);
.. _ime_pinyin_modes: .. _ime_pinyin_modes:
Modes Modes
----- *****
The lv_ime_pinyin have the following modes: lv_ime_pinyin has the following modes:
- :cpp:enumerator:`LV_IME_PINYIN_MODE_K26`: Pinyin 26 key input mode - :cpp:enumerator:`LV_IME_PINYIN_MODE_K26`: Pinyin 26-key input mode
- :cpp:enumerator:`LV_IME_PINYIN_MODE_K9`: Pinyin 9 key input mode - :cpp:enumerator:`LV_IME_PINYIN_MODE_K9`: Pinyin 9-key input mode
- :cpp:enumerator:`LV_IME_PINYIN_MODE_K9_NUMBER`: Numeric keypad mode - :cpp:enumerator:`LV_IME_PINYIN_MODE_K9_NUMBER`: Numeric keypad mode
The ``TEXT`` modes' layout contains buttons to change mode. The Keyboard's ``TEXT``-mode layout contains buttons to change mode.
To set the mode manually, use :cpp:expr:`lv_ime_pinyin_set_mode(pinyin_ime, mode)`. To set the mode manually, use :cpp:expr:`lv_ime_pinyin_set_mode(pinyin_ime, mode)`.
The default mode is :cpp:enumerator:`LV_IME_PINYIN_MODE_K26`. The default mode is :cpp:enumerator:`LV_IME_PINYIN_MODE_K26`.
.. _ime_pinyin_example: .. _ime_pinyin_example:
Example Example
------- *******
.. include:: ../../examples/others/ime/index.rst .. include:: ../../examples/others/ime/index.rst
.. _ime_pinyin_api: .. _ime_pinyin_api:
API API
--- ***

View File

@@ -9,18 +9,26 @@ display Unicode emoji icons in text.
Supported image formats: determined by enabled LVGL :ref:`image decoders <overview_image_decoder>`. Supported image formats: determined by enabled LVGL :ref:`image decoders <overview_image_decoder>`.
.. _lv_imgfont_usage: .. _lv_imgfont_usage:
Usage Usage
----- *****
Enable :c:macro:`LV_USE_IMGFONT` in ``lv_conf.h``. Enable :c:macro:`LV_USE_IMGFONT` in ``lv_conf.h``.
To create a new *imgfont* use :cpp:expr:`lv_imgfont_create(height, path_cb, user_data)`. To create a new *imgfont*:
.. code-block:: c
static lv_font_t * imgfont;
...
imgfont = lv_imgfont_create(height, path_cb, user_data);
- ``height`` Font size. - ``height`` Font size.
- ``path_cb`` A function to get the image path of a character. - ``path_cb`` A function to get the image path of a character.
Return ``NULL`` if no image should be shown, but the character itself. Pass ``NULL`` if no image should be shown, but the character itself.
- ``user_data`` Pointer to user data. - ``user_data`` Pointer to user data.
To use the *imgfont* in a label, reference it: To use the *imgfont* in a label, reference it:
@@ -28,14 +36,18 @@ To use the *imgfont* in a label, reference it:
To destroy the *imgfont* that is no longer used, use :cpp:expr:`lv_imgfont_destroy(imgfont)`. To destroy the *imgfont* that is no longer used, use :cpp:expr:`lv_imgfont_destroy(imgfont)`.
.. _lv_imgfont_example: .. _lv_imgfont_example:
Example Example
------- *******
.. include:: ../../examples/others/imgfont/index.rst .. include:: ../../examples/others/imgfont/index.rst
.. _lv_imgfont_api: .. _lv_imgfont_api:
API API
--- ***

View File

@@ -4,28 +4,38 @@
Monkey Monkey
====== ======
A simple monkey test. Use random input to stress test the application. The Monkey module provides LVGL applications with a simple monkey test. Monkey
Testing is a technique where the user tests the application or system by providing
random inputs and checking the behavior or seeing whether the aplication or system
will crash. This module provides this service as simulated random input to stress
test an LVGL application.
.. _monkey_usage: .. _monkey_usage:
Usage Usage
----- *****
Enable :c:macro:`LV_USE_MONKEY` in ``lv_conf.h``. First, enable :c:macro:`LV_USE_MONKEY` in ``lv_conf.h``.
First configure monkey, use :c:struct:`lv_monkey_config_t` to define the Next, declare a variable (it can be local) of type :c:type:`lv_monkey_config_t` to
configuration structure, set the ``type`` (check :ref:`Input Devices <indev>` define the configuration structure, initialize it using
for the supported types), and then set the :cpp:expr:`lv_monkey_config_init(cfg)` then set its ``type`` member to the desired
range of ``period_range`` and ``input_range``, the monkey will output type of :ref:`input device <indev>`, and set the ``min`` and ``max`` values for its
random operations at random times within this range. Call ``period_range`` and ``input_range`` members to set the time ranges (in milliseconds)
:cpp:func:`lv_monkey_create` to create monkey. Finally call and input ranges the Monkey module will use to generate random input at random times.
:cpp:expr:`lv_monkey_set_enable(monkey, true)` to enable monkey.
Next, call :cpp:expr:`lv_monkey_create(cfg)` to create the Monkey. It returns a
pointer to the ``lv_monkey_t`` created.
Finally call :cpp:expr:`lv_monkey_set_enable(monkey, true)` to enable Monkey.
If you want to pause the monkey, call If you want to pause the monkey, call
:cpp:expr:`lv_monkey_set_enable(monkey, false)`. To delete the monkey, call :cpp:expr:`lv_monkey_set_enable(monkey, false)`. To delete it, call
:cpp:expr:`lv_monkey_delete(monkey)`. :cpp:expr:`lv_monkey_delete(monkey)`.
Note that ``input_range`` has different meanings in different ``type``: Note that ``input_range`` has different meanings depending on the ``type`` input device:
- :cpp:enumerator:`LV_INDEV_TYPE_POINTER`: No effect, click randomly within the pixels of the screen resolution. - :cpp:enumerator:`LV_INDEV_TYPE_POINTER`: No effect, click randomly within the pixels of the screen resolution.
- :cpp:enumerator:`LV_INDEV_TYPE_ENCODER`: The minimum and maximum values of ``enc_diff``. - :cpp:enumerator:`LV_INDEV_TYPE_ENCODER`: The minimum and maximum values of ``enc_diff``.
@@ -34,15 +44,19 @@ Note that ``input_range`` has different meanings in different ``type``:
:cpp:func:`lv_indev_set_button_points` to map the key ID to the coordinates. :cpp:func:`lv_indev_set_button_points` to map the key ID to the coordinates.
- :cpp:enumerator:`LV_INDEV_TYPE_KEYPAD`: No effect, Send random :ref:`indev_keys`. - :cpp:enumerator:`LV_INDEV_TYPE_KEYPAD`: No effect, Send random :ref:`indev_keys`.
.. _monkey_example: .. _monkey_example:
Example Example
------- *******
.. include:: ../../examples/others/monkey/index.rst .. include:: ../../examples/others/monkey/index.rst
.. _monkey_api: .. _monkey_api:
API API
--- ***

View File

@@ -1,66 +1,196 @@
.. _obj_id: .. _widget_id:
========= =========
Widget ID Widget ID
========= =========
LVGL provides an optional field in :cpp:type:`lv_obj_t` to store the Widget ID. Widgets can optionally have identifiers added to their functionality if needed for
Widget ID can be used in many cases, for example, to identify the Widget. the application. Exactly how that happens is designed to be flexible, and can morph
Or we can store a program backtrace to where the Widget is created. with the needs of the application. It can even be a timestamp or other data current
at the time the Widget was created.
.. _obj_id_usage:
.. _widget_id_usage:
Usage Usage
----- *****
Enable this feature by setting :c:macro:`LV_USE_OBJ_ID` to `1` in ``lv_conf.h``. Enable Widget ID functionality by setting :c:macro:`LV_USE_OBJ_ID` to ``1`` in ``lv_conf.h``.
Enable :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` to automatically assign an ID to Widget when it's created. Once enabled, several things change:
It's done by calling function :cpp:func:`lv_obj_assign_id` from :cpp:func:`lv_obj_constructor`.
You can either use your own ID generator by defining the function :cpp:func:`lv_obj_assign_id` or you can utilize the built-in one. - each Widget will now have a ``void *`` field called ``id``;
To use the builtin ID generator, set :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `1`. - these two API functions become available:
You can directly access the ID by :cpp:expr:`lv_obj_get_id(widget)` or use API :cpp:expr:`lv_obj_stringify_id(widget, buf, len)` - :cpp:expr:`lv_obj_get_id(widget)`,
to get a string representation of the ID. - :cpp:expr:`lv_obj_get_child_by_id(widget, id)`;
Use custom ID generator - several more Widget-ID-related API functions become available if
~~~~~~~~~~~~~~~~~~~~~~~ :c:macro:`LV_USE_OBJ_ID_BUILTIN` is non-zero (more on this below);
- two additional configuration macros both :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` and
:c:macro:`LV_USE_OBJ_ID_BUILTIN` now have meaning.
Set :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `0` in ``lv_conf.h``.
Below APIs needed to be implemented and linked to lvgl. :c:macro:`LV_OBJ_ID_AUTO_ASSIGN`
--------------------------------
This macro in ``lv_conf.h`` defaults to whatever value :c:macro:`LV_USE_OBJ_ID`
equates to. You can change this if you wish. Either way, if it equates to a
non-zero value, it causes two things to happen:
- :cpp:expr:`lv_obj_assign_id(class_p, widget)` will be called at the end of each
Widget's creation, and
- :cpp:expr:`lv_obj_free_id(widget)` will be called at the end of the sequence when
each Widget is deleted.
Because of this timing, custom versions of these functions can be used according to
the below, and they can even be used like "event hooks" to implement a trace
operation that occurs when each Widget is created and deleted.
:cpp:expr:`lv_obj_assign_id(class_p, widget)`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This function (whether provided by LVGL or by you --- more on this below) is
responsible for assigning a value to the Widget's ``id`` field, and possibly do
other things, depending on the implementation.
:cpp:expr:`lv_obj_free_id(widget)`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This function (whether provided by LVGL or by you --- more on this below) is
responsible for doing the clean-up of any resources allocated by
:cpp:func:`lv_obj_assign_id()`
:c:macro:`LV_USE_OBJ_ID_BUILTIN`
--------------------------------
This macro in ``lv_conf.h`` equates to ``1`` by default. You can change this if you
wish. When it equates to a non-zero value the following function implementations are
provided by LVGL:
- :cpp:expr:`lv_obj_assign_id(class_p, widget)`
- :cpp:expr:`lv_obj_free_id(widget)`
- :cpp:expr:`lv_obj_set_id(widget, id)`
- :cpp:expr:`lv_obj_stringify_id(widget, buf, len)`
- :cpp:expr:`lv_obj_id_compare(id1, id2)`
These supply the default implementation for Widget IDs, namely that for each Widget
created, :cpp:expr:`lv_obj_stringify_id(widget, buf, len)` will produce a unique
string for it. Example: if the following 6 Widgets are created in this sequence:
- Screen
- Label
- Button
- Label
- Label
- Image
the strings produced by :cpp:expr:`lv_obj_stringify_id(widget, buf, len)` would be
- obj1
- label1
- btn1
- label2
- label3
- image1
respectively.
.. _widget_id_custom_generator:
Using a custom ID generator
---------------------------
If you wish, you can provide custom implementations for several Widget-ID related
functions. You do this by first setting :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `0` in
``lv_conf.h``.
You will then need to provide implementations for the following functions (and link
them with LVGL):
.. code-block:: c .. code-block:: c
void lv_obj_set_id(lv_obj_t * widget, void * id);
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * widget);
void lv_obj_free_id(lv_obj_t * widget);
const char * lv_obj_stringify_id(lv_obj_t * widget, char * buf, uint32_t len); const char * lv_obj_stringify_id(lv_obj_t * widget, char * buf, uint32_t len);
int lv_obj_id_compare(void * id1, void * id2); int lv_obj_id_compare(const void * id1, const void * id2);
If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value (or if you otherwise
simply need to use them), you will also need to provide implementations for:
.. code-block:: c
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * widget);
void lv_obj_free_id(lv_obj_t * widget);
If :c:macro:`LV_BUILD_TEST` equates to a non-zero value and you are including LVGL
test code in your compile (or if you otherwise simply need to use them), you
will also need to provide an implementation for:
.. code-block:: c
void lv_obj_set_id(lv_obj_t * widget, void * id);
:cpp:func:`lv_obj_assign_id` is called when a Widget is created. The Widget final class is passed from Examples of implementations of these functions exist in ``lv_obj_id_builtin.c``, but
parameter ``class_p``. Note it may be different than :cpp:expr:`obj->class_p` which is the class you are free to use a different design if needed.
currently being constructed.
:cpp:func:`lv_obj_free_id` is called when Widget is deconstructed. Free any resource allocated in :cpp:func:`lv_obj_assign_id`. :cpp:func:`lv_obj_stringify_id` converts the passed ``widget`` to a string
representation (typically incorporating the ``id`` field) and writes it into the
buffer provided in its ``buf`` argument.
:cpp:func:`lv_obj_stringify_id` converts id to a string representation. The string is stored in ``buf``. :cpp:func:`lv_obj_id_compare` compares 2 ``void * id`` values and returns ``0`` when
they are considered equal, and non-zero otherwise.
Dump Widget Tree If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value,
~~~~~~~~~~~~~~~~ :cpp:func:`lv_obj_assign_id` is called when a Widget is created. It is responsible
for assigning a value to the Widget's ``id`` field. A pointer to the Widget's final
class is passed in its ``class_p`` argument in case it is needed for determining the
value for the ``id`` field, or for other possible needs related to your design for
Widget IDs. Note that this pointer may be different than :cpp:expr:`widget->class_p`
which is the class of the Widget currently being created.
Use API ``lv_obj_dump_tree(lv_obj_t * widget, int depth)`` to dump the Widget Tree. If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value,
It will walk through all children and print the Widget ID together with Widget address. :cpp:func:`lv_obj_free_id` is called when a Widget is deleted. It needs to perform
the clean-up for any resources allocated by :cpp:func:`lv_obj_assign_id`.
Dumping a Widget Tree
---------------------
Regardless of the state of any of the above macros, the function
:cpp:expr:`lv_obj_dump_tree(widget)` provides a "dump" of the Widget Tree for the
specified Widget (that Widget plus all its children recursively) using the
currently-configured method used by the :c:macro:`LV_LOG_USER` macro. If NULL is
passed instead of a pointer to a "root" Widget, the dump will include the Widget Tree
for all :ref:`Screens`, for all :ref:`Displays <display>` in the system.
For :c:macro:`LV_LOG_USER` to produce output, the following needs to be true in
``lv_conf.h``:
- :c:macro:`LV_USE_LOG` must equate to a non-zero value
- :c:macro:`LV_LOG_LEVEL` <= :c:macro:`LV_LOG_LEVEL_USER`
It will recursively walk through all that Widget's children (starting with the Widget
itself) and print the Widget's parent's address, the Widget's address, and if
:c:macro:`LV_USE_OBJ_ID` equates to a non-zero value, will also print the output of
:cpp:func:`lv_obj_stringify_id` for that Widget.
This can be useful in the event of a UI crash. From that log you can examine the
state of the Widget Tree when :cpp:expr:`lv_obj_dump_tree(widget)` was called.
For example, if a pointer to a deleted Widget is stored in a Timer's
:cpp:expr:`timer->user_data` field when the timer event callback is called, attempted
use of that pointer will likly cause a crash because the pointer is not valid any
more. However, a timely dump of the Widget Tree right before that point will show
that the Widget no longer exists.
This is useful to debug UI crash. From log we can rebuilt UI the moment before crash.
For example, if the obj is stored to a :cpp:expr:`timer->user_data`, but obj is deleted when timer expired.
Timer callback will crash because of accessing wild pointer.
From the dump log we can clearly see that the obj does not exist.
Find child by ID Find child by ID
~~~~~~~~~~~~~~~~ ----------------
:cpp:expr:`lv_obj_get_child_by_id(widget, id)` will perform a recursive walk through
``widget``\ 's children and return the first child encountered having the given ID.
Use API ``lv_obj_t * lv_obj_get_child_by_id(const lv_obj_t * widget, void * id)`` to find a child by ID.
It will walk through all children and return the first child with the given ID.