mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-30 07:06:19 +08:00
feat(obj_name): add auto-indexing with names like 'mybtn_#'
This commit is contained in:
committed by
Liam Howatt
parent
5652914e14
commit
e4bbc4f0fa
@@ -0,0 +1,35 @@
|
||||
diff --git a/src/draw/opengles/lv_draw_opengles.c b/src/draw/opengles/lv_draw_opengles.c
|
||||
index b3f2122a7..bfb167bc9 100644
|
||||
--- a/src/draw/opengles/lv_draw_opengles.c
|
||||
+++ b/src/draw/opengles/lv_draw_opengles.c
|
||||
@@ -275,6 +275,10 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
}
|
||||
|
||||
+ lv_draw_dsc_base_t * base_dsc = task->draw_dsc;
|
||||
+ cache_data->draw_dsc = lv_malloc(base_dsc->dsc_size);
|
||||
+ lv_memcpy((void *)cache_data->draw_dsc, base_dsc, base_dsc->dsc_size);
|
||||
+
|
||||
switch(task->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
lv_draw_fill_dsc_t * fill_dsc = task->draw_dsc;
|
||||
@@ -355,6 +359,8 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
break;
|
||||
}
|
||||
default:
|
||||
+ /*The malloced cache_data->draw_dsc will be freed automatically on failure
|
||||
+ *in opengles_texture_cache_free_cb*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -367,10 +373,7 @@ static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_da
|
||||
|
||||
unsigned int texture = create_texture(texture_w, texture_h, u->render_draw_buf.data);
|
||||
|
||||
- lv_draw_dsc_base_t * base_dsc = task->draw_dsc;
|
||||
|
||||
- cache_data->draw_dsc = lv_malloc(base_dsc->dsc_size);
|
||||
- lv_memcpy((void *)cache_data->draw_dsc, base_dsc, base_dsc->dsc_size);
|
||||
cache_data->w = texture_w;
|
||||
cache_data->h = texture_h;
|
||||
cache_data->texture = texture;
|
||||
@@ -577,9 +577,87 @@ more on encoder behaviors and the edit mode.
|
||||
|
||||
Learn more about :ref:`indev_keys`.
|
||||
|
||||
.. _widget_names:
|
||||
|
||||
Names
|
||||
*****
|
||||
|
||||
When a widget is created, its reference can be stored in an :cpp:expr:`lv_obj_t *` pointer
|
||||
variable. To use this widget in multiple places in the code, the variable can be passed
|
||||
as a function parameter or made a global variable. However, this approach has some drawbacks:
|
||||
|
||||
- Using global variables is not clean and generally not recommended.
|
||||
- It's not scalable. Passing references to 20 widgets as function parameters is not ideal.
|
||||
- It's hard to track whether a widget still exists or has been deleted.
|
||||
|
||||
Setting names
|
||||
-------------
|
||||
|
||||
To address these issues, LVGL introduces a powerful widget naming system that can be enabled
|
||||
by setting ``LV_USE_OBJ_NAME`` in ``lv_conf.h``.
|
||||
|
||||
A custom name can be assigned using :cpp:expr:`lv_obj_set_name(obj, "name")` or
|
||||
:cpp:expr:`lv_obj_set_name_static(obj, "name")`. The "static" variant means the passed name
|
||||
must remain valid while the widget exists, as only the pointer is stored. Otherwise, LVGL will
|
||||
allocate memory to store a copy of the name.
|
||||
|
||||
If a name ends with ``#``, LVGL will automatically replace it with an index based on the
|
||||
number of siblings with the same base name. If no name is provided, the default is
|
||||
``<widget_type>_#``.
|
||||
|
||||
Below is an example showing how manually and automatically assigned names are resolved:
|
||||
|
||||
- Main ``lv_obj`` container named ``"cont"``: "cont"
|
||||
- ``lv_obj`` container named ``"header"``: "header"
|
||||
- ``lv_label`` with no name: "lv_label_0"
|
||||
- ``lv_label`` named ``"title"``: "title"
|
||||
- ``lv_label`` with no name: "lv_label_1" (It's the third label, but custom-named widgets are not counted)
|
||||
- ``lv_obj`` container named ``"buttons"``:
|
||||
- ``lv_button`` with no name: "lv_button_0"
|
||||
- ``lv_button`` named ``"second_button"``: "second_button"
|
||||
- ``lv_button`` with no name: "lv_button_1"
|
||||
- ``lv_button`` named ``lv_button_#``: "lv_button_2"
|
||||
- ``lv_button`` named ``mybtn_#``: "mybtn_0"
|
||||
- ``lv_button`` with no name: "lv_button_2"
|
||||
- ``lv_button`` named ``mybtn_#``: "mybtn_1"
|
||||
- ``lv_button`` named ``mybtn_#``: "mybtn_2"
|
||||
- ``lv_button`` named ``mybtn_#``: "mybtn_3"
|
||||
|
||||
Finding widgets
|
||||
---------------
|
||||
|
||||
Widgets can be found by name in two ways:
|
||||
|
||||
1. **Get a direct child by name** using :cpp:func:`lv_obj_get_child_by_name(parent, "child_name")`.
|
||||
Example:
|
||||
``lv_obj_get_child_by_name(header, "title")``
|
||||
You can also use a "path" to find nested children:
|
||||
``lv_obj_get_child_by_name(cont, "buttons/mybtn_2")``
|
||||
|
||||
2. **Find a descendant at any level** using :cpp:func:`lv_obj_find_by_name(parent, "child_name")`.
|
||||
Example:
|
||||
``lv_obj_find_by_name(cont, "mybtn_1")``
|
||||
Note that ``"mybtn_1"`` is a child of ``"buttons"``, not directly of ``"cont"``.
|
||||
This is useful when you want to ignore hierarchy and search by name alone.
|
||||
|
||||
Since both functions start searching from a specific parent, it’s possible to have multiple widget
|
||||
subtrees with identical names under different parents.
|
||||
|
||||
For example, if ``my_listitem_create(parent)`` creates a widget named ``"list_item_#"``
|
||||
with children like ``"icon"``, ``"title"``, ``"ok_button"``, and ``"lv_label_0"``,
|
||||
and it's called 10 times, a specific ``"ok_button"`` can be found like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_obj_t * item = lv_obj_find_by_name(lv_screen_active(), "list_item_5");
|
||||
lv_obj_t * ok_btn = lv_obj_find_by_name(item, "ok_button");
|
||||
|
||||
// Or
|
||||
lv_obj_t * ok_btn = lv_obj_get_child_by_name(some_list_container, "list_item_5/ok_button");
|
||||
|
||||
Names are resolved **when they are retrieved**, not when they are set.
|
||||
This means the indices always reflect the current state of the widget tree
|
||||
at the time the name is used.
|
||||
|
||||
.. _widget_snapshot:
|
||||
|
||||
|
||||
+57
-5
@@ -464,13 +464,65 @@ void lv_obj_get_name_resolved(const lv_obj_t * obj, char buf[], size_t buf_size)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(obj->spec_attr && obj->spec_attr->name) {
|
||||
lv_strlcpy(buf, obj->spec_attr->name, buf_size);
|
||||
const char * name = lv_obj_get_name(obj);
|
||||
/*Use a default name which auto-indexing*/
|
||||
char name_buf[LV_OBJ_NAME_MAX_LEN];
|
||||
if(name == NULL) {
|
||||
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", obj->class_p->name);
|
||||
name = name_buf;
|
||||
}
|
||||
|
||||
size_t name_len = lv_strlen(name);
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
|
||||
/*If the last character is # automatically index the children with the same name start*/
|
||||
if(parent && name_len > 0 && name[name_len - 1] == '#') {
|
||||
uint32_t child_cnt = lv_obj_get_child_count(parent);
|
||||
uint32_t cnt = 0;
|
||||
uint32_t i;
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(parent, i);
|
||||
/*All siblings older siblings are checked, craft the name of this widget*/
|
||||
if(child == obj) {
|
||||
char num_buf[8];
|
||||
size_t num_len;
|
||||
num_len = lv_snprintf(num_buf, sizeof(num_buf), "%d", cnt);
|
||||
/*Is there enough space for the name and the index?*/
|
||||
if(buf_size > name_len + num_len) {
|
||||
/*E.g. buf = "some_name_", so trim the # from the end*/
|
||||
lv_strncpy(buf, name, name_len - 1);
|
||||
lv_strcpy(&buf[name_len - 1], num_buf);
|
||||
}
|
||||
else {
|
||||
/*Use the name as it is as a fallback*/
|
||||
lv_strlcpy(buf, obj->spec_attr->name, buf_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*Check the older siblings. IF they start with the same name count them*/
|
||||
else {
|
||||
const char * child_name = lv_obj_get_name(child);
|
||||
if(child_name == NULL) {
|
||||
/*If the name we are looking for start with the child's class name
|
||||
*increment the index. E.g. <class_name>_#*/
|
||||
size_t class_name_len = lv_strlen(child->class_p->name);
|
||||
if(name_len > 3 && class_name_len == name_len - 2 &&
|
||||
lv_strncmp(child->class_p->name, name, class_name_len) == 0) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
/*The name is set, check if it's e.g. <some_name>#*/
|
||||
else {
|
||||
if(lv_strcmp(child->spec_attr->name, name) == 0) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Craft a name if not set. E.g. "lv_button_1"*/
|
||||
else {
|
||||
uint32_t idx = lv_obj_get_index_by_type(obj, obj->class_p);
|
||||
lv_snprintf(buf, buf_size, "%s_%"LV_PRIu32, obj->class_p->name, idx);
|
||||
/*Just use the set name*/
|
||||
lv_strlcpy(buf, obj->spec_attr->name, buf_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-10
@@ -196,36 +196,55 @@ uint32_t lv_obj_get_child_count_by_type(const lv_obj_t * obj, const lv_obj_class
|
||||
#if LV_USE_OBJ_NAME
|
||||
|
||||
/**
|
||||
* Set a name for a widget. The name will be allocated.
|
||||
* Set a name for a widget. The name will be allocated and freed when the
|
||||
* widget is deleted or a new name is set.
|
||||
* @param obj pointer to an object
|
||||
* @param name the name to set
|
||||
* @param name the name to set. If set to `NULL` the default "<widget_type>_#"
|
||||
* name will be used.
|
||||
* @note If the name ends with a `#`, older siblings with the same name
|
||||
* will be counted, and the `#` will be replaced by the index of the
|
||||
* given widget. For example, creating multiple widgets with the name
|
||||
* "mybtn_#" will result in resolved names like "mybtn_0", "mybtn_1",
|
||||
* "mybtn_2", etc. The name is resolved when `lv_obj_get_name_resolved`
|
||||
* is called, so the result reflects the currently existing widgets at
|
||||
* that time.
|
||||
*/
|
||||
void lv_obj_set_name(lv_obj_t * obj, const char * name);
|
||||
|
||||
/**
|
||||
* Set a name for a widget. Only a pointer will be saved.
|
||||
* @param obj pointer to an object
|
||||
* @param name the name to set
|
||||
* @param name the name to set. If set to `NULL` the default "<widget_type>_#"
|
||||
* name will be used.
|
||||
* @note If the name ends with a `#`, older siblings with the same name
|
||||
* will be counted, and the `#` will be replaced by the index of the
|
||||
* given widget. For example, creating multiple widgets with the name
|
||||
* "mybtn_#" will result in resolved names like "mybtn_0", "mybtn_1",
|
||||
* "mybtn_2", etc. The name is resolved when `lv_obj_get_name_resolved`
|
||||
* is called, so the result reflects the currently existing widgets at
|
||||
* that time.
|
||||
*/
|
||||
void lv_obj_set_name_static(lv_obj_t * obj, const char * name);
|
||||
|
||||
/**
|
||||
* Get the set name as it was set
|
||||
* Get the set name as it was set.
|
||||
* @param obj pointer to an object
|
||||
* @return get the set name or NULL if it wasn't set yet
|
||||
*/
|
||||
const char * lv_obj_get_name(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the set name or craft a name automatically if there is no set name.
|
||||
* The crafted names are built like <widget type> + "_" + <index of the given type>
|
||||
* For example if a parent has two button and two label children the names will be
|
||||
* "lv_button_0", "lv_button1", "lv_label_0", "lv_label_1"
|
||||
* The <widget name> comes from the `class->name` field.
|
||||
* The index is 0 based.
|
||||
* Get the set name or craft a name automatically.
|
||||
* @param obj pointer to an object
|
||||
* @param buf buffer to store the name
|
||||
* @param buf_size the size of the buffer in bytes
|
||||
* @note If the name ends with a `#`, older siblings with the same name
|
||||
* will be counted, and the `#` will be replaced by the index of the
|
||||
* given widget. For example, creating multiple widgets with the name
|
||||
* "mybtn_#" will result in resolved names like "mybtn_0", "mybtn_1",
|
||||
* "mybtn_2", etc. The name is resolved when `lv_obj_get_name_resolved`
|
||||
* is called, so the result reflects the currently existing widgets at
|
||||
* that time.
|
||||
*/
|
||||
void lv_obj_get_name_resolved(const lv_obj_t * obj, char buf[], size_t buf_size);
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include "parsers/lv_xml_canvas_parser.h"
|
||||
#include "parsers/lv_xml_calendar_parser.h"
|
||||
#include "parsers/lv_xml_event_parser.h"
|
||||
#include "parsers/lv_xml_update_parser.h"
|
||||
#include "../../libs/expat/expat.h"
|
||||
#include "../../draw/lv_draw_image.h"
|
||||
|
||||
|
||||
@@ -93,6 +93,19 @@ lv_obj_t * lv_xml_component_process(lv_xml_parser_state_t * state, const char *
|
||||
lv_widget_processor_t * extended_proc = lv_xml_widget_get_extended_widget_processor(ctx->extends);
|
||||
extended_proc->apply_cb(state, attrs);
|
||||
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
/*Set a default indexed name*/
|
||||
if(state->item) {
|
||||
const char * value_of_name = lv_xml_get_value_of(attrs, "name");
|
||||
if(value_of_name) lv_obj_set_name(item, value_of_name);
|
||||
else {
|
||||
char name_buf[128];
|
||||
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", scope->name);
|
||||
lv_obj_set_name(state->item, name_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,9 @@ void lv_xml_obj_apply(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
size_t name_len = lv_strlen(name);
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
if(lv_streq("name", name)) lv_obj_set_name(item, value);
|
||||
if(lv_streq("name", name)) {
|
||||
lv_obj_set_name(item, value);
|
||||
}
|
||||
#endif
|
||||
if(lv_streq("x", name)) lv_obj_set_x(item, lv_xml_to_size(value));
|
||||
else if(lv_streq("y", name)) lv_obj_set_y(item, lv_xml_to_size(value));
|
||||
|
||||
@@ -209,6 +209,8 @@ void test_obj_get_by_name(void)
|
||||
lv_obj_t * cont3 = lv_obj_create(lv_screen_active());
|
||||
lv_obj_set_name_static(cont3, "third_static");
|
||||
lv_obj_set_name_static(cont3, "third");
|
||||
lv_obj_t * cont4 = lv_obj_create(lv_screen_active());
|
||||
|
||||
|
||||
lv_obj_t * root_label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(root_label, "Root");
|
||||
@@ -223,6 +225,19 @@ void test_obj_get_by_name(void)
|
||||
lv_label_set_text(hello_label, "Hello");
|
||||
lv_obj_set_name(hello_label, "my_label"); /*Same name as ofr the other label*/
|
||||
|
||||
/*Test auto indexing*/
|
||||
|
||||
lv_obj_t * label0 = lv_label_create(cont3);
|
||||
lv_obj_set_name(label0, "title_#");
|
||||
lv_obj_t * label1 = lv_label_create(cont3);
|
||||
lv_obj_set_name(label1, "title_#");
|
||||
lv_obj_t * label2 = lv_label_create(cont3); //lv_label_0
|
||||
lv_obj_t * label3 = lv_label_create(cont3);
|
||||
lv_obj_set_name(label3, "title_#?");
|
||||
lv_obj_t * label4 = lv_label_create(cont3); //lv_label_1
|
||||
lv_obj_t * label5 = lv_label_create(cont3);
|
||||
lv_obj_set_name(label5, "title_#");
|
||||
|
||||
|
||||
lv_obj_t * found_obj;
|
||||
|
||||
@@ -233,9 +248,12 @@ void test_obj_get_by_name(void)
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "first");
|
||||
TEST_ASSERT_EQUAL(cont1, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "lv_obj_2");
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "lv_obj_0");
|
||||
TEST_ASSERT_EQUAL(cont2, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "lv_obj_1");
|
||||
TEST_ASSERT_EQUAL(cont4, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "fifth");
|
||||
TEST_ASSERT_EQUAL(NULL, found_obj);
|
||||
|
||||
@@ -258,11 +276,30 @@ void test_obj_get_by_name(void)
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "");
|
||||
TEST_ASSERT_EQUAL(NULL, found_obj);
|
||||
|
||||
/* Test auto indexed names*/
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "third/title_0");
|
||||
TEST_ASSERT_EQUAL(label0, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "third/title_1");
|
||||
TEST_ASSERT_EQUAL(label1, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "third/lv_label_0");
|
||||
TEST_ASSERT_EQUAL(label2, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "third/title_#?");
|
||||
TEST_ASSERT_EQUAL(label3, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "third/lv_label_1");
|
||||
TEST_ASSERT_EQUAL(label4, found_obj);
|
||||
|
||||
found_obj = lv_obj_get_child_by_name(lv_screen_active(), "third/title_2");
|
||||
TEST_ASSERT_EQUAL(label5, found_obj);
|
||||
|
||||
/*-------------
|
||||
* Find by name
|
||||
*------------*/
|
||||
|
||||
found_obj = lv_obj_find_by_name(lv_screen_active(), "lv_obj_2");
|
||||
found_obj = lv_obj_find_by_name(lv_screen_active(), "lv_obj_0");
|
||||
TEST_ASSERT_EQUAL(cont2, found_obj);
|
||||
|
||||
found_obj = lv_obj_find_by_name(lv_screen_active(), "my_label");
|
||||
@@ -270,6 +307,10 @@ void test_obj_get_by_name(void)
|
||||
|
||||
found_obj = lv_obj_find_by_name(cont1, "my_label");
|
||||
TEST_ASSERT_EQUAL(hello_label, found_obj);
|
||||
|
||||
found_obj = lv_obj_find_by_name(lv_screen_active(), "title_2");
|
||||
TEST_ASSERT_EQUAL(label5, found_obj);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -228,22 +228,23 @@ void test_xml_error_resilience_syntax_ok(void)
|
||||
{
|
||||
const char * my_btn_xml =
|
||||
"<component>"
|
||||
"<consts>"
|
||||
"<int name=\"abc\" value=\"0xff0000\"/>"
|
||||
"<not_a_type name=\"xyz\" value=\"0xff0000\"/>"
|
||||
"<int not_a_prop=\"abc\" value=\"0xff0000\"/>"
|
||||
"<int name=\"abc\" not_a_value=\"0xff0000\"/>"
|
||||
"</consts>"
|
||||
"<styles>"
|
||||
"<style name=\"rel_style\" bg_color=\"0xff0000\" not_a_prop=\"0xff0000\"/>"
|
||||
"<inv_style name=\"rel_style\" bg_color=\"0x800000\"/>"
|
||||
"<style bg_color=\"0x800000\"/>"
|
||||
"</styles>"
|
||||
|
||||
"<view extends=\"not_a_widget\" style_text_color=\"0x0000ff\" style_text_color:checked=\"0x8080ff\" styles=\"rel_style pr_style:checked\">"
|
||||
"<unknown/>"
|
||||
"<lv_label not_an_attr=\"40\"/>"
|
||||
"</view>"
|
||||
" <consts>"
|
||||
" <int name=\"abc\" value=\"0xff0000\"/>"
|
||||
" <not_a_type name=\"xyz\" value=\"0xff0000\"/>"
|
||||
" <int not_a_prop=\"abc\" value=\"0xff0000\"/>"
|
||||
" <int name=\"abc\" not_a_value=\"0xff0000\"/>"
|
||||
" </consts>"
|
||||
""
|
||||
" <styles>"
|
||||
" <style name=\"rel_style\" bg_color=\"0xff0000\" not_a_prop=\"0xff0000\"/>"
|
||||
" <inv_style name=\"rel_style\" bg_color=\"0x800000\"/>"
|
||||
" <style bg_color=\"0x800000\"/>"
|
||||
" </styles>"
|
||||
""
|
||||
" <view extends=\"not_a_widget\" style_text_color=\"0x0000ff\" style_text_color:checked=\"0x8080ff\" styles=\"rel_style pr_style:checked\">"
|
||||
" <unknown/>"
|
||||
" <lv_label not_an_attr=\"40\"/>"
|
||||
" </view>"
|
||||
"</component>";
|
||||
|
||||
lv_xml_component_register_from_data("my_btn", my_btn_xml);
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#if LV_BUILD_TEST || 1
|
||||
#include "../lvgl.h"
|
||||
|
||||
#include "unity/unity.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
/* Function run before every test */
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
/* Function run after every test */
|
||||
lv_obj_clean(lv_screen_active());
|
||||
}
|
||||
|
||||
void test_xml_names(void)
|
||||
{
|
||||
|
||||
const char * base_label_xml =
|
||||
"<component>"
|
||||
" <view extends=\"lv_label\"></view>"
|
||||
"</component>";
|
||||
|
||||
const char * my_label_xml =
|
||||
"<component>"
|
||||
" <view extends=\"base_label\"></view>"
|
||||
"</component>";
|
||||
|
||||
const char * my_btn_xml =
|
||||
"<component>"
|
||||
" <view extends=\"lv_button\">"
|
||||
" <my_label name=\"first_label\"/>"
|
||||
" <my_label/>"
|
||||
" <my_label name=\"third_label\"/>"
|
||||
" <my_label/>"
|
||||
" </view>"
|
||||
"</component>";
|
||||
|
||||
const char * main_screen_xml =
|
||||
"<screen>"
|
||||
" <view name=\"main_screen\">"
|
||||
" <my_btn/>"
|
||||
" <my_btn name=\"first_btn\"/>"
|
||||
" <lv_button/>"
|
||||
" <my_btn/>"
|
||||
" <my_btn name=\"lv_button_#\"/>"
|
||||
" <lv_button/>"
|
||||
" </view>"
|
||||
"</screen>";
|
||||
|
||||
lv_xml_component_register_from_data("my_btn", my_btn_xml);
|
||||
lv_xml_component_register_from_data("base_label", base_label_xml);
|
||||
lv_xml_component_register_from_data("my_label", my_label_xml);
|
||||
lv_xml_component_register_from_data("main_screen", main_screen_xml);
|
||||
|
||||
lv_obj_t * main_screen = lv_xml_create(NULL, "main_screen", NULL);
|
||||
|
||||
|
||||
char buf[128];
|
||||
lv_obj_t * btn;
|
||||
btn = lv_obj_get_child(main_screen, 0);
|
||||
lv_obj_get_name_resolved(btn, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("my_btn_0", buf);
|
||||
|
||||
btn = lv_obj_get_child(main_screen, 1);
|
||||
lv_obj_get_name_resolved(btn, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("first_btn", buf);
|
||||
|
||||
btn = lv_obj_get_child(main_screen, 2);
|
||||
lv_obj_get_name_resolved(btn, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("lv_button_0", buf);
|
||||
|
||||
btn = lv_obj_get_child(main_screen, 3);
|
||||
lv_obj_get_name_resolved(btn, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("my_btn_1", buf);
|
||||
|
||||
btn = lv_obj_get_child(main_screen, 4);
|
||||
lv_obj_get_name_resolved(btn, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("lv_button_1", buf);
|
||||
|
||||
btn = lv_obj_get_child(main_screen, 5);
|
||||
lv_obj_get_name_resolved(btn, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("lv_button_2", buf);
|
||||
|
||||
|
||||
btn = lv_obj_get_child(main_screen, 3);
|
||||
lv_obj_t * label;
|
||||
label = lv_obj_get_child(btn, 0);
|
||||
lv_obj_get_name_resolved(label, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("first_label", buf);
|
||||
|
||||
label = lv_obj_get_child(btn, 1);
|
||||
lv_obj_get_name_resolved(label, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("my_label_0", buf);
|
||||
|
||||
label = lv_obj_get_child(btn, 2);
|
||||
lv_obj_get_name_resolved(label, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("third_label", buf);
|
||||
|
||||
label = lv_obj_get_child(btn, 3);
|
||||
lv_obj_get_name_resolved(label, buf, 128);
|
||||
TEST_ASSERT_EQUAL_STRING("my_label_1", buf);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user