From 5f5c74c088b7bd67d2f7657740bb1cc9bfab572b Mon Sep 17 00:00:00 2001 From: Victor Wheeler Date: Wed, 15 Jan 2025 00:48:25 -0700 Subject: [PATCH] feat(docs): batch 14 of proofread/edited docs (#7477) --- docs/details/main-components/image.rst | 35 ++-- docs/details/other-components/fragment.rst | 22 +- docs/details/other-components/gridnav.rst | 46 +++-- docs/details/other-components/ime_pinyin.rst | 65 +++--- docs/details/other-components/imgfont.rst | 22 +- docs/details/other-components/monkey.rst | 42 ++-- docs/details/other-components/obj_id.rst | 204 +++++++++++++++---- 7 files changed, 307 insertions(+), 129 deletions(-) diff --git a/docs/details/main-components/image.rst b/docs/details/main-components/image.rst index 3eb9619d6..a89edf520 100644 --- a/docs/details/main-components/image.rst +++ b/docs/details/main-components/image.rst @@ -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. diff --git a/docs/details/other-components/fragment.rst b/docs/details/other-components/fragment.rst index 55db7e16b..29d18016a 100644 --- a/docs/details/other-components/fragment.rst +++ b/docs/details/other-components/fragment.rst @@ -18,19 +18,21 @@ Such concept also has some similarities to `UiViewController on iOS `__. 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 ---- +*** diff --git a/docs/details/other-components/gridnav.rst b/docs/details/other-components/gridnav.rst index 04730d9b3..07c235a17 100644 --- a/docs/details/other-components/gridnav.rst +++ b/docs/details/other-components/gridnav.rst @@ -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 `. +column. This is useful, for example, to simplify navigation among items in a +:ref:`List Widget `. Gridnav assumes that the Widget to which gridnav is added is part of a :ref:`group `. 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 ---- +*** diff --git a/docs/details/other-components/ime_pinyin.rst b/docs/details/other-components/ime_pinyin.rst index 25382fe0e..dd15e1a4f 100644 --- a/docs/details/other-components/ime_pinyin.rst +++ b/docs/details/other-components/ime_pinyin.rst @@ -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 `__ 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 ---- +*** diff --git a/docs/details/other-components/imgfont.rst b/docs/details/other-components/imgfont.rst index f769ad93c..b0af49369 100644 --- a/docs/details/other-components/imgfont.rst +++ b/docs/details/other-components/imgfont.rst @@ -9,18 +9,26 @@ display Unicode emoji icons in text. Supported image formats: determined by enabled LVGL :ref:`image decoders `. + + .. _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 ---- +*** diff --git a/docs/details/other-components/monkey.rst b/docs/details/other-components/monkey.rst index 9624610ee..a706f1403 100644 --- a/docs/details/other-components/monkey.rst +++ b/docs/details/other-components/monkey.rst @@ -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 ` -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 `, 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 ---- +*** diff --git a/docs/details/other-components/obj_id.rst b/docs/details/other-components/obj_id.rst index bb7c91779..2306af349 100644 --- a/docs/details/other-components/obj_id.rst +++ b/docs/details/other-components/obj_id.rst @@ -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 ` 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.