1.. _widget_id: 2 3========= 4Widget ID 5========= 6 7Widgets can optionally have identifiers added to their functionality if needed for 8the application. Exactly how that happens is designed to be flexible, and can morph 9with the needs of the application. It can even be a timestamp or other data current 10at the time the Widget was created. 11 12 13 14.. _widget_id_usage: 15 16Usage 17***** 18 19Enable Widget ID functionality by setting :c:macro:`LV_USE_OBJ_ID` to ``1`` in ``lv_conf.h``. 20 21Once enabled, several things change: 22 23- each Widget will now have a ``void *`` field called ``id``; 24- these two API functions become available: 25 26 - :cpp:expr:`lv_obj_get_id(widget)`, 27 - :cpp:expr:`lv_obj_get_child_by_id(widget, id)`; 28 29- several more Widget-ID-related API functions become available if 30 :c:macro:`LV_USE_OBJ_ID_BUILTIN` is non-zero (more on this below); 31- two additional configuration macros both :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` and 32 :c:macro:`LV_USE_OBJ_ID_BUILTIN` now have meaning. 33 34 35:c:macro:`LV_OBJ_ID_AUTO_ASSIGN` 36-------------------------------- 37 38This macro in ``lv_conf.h`` defaults to whatever value :c:macro:`LV_USE_OBJ_ID` 39equates to. You can change this if you wish. Either way, if it equates to a 40non-zero value, it causes two things to happen: 41 42- :cpp:expr:`lv_obj_assign_id(class_p, widget)` will be called at the end of each 43 Widget's creation, and 44- :cpp:expr:`lv_obj_free_id(widget)` will be called at the end of the sequence when 45 each Widget is deleted. 46 47Because of this timing, custom versions of these functions can be used according to 48the below, and they can even be used like "event hooks" to implement a trace 49operation that occurs when each Widget is created and deleted. 50 51:cpp:expr:`lv_obj_assign_id(class_p, widget)` 52~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 54This function (whether provided by LVGL or by you --- more on this below) is 55responsible for assigning a value to the Widget's ``id`` field, and possibly do 56other things, depending on the implementation. 57 58:cpp:expr:`lv_obj_free_id(widget)` 59~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 61This function (whether provided by LVGL or by you --- more on this below) is 62responsible for doing the clean-up of any resources allocated by 63:cpp:func:`lv_obj_assign_id()` 64 65 66:c:macro:`LV_USE_OBJ_ID_BUILTIN` 67-------------------------------- 68 69This macro in ``lv_conf.h`` equates to ``1`` by default. You can change this if you 70wish. When it equates to a non-zero value the following function implementations are 71provided by LVGL: 72 73- :cpp:expr:`lv_obj_assign_id(class_p, widget)` 74- :cpp:expr:`lv_obj_free_id(widget)` 75- :cpp:expr:`lv_obj_set_id(widget, id)` 76- :cpp:expr:`lv_obj_stringify_id(widget, buf, len)` 77- :cpp:expr:`lv_obj_id_compare(id1, id2)` 78 79These supply the default implementation for Widget IDs, namely that for each Widget 80created, :cpp:expr:`lv_obj_stringify_id(widget, buf, len)` will produce a unique 81string for it. Example: if the following 6 Widgets are created in this sequence: 82 83- Screen 84- Label 85- Button 86- Label 87- Label 88- Image 89 90the strings produced by :cpp:expr:`lv_obj_stringify_id(widget, buf, len)` would be 91 92- obj1 93- label1 94- btn1 95- label2 96- label3 97- image1 98 99respectively. 100 101 102.. _widget_id_custom_generator: 103 104Using a custom ID generator 105--------------------------- 106 107If you wish, you can provide custom implementations for several Widget-ID related 108functions. You do this by first setting :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `0` in 109``lv_conf.h``. 110 111You will then need to provide implementations for the following functions (and link 112them with LVGL): 113 114.. code-block:: c 115 116 const char * lv_obj_stringify_id(lv_obj_t * widget, char * buf, uint32_t len); 117 int lv_obj_id_compare(const void * id1, const void * id2); 118 119If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value (or if you otherwise 120simply need to use them), you will also need to provide implementations for: 121 122.. code-block:: c 123 124 void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * widget); 125 void lv_obj_free_id(lv_obj_t * widget); 126 127If :c:macro:`LV_BUILD_TEST` equates to a non-zero value and you are including LVGL 128test code in your compile (or if you otherwise simply need to use them), you 129will also need to provide an implementation for: 130 131.. code-block:: c 132 133 void lv_obj_set_id(lv_obj_t * widget, void * id); 134 135 136Examples of implementations of these functions exist in ``lv_obj_id_builtin.c``, but 137you are free to use a different design if needed. 138 139:cpp:func:`lv_obj_stringify_id` converts the passed ``widget`` to a string 140representation (typically incorporating the ``id`` field) and writes it into the 141buffer provided in its ``buf`` argument. 142 143:cpp:func:`lv_obj_id_compare` compares 2 ``void * id`` values and returns ``0`` when 144they are considered equal, and non-zero otherwise. 145 146If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value, 147:cpp:func:`lv_obj_assign_id` is called when a Widget is created. It is responsible 148for assigning a value to the Widget's ``id`` field. A pointer to the Widget's final 149class is passed in its ``class_p`` argument in case it is needed for determining the 150value for the ``id`` field, or for other possible needs related to your design for 151Widget IDs. Note that this pointer may be different than :cpp:expr:`widget->class_p` 152which is the class of the Widget currently being created. 153 154If :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` equates to a non-zero value, 155:cpp:func:`lv_obj_free_id` is called when a Widget is deleted. It needs to perform 156the clean-up for any resources allocated by :cpp:func:`lv_obj_assign_id`. 157 158 159Dumping a Widget Tree 160--------------------- 161 162Regardless of the state of any of the above macros, the function 163:cpp:expr:`lv_obj_dump_tree(widget)` provides a "dump" of the Widget Tree for the 164specified Widget (that Widget plus all its children recursively) using the 165currently-configured method used by the :c:macro:`LV_LOG_USER` macro. If NULL is 166passed instead of a pointer to a "root" Widget, the dump will include the Widget Tree 167for all :ref:`Screens`, for all :ref:`Displays <display>` in the system. 168 169For :c:macro:`LV_LOG_USER` to produce output, the following needs to be true in 170``lv_conf.h``: 171 172- :c:macro:`LV_USE_LOG` must equate to a non-zero value 173- :c:macro:`LV_LOG_LEVEL` <= :c:macro:`LV_LOG_LEVEL_USER` 174 175It will recursively walk through all that Widget's children (starting with the Widget 176itself) and print the Widget's parent's address, the Widget's address, and if 177:c:macro:`LV_USE_OBJ_ID` equates to a non-zero value, will also print the output of 178:cpp:func:`lv_obj_stringify_id` for that Widget. 179 180This can be useful in the event of a UI crash. From that log you can examine the 181state of the Widget Tree when :cpp:expr:`lv_obj_dump_tree(widget)` was called. 182 183For example, if a pointer to a deleted Widget is stored in a Timer's 184:cpp:expr:`timer->user_data` field when the timer event callback is called, attempted 185use of that pointer will likly cause a crash because the pointer is not valid any 186more. However, a timely dump of the Widget Tree right before that point will show 187that the Widget no longer exists. 188 189 190Find child by ID 191---------------- 192 193:cpp:expr:`lv_obj_get_child_by_id(widget, id)` will perform a recursive walk through 194``widget``\ 's children and return the first child encountered having the given ID. 195 196 197