feat(obj): add API to set/get object ID. (#6278)
Signed-off-by: Neo Xu <neo.xu1990@gmail.com>
This commit is contained in:
@@ -290,6 +290,9 @@
|
|||||||
/* Add `id` field to `lv_obj_t` */
|
/* Add `id` field to `lv_obj_t` */
|
||||||
#define LV_USE_OBJ_ID 0
|
#define LV_USE_OBJ_ID 0
|
||||||
|
|
||||||
|
/* Automatically assign an ID when obj is created */
|
||||||
|
#define LV_OBJ_ID_AUTO_ASSIGN 1
|
||||||
|
|
||||||
/* Use lvgl builtin method for obj ID */
|
/* Use lvgl builtin method for obj ID */
|
||||||
#define LV_USE_OBJ_ID_BUILTIN 0
|
#define LV_USE_OBJ_ID_BUILTIN 0
|
||||||
|
|
||||||
|
|||||||
6
Kconfig
6
Kconfig
@@ -612,9 +612,15 @@ menu "LVGL configuration"
|
|||||||
bool "Add id field to obj"
|
bool "Add id field to obj"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config LV_OBJ_ID_AUTO_ASSIGN
|
||||||
|
bool "Automatically assign an ID when obj is created"
|
||||||
|
default y
|
||||||
|
depends on LV_USE_OBJ_ID
|
||||||
|
|
||||||
config LV_USE_OBJ_ID_BUILTIN
|
config LV_USE_OBJ_ID_BUILTIN
|
||||||
bool "Use builtin method to deal with obj ID"
|
bool "Use builtin method to deal with obj ID"
|
||||||
default n
|
default n
|
||||||
|
depends on LV_USE_OBJ_ID
|
||||||
|
|
||||||
config LV_USE_OBJ_PROPERTY
|
config LV_USE_OBJ_PROPERTY
|
||||||
bool "Use obj property set/get API"
|
bool "Use obj property set/get API"
|
||||||
|
|||||||
@@ -14,19 +14,20 @@ Usage
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
Enable this feature by setting :c:macro:`LV_USE_OBJ_ID` to `1` in ``lv_conf.h``.
|
Enable this feature by setting :c:macro:`LV_USE_OBJ_ID` to `1` in ``lv_conf.h``.
|
||||||
Use the builtin obj ID generator by setting :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `1`.
|
|
||||||
Otherwise provide your own custom implementation.
|
|
||||||
|
|
||||||
The ID is automatically generated and assigned to :cpp:expr:`obj->id` during obj's
|
Enable :c:macro:`LV_OBJ_ID_AUTO_ASSIGN` to automatically assign an ID to object when it's created.
|
||||||
construction by calling API :cpp:expr:`lv_obj_assign_id(obj)` from :cpp:func:`lv_obj_constructor`.
|
It's done by calling function :cpp:func:`lv_obj_assign_id` from :cpp:func:`lv_obj_constructor`.
|
||||||
|
|
||||||
You can directly access the ID by :cpp:expr:`obj->id` or use API :cpp:expr:`lv_obj_stringify_id(obj, buf, len)`
|
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`.
|
||||||
|
|
||||||
|
You can directly access the ID by :cpp:expr:`lv_obj_get_id(obj)` or use API :cpp:expr:`lv_obj_stringify_id(obj, buf, len)`
|
||||||
to get a string representation of the ID.
|
to get a string representation of the ID.
|
||||||
|
|
||||||
Use custom ID generator
|
Use custom ID generator
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Set :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `0` in ``lv_conf.h``.
|
Set :c:macro:`LV_USE_OBJ_ID_BUILTIN` to `0` in ``lv_conf.h``.
|
||||||
|
|
||||||
Below APIs needed to be implemented and linked to lvgl.
|
Below APIs needed to be implemented and linked to lvgl.
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ Below APIs needed to be implemented and linked to lvgl.
|
|||||||
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||||
void lv_obj_free_id(lv_obj_t * obj);
|
void lv_obj_free_id(lv_obj_t * obj);
|
||||||
const char * lv_obj_stringify_id(lv_obj_t * obj, char * buf, uint32_t len);
|
const char * lv_obj_stringify_id(lv_obj_t * obj, char * buf, uint32_t len);
|
||||||
|
int lv_obj_id_compare(void * id1, void * id2);
|
||||||
|
|
||||||
|
|
||||||
:cpp:func:`lv_obj_assign_id` is called when an object is created. The object final class is passed from
|
:cpp:func:`lv_obj_assign_id` is called when an object is created. The object final class is passed from
|
||||||
@@ -55,3 +57,9 @@ This is useful to debug UI crash. From log we can rebuilt UI the moment before c
|
|||||||
For example, if the obj is stored to a :cpp:expr:`timer->user_data`, but obj is deleted when timer expired.
|
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.
|
Timer callback will crash because of accessing wild pointer.
|
||||||
From the dump log we can clearly see that the obj does not exist.
|
From the dump log we can clearly see that the obj does not exist.
|
||||||
|
|
||||||
|
Find child by ID
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Use API :cpp:expr:`lv_obj_t * lv_obj_get_child_by_id(const lv_obj_t * obj, void * id);` to find a child by ID.
|
||||||
|
It will walk through all children and return the first child with the given ID.
|
||||||
|
|||||||
@@ -312,6 +312,9 @@
|
|||||||
/* Add `id` field to `lv_obj_t` */
|
/* Add `id` field to `lv_obj_t` */
|
||||||
#define LV_USE_OBJ_ID 0
|
#define LV_USE_OBJ_ID 0
|
||||||
|
|
||||||
|
/* Automatically assign an ID when obj is created */
|
||||||
|
#define LV_OBJ_ID_AUTO_ASSIGN 1
|
||||||
|
|
||||||
/* Use lvgl builtin method for obj ID */
|
/* Use lvgl builtin method for obj ID */
|
||||||
#define LV_USE_OBJ_ID_BUILTIN 0
|
#define LV_USE_OBJ_ID_BUILTIN 0
|
||||||
|
|
||||||
|
|||||||
@@ -353,8 +353,16 @@
|
|||||||
/* Add `id` field to `lv_obj_t` */
|
/* Add `id` field to `lv_obj_t` */
|
||||||
#define LV_USE_OBJ_ID 0
|
#define LV_USE_OBJ_ID 0
|
||||||
|
|
||||||
/* Use lvgl builtin method for obj ID */
|
/* Automatically assign an ID when obj is created */
|
||||||
#define LV_USE_OBJ_ID_BUILTIN 0
|
#define LV_OBJ_ID_AUTO_ASSIGN LV_USE_OBJ_ID
|
||||||
|
|
||||||
|
/*Use the builtin obj ID handler functions:
|
||||||
|
* - lv_obj_assign_id: Called when a widget is created. Use a separate counter for each widget class as an ID.
|
||||||
|
* - lv_obj_id_compare: Compare the ID to decide if it matches with a requested value.
|
||||||
|
* - lv_obj_stringify_id: Return e.g. "button3"
|
||||||
|
* - lv_obj_free_id: Does nothing, as there is no memory allocation for the ID.
|
||||||
|
* When disabled these functions needs to be implemented by the user.*/
|
||||||
|
#define LV_USE_OBJ_ID_BUILTIN 1
|
||||||
|
|
||||||
/*Use obj property set/get API*/
|
/*Use obj property set/get API*/
|
||||||
#define LV_USE_OBJ_PROPERTY 0
|
#define LV_USE_OBJ_PROPERTY 0
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ static void draw_scrollbar(lv_obj_t * obj, lv_layer_t * layer);
|
|||||||
static lv_result_t scrollbar_init_draw_dsc(lv_obj_t * obj, lv_draw_rect_dsc_t * dsc);
|
static lv_result_t scrollbar_init_draw_dsc(lv_obj_t * obj, lv_draw_rect_dsc_t * dsc);
|
||||||
static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find);
|
static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find);
|
||||||
static void update_obj_state(lv_obj_t * obj, lv_state_t new_state);
|
static void update_obj_state(lv_obj_t * obj, lv_state_t new_state);
|
||||||
|
|
||||||
#if LV_USE_OBJ_PROPERTY
|
#if LV_USE_OBJ_PROPERTY
|
||||||
static lv_result_t lv_obj_set_any(lv_obj_t *, lv_prop_id_t, const lv_property_t *);
|
static lv_result_t lv_obj_set_any(lv_obj_t *, lv_prop_id_t, const lv_property_t *);
|
||||||
static lv_result_t lv_obj_get_any(const lv_obj_t *, lv_prop_id_t, lv_property_t *);
|
static lv_result_t lv_obj_get_any(const lv_obj_t *, lv_prop_id_t, lv_property_t *);
|
||||||
@@ -311,6 +312,42 @@ bool lv_obj_is_valid(const lv_obj_t * obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_OBJ_ID
|
||||||
|
void lv_obj_set_id(lv_obj_t * obj, void * id)
|
||||||
|
{
|
||||||
|
LV_ASSERT_NULL(obj);
|
||||||
|
obj->id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * lv_obj_get_id(const lv_obj_t * obj)
|
||||||
|
{
|
||||||
|
LV_ASSERT_NULL(obj);
|
||||||
|
return obj->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_t * lv_obj_get_child_by_id(const lv_obj_t * obj, void * id)
|
||||||
|
{
|
||||||
|
if(obj == NULL) obj = lv_display_get_screen_active(NULL);
|
||||||
|
if(obj == NULL) return NULL;
|
||||||
|
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t child_cnt = lv_obj_get_child_count(obj);
|
||||||
|
for(i = 0; i < child_cnt; i++) {
|
||||||
|
lv_obj_t * child = obj->spec_attr->children[i];
|
||||||
|
if(lv_obj_id_compare(child->id, id) == 0) return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Search children*/
|
||||||
|
for(i = 0; i < child_cnt; i++) {
|
||||||
|
lv_obj_t * child = obj->spec_attr->children[i];
|
||||||
|
lv_obj_t * found = lv_obj_get_child_by_id(child, id);
|
||||||
|
if(found != NULL) return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC FUNCTIONS
|
* STATIC FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
@@ -343,7 +380,7 @@ static void lv_obj_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
|||||||
obj->flags |= LV_OBJ_FLAG_SCROLL_WITH_ARROW;
|
obj->flags |= LV_OBJ_FLAG_SCROLL_WITH_ARROW;
|
||||||
if(parent) obj->flags |= LV_OBJ_FLAG_GESTURE_BUBBLE;
|
if(parent) obj->flags |= LV_OBJ_FLAG_GESTURE_BUBBLE;
|
||||||
|
|
||||||
#if LV_USE_OBJ_ID
|
#if LV_OBJ_ID_AUTO_ASSIGN
|
||||||
lv_obj_assign_id(class_p, obj);
|
lv_obj_assign_id(class_p, obj);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -380,7 +417,7 @@ static void lv_obj_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
|||||||
obj->spec_attr = NULL;
|
obj->spec_attr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LV_USE_OBJ_ID
|
#if LV_OBJ_ID_AUTO_ASSIGN
|
||||||
lv_obj_free_id(obj);
|
lv_obj_free_id(obj);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -405,11 +405,38 @@ const lv_obj_class_t * lv_obj_get_class(const lv_obj_t * obj);
|
|||||||
bool lv_obj_is_valid(const lv_obj_t * obj);
|
bool lv_obj_is_valid(const lv_obj_t * obj);
|
||||||
|
|
||||||
#if LV_USE_OBJ_ID
|
#if LV_USE_OBJ_ID
|
||||||
|
/**
|
||||||
|
* Set an id for an object.
|
||||||
|
* @param obj pointer to an object
|
||||||
|
* @param id the id of the object
|
||||||
|
*/
|
||||||
|
void lv_obj_set_id(lv_obj_t * obj, void * id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign an id to an object if not previously assigned
|
* Get the id of an object.
|
||||||
* Set `LV_USE_OBJ_ID_BUILTIN` to 1 to use builtin method to generate object ID.
|
* @param obj pointer to an object
|
||||||
* Otherwise, these functions including `lv_obj_[assign|free|stringify]_id` should be implemented externally.
|
* @return the id of the object
|
||||||
|
*/
|
||||||
|
void * lv_obj_get_id(const lv_obj_t * obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the child object by its id.
|
||||||
|
* It will check children and grandchildren recursively.
|
||||||
|
* Function `lv_obj_id_compare` is used to matched obj id with given id.
|
||||||
|
*
|
||||||
|
* @param obj pointer to an object
|
||||||
|
* @param id the id of the child object
|
||||||
|
* @return pointer to the child object or NULL if not found
|
||||||
|
*/
|
||||||
|
lv_obj_t * lv_obj_get_child_by_id(const lv_obj_t * obj, void * id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign id to object if not previously assigned.
|
||||||
|
* This function gets called automatically when LV_OBJ_ID_AUTO_ASSIGN is enabled.
|
||||||
|
*
|
||||||
|
* Set `LV_USE_OBJ_ID_BUILTIN` to use the builtin method to generate object ID.
|
||||||
|
* Otherwise, these functions including `lv_obj_[assign|free|stringify]_id` and
|
||||||
|
* `lv_obj_id_compare`should be implemented externally.
|
||||||
*
|
*
|
||||||
* @param class_p the class this obj belongs to. Note obj->class_p is the class currently being constructed.
|
* @param class_p the class this obj belongs to. Note obj->class_p is the class currently being constructed.
|
||||||
* @param obj pointer to an object
|
* @param obj pointer to an object
|
||||||
@@ -417,11 +444,24 @@ bool lv_obj_is_valid(const lv_obj_t * obj);
|
|||||||
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free resources allocated by `lv_obj_assign_id`
|
* Free resources allocated by `lv_obj_assign_id`.
|
||||||
|
* This function gets called automatically when object is deleted.
|
||||||
* @param obj pointer to an object
|
* @param obj pointer to an object
|
||||||
*/
|
*/
|
||||||
void lv_obj_free_id(lv_obj_t * obj);
|
void lv_obj_free_id(lv_obj_t * obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two obj id, return 0 if they are equal.
|
||||||
|
*
|
||||||
|
* Set `LV_USE_OBJ_ID_BUILTIN` to use the builtin method for compare.
|
||||||
|
* Otherwise, it must be implemented externally.
|
||||||
|
*
|
||||||
|
* @param id1: the first id
|
||||||
|
* @param id2: the second id
|
||||||
|
* @return 0 if they are equal, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int lv_obj_id_compare(void * id1, void * id2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format an object's id into a string.
|
* Format an object's id into a string.
|
||||||
* @param obj pointer to an object
|
* @param obj pointer to an object
|
||||||
@@ -435,7 +475,6 @@ const char * lv_obj_stringify_id(lv_obj_t * obj, char * buf, uint32_t len);
|
|||||||
* Free resources used by builtin ID generator.
|
* Free resources used by builtin ID generator.
|
||||||
*/
|
*/
|
||||||
void lv_objid_builtin_destroy(void);
|
void lv_objid_builtin_destroy(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /*LV_USE_OBJ_ID*/
|
#endif /*LV_USE_OBJ_ID*/
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ typedef struct _class_info_t {
|
|||||||
* GLOBAL FUNCTIONS
|
* GLOBAL FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
#if LV_USE_OBJ_ID_BUILTIN
|
#if LV_USE_OBJ_ID && LV_USE_OBJ_ID_BUILTIN
|
||||||
|
|
||||||
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||||
{
|
{
|
||||||
@@ -105,4 +105,9 @@ void lv_objid_builtin_destroy(void)
|
|||||||
global->objid_count = 0;
|
global->objid_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lv_obj_id_compare(void * id1, void * id2)
|
||||||
|
{
|
||||||
|
return id1 == id2 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /*LV_USE_OBJ_ID_BUILTIN*/
|
#endif /*LV_USE_OBJ_ID_BUILTIN*/
|
||||||
|
|||||||
@@ -1042,12 +1042,30 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Use lvgl builtin method for obj ID */
|
/* Automatically assign an ID when obj is created */
|
||||||
#ifndef LV_USE_OBJ_ID_BUILTIN
|
#ifndef LV_OBJ_ID_AUTO_ASSIGN
|
||||||
#ifdef CONFIG_LV_USE_OBJ_ID_BUILTIN
|
#ifdef CONFIG_LV_OBJ_ID_AUTO_ASSIGN
|
||||||
#define LV_USE_OBJ_ID_BUILTIN CONFIG_LV_USE_OBJ_ID_BUILTIN
|
#define LV_OBJ_ID_AUTO_ASSIGN CONFIG_LV_OBJ_ID_AUTO_ASSIGN
|
||||||
#else
|
#else
|
||||||
#define LV_USE_OBJ_ID_BUILTIN 0
|
#define LV_OBJ_ID_AUTO_ASSIGN LV_USE_OBJ_ID
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*Use the builtin obj ID handler functions:
|
||||||
|
* - lv_obj_assign_id: Called when a widget is created. Use a separate counter for each widget class as an ID.
|
||||||
|
* - lv_obj_id_compare: Compare the ID to decide if it matches with a requested value.
|
||||||
|
* - lv_obj_stringify_id: Return e.g. "button3"
|
||||||
|
* - lv_obj_free_id: Does nothing, as there is no memory allocation for the ID.
|
||||||
|
* When disabled these functions needs to be implemented by the user.*/
|
||||||
|
#ifndef LV_USE_OBJ_ID_BUILTIN
|
||||||
|
#ifdef _LV_KCONFIG_PRESENT
|
||||||
|
#ifdef CONFIG_LV_USE_OBJ_ID_BUILTIN
|
||||||
|
#define LV_USE_OBJ_ID_BUILTIN CONFIG_LV_USE_OBJ_ID_BUILTIN
|
||||||
|
#else
|
||||||
|
#define LV_USE_OBJ_ID_BUILTIN 0
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define LV_USE_OBJ_ID_BUILTIN 1
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ void lv_deinit(void)
|
|||||||
lv_profiler_builtin_uninit();
|
lv_profiler_builtin_uninit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LV_USE_OBJ_ID_BUILTIN
|
#if LV_USE_OBJ_ID && LV_USE_OBJ_ID_BUILTIN
|
||||||
lv_objid_builtin_destroy();
|
lv_objid_builtin_destroy();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
#define LV_USE_DEMO_VECTOR_GRAPHIC 1
|
#define LV_USE_DEMO_VECTOR_GRAPHIC 1
|
||||||
|
|
||||||
#define LV_USE_OBJ_ID 1
|
#define LV_USE_OBJ_ID 1
|
||||||
|
#define LV_OBJ_ID_AUTO_ASSIGN 1
|
||||||
#define LV_USE_OBJ_ID_BUILTIN 1
|
#define LV_USE_OBJ_ID_BUILTIN 1
|
||||||
|
|
||||||
#define LV_CACHE_DEF_SIZE (10 * 1024 * 1024)
|
#define LV_CACHE_DEF_SIZE (10 * 1024 * 1024)
|
||||||
|
|||||||
@@ -27,4 +27,17 @@ void test_obj_id_should_grow_by_one(void)
|
|||||||
TEST_ASSERT_EQUAL(id1 + 1, id2);
|
TEST_ASSERT_EQUAL(id1 + 1, id2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_obj_id_get_child(void)
|
||||||
|
{
|
||||||
|
lv_obj_t * parent = lv_obj_create(lv_screen_active());
|
||||||
|
lv_obj_t * child = lv_label_create(parent);
|
||||||
|
lv_obj_t * grandchild = lv_label_create(child);
|
||||||
|
|
||||||
|
lv_obj_set_id(child, (void *)(lv_uintptr_t)1);
|
||||||
|
lv_obj_set_id(grandchild, (void *)(lv_uintptr_t)2);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_PTR(child, lv_obj_get_child_by_id(NULL, (void *)(lv_uintptr_t)1));
|
||||||
|
TEST_ASSERT_EQUAL_PTR(grandchild, lv_obj_get_child_by_id(NULL, (void *)(lv_uintptr_t)2));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user