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: .. _xml_events_screen:
Screen Load and Create events 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: 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. 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``). (unless they are saved in ``subjects``).
Both tags support the following optional attributes: 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"``. - ``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"``. - ``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"``. - ``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: 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 --> <!-- screen1.xml -->
<screen> <screen>
<view style_bg_color="0xff7788" name="first"> <view style_bg_color="0xff7788">
<lv_button> <lv_button>
<lv_label text="Create"/> <lv_label text="Create"/>
<!-- Create an instance of "screen2" and load it. <!-- Create an instance of "screen2" and load it. -->
Note that here the name of the XML file is used. -->
<screen_create_event screen="screen2" anim_type="over_right" duration="500" delay="1000"/> <screen_create_event screen="screen2" anim_type="over_right" duration="500" delay="1000"/>
</lv_button> </lv_button>
</view> </view>
@@ -93,13 +93,11 @@ This is a simple example of both load and create:
<!-- screen2.xml --> <!-- screen2.xml -->
<screen> <screen>
<view style_bg_color="0x77ff88" name="second"> <view style_bg_color="0x77ff88">
<lv_button> <lv_button>
<lv_label text="Load"/> <lv_label text="Load"/>
<!-- Load an already created screen that has the name "first". <!-- Load an already created instance of screen1.-->
Note that here the name of the instance is used, <screen_load_event screen="screen1"/>
and not the name of the XML file. -->
<screen_load_event screen="first"/>
</lv_button> </lv_button>
</view> </view>
</screen> </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.*/ /*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_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); lv_screen_load(screen1);
Set subject value 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 #if LV_USE_OBJ_NAME
/*Set a default indexed name*/ /*Set a default indexed name*/
if(state.item && lv_obj_get_name(state.item) == NULL) { if(state.item) {
char name_buf[128]; if(state.scope.is_screen) {
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", scope->name); lv_obj_set_name(state.item, scope->name);
lv_obj_set_name(state.item, name_buf); }
else if(lv_obj_get_name(state.item) == NULL) {
char name_buf[128];
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", scope->name);
}
} }
#endif #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.*/ * So leave state.scope = NULL which means the global context.*/
state.item = p->create_cb(&state, attrs); state.item = p->create_cb(&state, attrs);
if(state.item == NULL) {
LV_LOG_WARN("Couldn't create widget.");
return NULL;
}
if(attrs) { if(attrs) {
p->apply_cb(&state, 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); lv_xml_component_scope_t * scope = lv_xml_component_get_scope(name);
if(scope) { if(scope) {
item = lv_xml_create_in_scope(parent, NULL, scope, attrs); 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) { if(attrs) {
lv_xml_parser_state_t state; lv_xml_parser_state_t state;
lv_xml_parser_state_init(&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 = lv_xml_widget_get_extended_widget_processor(scope->extends);
p->apply_cb(&state, attrs); 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; 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); lv_widget_processor_t * extended_proc = lv_xml_widget_get_extended_widget_processor(scope->extends);
extended_proc->apply_cb(state, attrs); extended_proc->apply_cb(state, attrs);
#if LV_USE_OBJ_NAME #if LV_USE_OBJ_NAME
/*Set a default indexed name*/ /*Set a default indexed name*/
if(state->item) { if(state->item) {
@@ -18,7 +18,7 @@ void test_xml_screen_event_1(void)
{ {
const char * screen1_xml = { const char * screen1_xml = {
" <screen>" " <screen>"
" <view style_bg_color=\"0xff7788\" name=\"first\">" " <view style_bg_color=\"0xff7788\">"
" <lv_button>" " <lv_button>"
" <lv_label text=\"Create\"/>" " <lv_label text=\"Create\"/>"
" <screen_create_event screen=\"screen2\" anim_type=\"over_right\" duration=\"500\" delay=\"1000\"/>" " <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 = { const char * screen2_xml = {
" <screen>" " <screen>"
" <view style_bg_color=\"0x77ff88\" name=\"second\">" " <view style_bg_color=\"0x77ff88\">"
" <lv_button>" " <lv_button>"
" <lv_label text=\"Load\"/>" " <lv_label text=\"Load\"/>"
" <screen_load_event screen=\"first\"/>" " <screen_load_event screen=\"screen1\"/>"
" </lv_button>" " </lv_button>"
" </view>" " </view>"
" </screen>" " </screen>"
@@ -46,31 +46,32 @@ void test_xml_screen_event_1(void)
lv_obj_t * screen1; lv_obj_t * screen1;
screen1 = lv_xml_create(NULL, "screen1", NULL); 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_screen_load(screen1);
lv_test_mouse_click_at(10, 10); lv_test_mouse_click_at(10, 10);
lv_test_wait(200); lv_test_wait(200);
/*There is a delay so stays on the first screen*/ /*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*/ /*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); 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*/ /*No delay, go back the first screen immediately*/
lv_test_mouse_click_at(10, 10); 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*/ /*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*/ /*Clean up*/
lv_screen_load(default_screen); lv_screen_load(default_screen);
lv_obj_delete(screen1); 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 #endif