fix(xml): fix screen names and extended component names

This commit is contained in:
Gabor Kiss-Vamosi
2025-07-03 13:17:25 +02:00
committed by Felipe Neves
parent 84acb67dca
commit b441ec37fa
4 changed files with 50 additions and 29 deletions
+9 -13
View File
@@ -55,6 +55,7 @@ The ``user_data`` is optional. If omitted, ``NULL`` will be passed.
.. _xml_events_screen:
Screen Load and Create events
*****************************
@@ -63,9 +64,9 @@ of a widget or component, screens can be loaded or created on a trigger (e.g. cl
The difference between load and create is that:
- **load**: Just loads an already existing screen. When the screen is left, it remains in memory,
- **load**: Just loads an already existing screen. After leaving the screen, it remains in memory,
so all states are preserved.
- **create**: The screen is created dynamically, and when it's left, it is deleted, so all changes are lost
- **create**: The screen is created dynamically, and when leaving the screen, it is deleted, so all changes are lost
(unless they are saved in ``subjects``).
Both tags support the following optional attributes:
@@ -73,7 +74,7 @@ Both tags support the following optional attributes:
- ``trigger``: Event code that triggers the action (e.g. ``"clicked"``, ``"long_pressed"``, etc). Default: ``"clicked"``.
- ``anim_type``: Describes how the screen is loaded (e.g. ``"move_right"``, ``"fade_in"``). Default: ``"none"``.
- ``duration``: Length of the animation in milliseconds. Default: ``0``. Only used if ``anim_type`` is not ``"none"``.
- ``delay``: Wait time before loading the screen in milliseconds.
- ``delay``: Wait time before loading the screen in milliseconds. Default: ``0``.
This is a simple example of both load and create:
@@ -81,11 +82,10 @@ This is a simple example of both load and create:
<!-- screen1.xml -->
<screen>
<view style_bg_color="0xff7788" name="first">
<view style_bg_color="0xff7788">
<lv_button>
<lv_label text="Create"/>
<!-- Create an instance of "screen2" and load it.
Note that here the name of the XML file is used. -->
<!-- Create an instance of "screen2" and load it. -->
<screen_create_event screen="screen2" anim_type="over_right" duration="500" delay="1000"/>
</lv_button>
</view>
@@ -93,13 +93,11 @@ This is a simple example of both load and create:
<!-- screen2.xml -->
<screen>
<view style_bg_color="0x77ff88" name="second">
<view style_bg_color="0x77ff88">
<lv_button>
<lv_label text="Load"/>
<!-- Load an already created screen that has the name "first".
Note that here the name of the instance is used,
and not the name of the XML file. -->
<screen_load_event screen="first"/>
<!-- Load an already created instance of screen1.-->
<screen_load_event screen="screen1"/>
</lv_button>
</view>
</screen>
@@ -111,10 +109,8 @@ This is a simple example of both load and create:
/*Create an instance of screen_1 so that it can loaded from screen2.*/
lv_obj_t * screen1 = lv_xml_create(NULL, "screen1", NULL);
lv_obj_set_name(screen1, "first"); /*Will be referenced by this name when loaded*/
lv_screen_load(screen1);
Set subject value
*****************
+30 -5
View File
@@ -177,10 +177,14 @@ void * lv_xml_create_in_scope(lv_obj_t * parent, lv_xml_component_scope_t * pare
#if LV_USE_OBJ_NAME
/*Set a default indexed name*/
if(state.item && lv_obj_get_name(state.item) == NULL) {
char name_buf[128];
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", scope->name);
lv_obj_set_name(state.item, name_buf);
if(state.item) {
if(state.scope.is_screen) {
lv_obj_set_name(state.item, scope->name);
}
else if(lv_obj_get_name(state.item) == NULL) {
char name_buf[128];
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", scope->name);
}
}
#endif
@@ -206,6 +210,10 @@ void * lv_xml_create(lv_obj_t * parent, const char * name, const char ** attrs)
* So leave state.scope = NULL which means the global context.*/
state.item = p->create_cb(&state, attrs);
if(state.item == NULL) {
LV_LOG_WARN("Couldn't create widget.");
return NULL;
}
if(attrs) {
p->apply_cb(&state, attrs);
}
@@ -215,7 +223,11 @@ void * lv_xml_create(lv_obj_t * parent, const char * name, const char ** attrs)
lv_xml_component_scope_t * scope = lv_xml_component_get_scope(name);
if(scope) {
item = lv_xml_create_in_scope(parent, NULL, scope, attrs);
if(item == NULL) {
LV_LOG_WARN("Couldn't create component.");
return NULL;
}
const char * value_of_name = NULL;
if(attrs) {
lv_xml_parser_state_t state;
lv_xml_parser_state_init(&state);
@@ -228,8 +240,21 @@ void * lv_xml_create(lv_obj_t * parent, const char * name, const char ** attrs)
p = lv_xml_widget_get_extended_widget_processor(scope->extends);
p->apply_cb(&state, attrs);
#if LV_USE_OBJ_NAME
value_of_name = lv_xml_get_value_of(attrs, "name");
if(value_of_name) lv_obj_set_name(item, value_of_name);
#endif
}
/*Set a default indexed name for non screens*/
#if LV_USE_OBJ_NAME
if(lv_obj_get_parent(item) && value_of_name == NULL) {
char name_buf[128];
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", scope->name);
lv_obj_set_name(item, name_buf);
}
#endif
return item;
}
-1
View File
@@ -94,7 +94,6 @@ 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(scope->extends);
extended_proc->apply_cb(state, attrs);
#if LV_USE_OBJ_NAME
/*Set a default indexed name*/
if(state->item) {
@@ -18,7 +18,7 @@ void test_xml_screen_event_1(void)
{
const char * screen1_xml = {
" <screen>"
" <view style_bg_color=\"0xff7788\" name=\"first\">"
" <view style_bg_color=\"0xff7788\">"
" <lv_button>"
" <lv_label text=\"Create\"/>"
" <screen_create_event screen=\"screen2\" anim_type=\"over_right\" duration=\"500\" delay=\"1000\"/>"
@@ -29,10 +29,10 @@ void test_xml_screen_event_1(void)
const char * screen2_xml = {
" <screen>"
" <view style_bg_color=\"0x77ff88\" name=\"second\">"
" <view style_bg_color=\"0x77ff88\">"
" <lv_button>"
" <lv_label text=\"Load\"/>"
" <screen_load_event screen=\"first\"/>"
" <screen_load_event screen=\"screen1\"/>"
" </lv_button>"
" </view>"
" </screen>"
@@ -46,31 +46,32 @@ void test_xml_screen_event_1(void)
lv_obj_t * screen1;
screen1 = lv_xml_create(NULL, "screen1", NULL);
TEST_ASSERT_NOT_NULL(lv_display_get_screen_by_name(NULL, "first"));
TEST_ASSERT_NOT_NULL(lv_display_get_screen_by_name(NULL, "screen1"));
lv_screen_load(screen1);
lv_test_mouse_click_at(10, 10);
lv_test_wait(200);
/*There is a delay so stays on the first screen*/
TEST_ASSERT_EQUAL_STRING("first", lv_obj_get_name(lv_screen_active()));
TEST_ASSERT_EQUAL_STRING("screen1", lv_obj_get_name(lv_screen_active()));
/*second should be created*/
TEST_ASSERT_NOT_NULL(lv_display_get_screen_by_name(NULL, "second"));
TEST_ASSERT_NOT_NULL(lv_display_get_screen_by_name(NULL, "screen2"));
lv_test_wait(1300);
TEST_ASSERT_EQUAL_STRING("second", lv_obj_get_name(lv_screen_active()));
/*second screen should be loaded*/
TEST_ASSERT_EQUAL_STRING("screen2", lv_obj_get_name(lv_screen_active()));
/*No delay, go back the first screen immediately*/
lv_test_mouse_click_at(10, 10);
TEST_ASSERT_EQUAL_STRING("first", lv_obj_get_name(lv_screen_active()));
TEST_ASSERT_EQUAL_STRING("screen1", lv_obj_get_name(lv_screen_active()));
/*second should be deleted*/
TEST_ASSERT_NULL(lv_display_get_screen_by_name(NULL, "second"));
TEST_ASSERT_NULL(lv_display_get_screen_by_name(NULL, "screen2"));
/*Clean up*/
lv_screen_load(default_screen);
lv_obj_delete(screen1);
TEST_ASSERT_NULL(lv_display_get_screen_by_name(NULL, "first"));
TEST_ASSERT_NULL(lv_display_get_screen_by_name(NULL, "screen1"));
}
#endif