mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
feat(docs): batch 14 of proofread/edited docs (#7477)
This commit is contained in:
parent
b1728f85b3
commit
5f5c74c088
@ -188,27 +188,28 @@ and attach them to LVGL via the *Image decoder* interface.
|
||||
|
||||
An image decoder consists of 4 callbacks:
|
||||
|
||||
- **info** get some basic info about the image (width, height and color format).
|
||||
- **open** open an image:
|
||||
- store a decoded image
|
||||
- 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.
|
||||
- **close** close an opened image, free the allocated resources.
|
||||
:info: get some basic info about the image (width, height and color format).
|
||||
:open: open an image:
|
||||
- store a decoded image
|
||||
- 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.
|
||||
:close: close an opened image, free the allocated resources.
|
||||
|
||||
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
|
||||
finds one which can open the image, i.e. one which knows that format.
|
||||
|
||||
The following formats are understood by the built-in decoder:
|
||||
- ``LV_COLOR_FORMAT_I1``
|
||||
- ``LV_COLOR_FORMAT_I2``
|
||||
- ``LV_COLOR_FORMAT_I4``
|
||||
- ``LV_COLOR_FORMAT_I8``
|
||||
- ``LV_COLOR_FORMAT_RGB888``
|
||||
- ``LV_COLOR_FORMAT_XRGB8888``
|
||||
- ``LV_COLOR_FORMAT_ARGB8888``
|
||||
- ``LV_COLOR_FORMAT_RGB565``
|
||||
- ``LV_COLOR_FORMAT_RGB565A8``
|
||||
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_I1`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_I2`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_I4`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_I8`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB888`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_XRGB8888`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_ARGB8888`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB565`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB565A8`
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Register an image decoder
|
||||
-------------------------
|
||||
Registering an image decoder
|
||||
----------------------------
|
||||
|
||||
Here's an example of getting LVGL to work with PNG images.
|
||||
|
||||
|
@ -18,19 +18,21 @@ Such concept also has some similarities to `UiViewController on
|
||||
iOS <https://developer.apple.com/documentation/uikit/uiviewcontroller>`__.
|
||||
|
||||
Fragment Manager is a manager holding references to fragments attached
|
||||
to it, and has an internal stack to achieve navigation. You can use
|
||||
fragment manager to build navigation stack, or multi pane application
|
||||
to it, and has an internal stack to achieve forward and backwards navigation. You can use
|
||||
fragment manager to build a navigation stack, or a multi-pane application
|
||||
easily.
|
||||
|
||||
|
||||
|
||||
.. _fragment_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
*****
|
||||
|
||||
Enable :c:macro:`LV_USE_FRAGMENT` in ``lv_conf.h``.
|
||||
|
||||
Create Fragment Class
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -51,7 +53,7 @@ Create Fragment Class
|
||||
};
|
||||
|
||||
Use ``lv_fragment_manager``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -61,7 +63,7 @@ Use ``lv_fragment_manager``
|
||||
lv_fragment_manager_replace(manager, &sample_cls, init_argument);
|
||||
|
||||
Fragment Based Navigation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -73,14 +75,18 @@ Fragment Based Navigation
|
||||
/* Remove the top most fragment from the stack, and bring back previous one. */
|
||||
lv_fragment_manager_pop(manager);
|
||||
|
||||
|
||||
|
||||
.. _fragment_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
*******
|
||||
|
||||
.. include:: ../../examples/others/fragment/index.rst
|
||||
|
||||
|
||||
|
||||
.. _fragment_api:
|
||||
|
||||
API
|
||||
---
|
||||
***
|
||||
|
@ -4,10 +4,10 @@
|
||||
Grid navigation
|
||||
===============
|
||||
|
||||
Grid navigation (gridnav for short) is a feature that changes the
|
||||
currently focused child Widget as arrow keys are pressed.
|
||||
Grid navigation (gridnav for short) is a feature that moves focus among a set
|
||||
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
|
||||
respective direction.
|
||||
|
||||
@ -17,8 +17,8 @@ manually positioned children, as well as :ref:`flex` and
|
||||
:ref:`grid` layouts.
|
||||
|
||||
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
|
||||
:ref:`List widget <lv_list>`.
|
||||
column. This is useful, for example, to simplify navigation among items in a
|
||||
:ref:`List Widget <lv_list>`.
|
||||
|
||||
Gridnav assumes that the Widget to which gridnav is added is part of a
|
||||
: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,
|
||||
gridnav will automatically scroll the child into view.
|
||||
|
||||
|
||||
|
||||
.. _gridnav_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
*****
|
||||
|
||||
To add the gridnav feature to a Widget use
|
||||
:cpp:expr:`lv_gridnav_add(cont, flags)`.
|
||||
To add gridnav behavior to any Widget (e.g. one serving as a container for
|
||||
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_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
|
||||
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
|
||||
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
|
||||
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
|
||||
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`
|
||||
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
|
||||
-----------------
|
||||
*****************
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
Example
|
||||
-------
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: ../../examples/others/gridnav/index.rst
|
||||
|
||||
|
||||
|
||||
.. _gridnav_api:
|
||||
|
||||
API
|
||||
---
|
||||
***
|
||||
|
||||
|
@ -4,47 +4,48 @@
|
||||
Pinyin IME
|
||||
==========
|
||||
|
||||
Pinyin IME provides API to provide Chinese Pinyin input method (Chinese
|
||||
input) for keyboard object, which supports 26 key and 9 key input modes.
|
||||
Pinyin IME provides an API to provide Chinese Pinyin input method (Chinese
|
||||
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
|
||||
keyboard objects.
|
||||
the Keyboard Widget.
|
||||
|
||||
Normally, an environment where :ref:`lv_keyboard` can
|
||||
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.
|
||||
|
||||
|
||||
|
||||
.. _ime_pinyin_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
*****
|
||||
|
||||
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
|
||||
input method plug-in, then use
|
||||
:cpp:expr:`lv_ime_pinyin_set_keyboard(pinyin_ime, kb)` to add the ``keyboard``
|
||||
input-method plug-in, then use
|
||||
: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
|
||||
: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``,
|
||||
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
|
||||
**LV_FONT_SIMSUN_16_CJK** font library, which currently only has more
|
||||
than ``1,000`` most common CJK radicals, so it is recommended to use
|
||||
custom fonts and thesaurus.
|
||||
**LV_FONT_SIMSUN_16_CJK** font library, which currently has more
|
||||
than 1,000 of the most common CJK radicals, so it is recommended to use a
|
||||
custom font and thesaurus.
|
||||
|
||||
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. Or if you think that the built-in phonetic dictionary
|
||||
consumes a lot of memory, you can also use a custom dictionary.
|
||||
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.
|
||||
|
||||
@ -54,11 +55,11 @@ Then, write a dictionary in the following 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
|
||||
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>`__
|
||||
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", "昨左佐做作坐座撮琢柞"},
|
||||
{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.
|
||||
|
||||
|
||||
.. _ime_pinyin_apply_new_dictionary:
|
||||
|
||||
Apply new dictionary
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Applying a new dictionary
|
||||
-------------------------
|
||||
|
||||
After writing a dictionary according to the above dictionary format, you
|
||||
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);
|
||||
|
||||
|
||||
|
||||
.. _ime_pinyin_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_K9`: Pinyin 9 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_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)`.
|
||||
The default mode is :cpp:enumerator:`LV_IME_PINYIN_MODE_K26`.
|
||||
|
||||
|
||||
|
||||
.. _ime_pinyin_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
*******
|
||||
|
||||
.. include:: ../../examples/others/ime/index.rst
|
||||
|
||||
|
||||
|
||||
.. _ime_pinyin_api:
|
||||
|
||||
API
|
||||
---
|
||||
***
|
||||
|
||||
|
@ -9,18 +9,26 @@ display Unicode emoji icons in text.
|
||||
|
||||
Supported image formats: determined by enabled LVGL :ref:`image decoders <overview_image_decoder>`.
|
||||
|
||||
|
||||
|
||||
.. _lv_imgfont_usage:
|
||||
|
||||
Usage
|
||||
-----
|
||||
*****
|
||||
|
||||
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.
|
||||
- ``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.
|
||||
|
||||
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)`.
|
||||
|
||||
|
||||
|
||||
.. _lv_imgfont_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
*******
|
||||
|
||||
.. include:: ../../examples/others/imgfont/index.rst
|
||||
|
||||
|
||||
|
||||
.. _lv_imgfont_api:
|
||||
|
||||
API
|
||||
---
|
||||
***
|
||||
|
@ -4,28 +4,38 @@
|
||||
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:
|
||||
|
||||
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
|
||||
configuration structure, set the ``type`` (check :ref:`Input Devices <indev>`
|
||||
for the supported types), and then set the
|
||||
range of ``period_range`` and ``input_range``, the monkey will output
|
||||
random operations at random times within this range. Call
|
||||
:cpp:func:`lv_monkey_create` to create monkey. Finally call
|
||||
:cpp:expr:`lv_monkey_set_enable(monkey, true)` to enable monkey.
|
||||
Next, declare a variable (it can be local) of type :c:type:`lv_monkey_config_t` to
|
||||
define the configuration structure, initialize it using
|
||||
:cpp:expr:`lv_monkey_config_init(cfg)` then set its ``type`` member to the desired
|
||||
type of :ref:`input device <indev>`, and set the ``min`` and ``max`` values for its
|
||||
``period_range`` and ``input_range`` members to set the time ranges (in milliseconds)
|
||||
and input ranges the Monkey module will use to generate random input at random times.
|
||||
|
||||
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
|
||||
: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)`.
|
||||
|
||||
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_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:enumerator:`LV_INDEV_TYPE_KEYPAD`: No effect, Send random :ref:`indev_keys`.
|
||||
|
||||
|
||||
|
||||
.. _monkey_example:
|
||||
|
||||
Example
|
||||
-------
|
||||
*******
|
||||
|
||||
.. include:: ../../examples/others/monkey/index.rst
|
||||
|
||||
|
||||
|
||||
.. _monkey_api:
|
||||
|
||||
API
|
||||
---
|
||||
***
|
||||
|
||||
|
@ -1,66 +1,196 @@
|
||||
.. _obj_id:
|
||||
.. _widget_id:
|
||||
|
||||
=========
|
||||
Widget ID
|
||||
=========
|
||||
|
||||
LVGL provides an optional field in :cpp:type:`lv_obj_t` to store the Widget ID.
|
||||
Widget ID can be used in many cases, for example, to identify the Widget.
|
||||
Or we can store a program backtrace to where the Widget is created.
|
||||
Widgets can optionally have identifiers added to their functionality if needed for
|
||||
the application. Exactly how that happens is designed to be flexible, and can morph
|
||||
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
|
||||
-----
|
||||
*****
|
||||
|
||||
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.
|
||||
It's done by calling function :cpp:func:`lv_obj_assign_id` from :cpp:func:`lv_obj_constructor`.
|
||||
Once enabled, several things change:
|
||||
|
||||
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.
|
||||
To use the builtin ID generator, set :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `1`.
|
||||
- each Widget will now have a ``void *`` field called ``id``;
|
||||
- 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)`
|
||||
to get a string representation of the ID.
|
||||
- :cpp:expr:`lv_obj_get_id(widget)`,
|
||||
- :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
|
||||
|
||||
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);
|
||||
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
|
||||
parameter ``class_p``. Note it may be different than :cpp:expr:`obj->class_p` which is the class
|
||||
currently being constructed.
|
||||
Examples of implementations of these functions exist in ``lv_obj_id_builtin.c``, but
|
||||
you are free to use a different design if needed.
|
||||
|
||||
: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.
|
||||
It will walk through all children and print the Widget ID together with Widget address.
|
||||
If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value,
|
||||
: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
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
: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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user