mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-25 01:04:25 +08:00
feat(xml): add slot support (#9193)
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Install LVGL using CMake / build-examples (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Install LVGL using CMake / build-examples (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
8bc37d840f
commit
f38718108d
@@ -63,6 +63,55 @@ These properties are set once (at creation time), and there are no specific
|
||||
``set`` functions to modify the property later. LVGL's general API can still be
|
||||
used to modify any widget in the component, but no dedicated API functions are generated.
|
||||
|
||||
|
||||
Slots
|
||||
-----
|
||||
|
||||
With the help of a "slot" any UI element in the component can be easily exposed as a parent
|
||||
that can be referenced later and children can be created there.
|
||||
|
||||
|
||||
Just add ``<slot name="my_slot"/>`` to the ``<api>`` to tell the Editor
|
||||
which children to expose.
|
||||
|
||||
To target a slot on an instance of a component create a child like
|
||||
``<component_name-slot_name>`` and add the children as needed.
|
||||
|
||||
Slots are available only for components. In case of a widget the more powerful
|
||||
:ref:`elements with get access type <xml_api_element_get>` can be used.
|
||||
|
||||
Slots are very useful to create components like screen templates where the user is
|
||||
allowed to create children on certain internal UI elements.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- simple_screen.xml -->
|
||||
<component>
|
||||
<api>
|
||||
<slot name="icon_area"/>
|
||||
<slot name="content_area"/>
|
||||
</api>
|
||||
|
||||
<view width="100%" height="100%" flex_flow="column">
|
||||
<lv_obj name="icon_area" width="100%" height="30" flex_flow="row"/>
|
||||
<lv_obj name="content_area" width="100%" flex_grow="1" flex_flow="column"/>
|
||||
</view>
|
||||
</component>
|
||||
|
||||
<!-- main_screen.xml -->
|
||||
<component>
|
||||
<view extends="simple_screen" width="100%">
|
||||
<simple_screen-icon_area>
|
||||
<lv_image src="img1"/>
|
||||
<lv_image src="img2"/>
|
||||
</simple_screen-icon_area>
|
||||
|
||||
<simple_screen-content_area>
|
||||
<lv_label text="Some content"/>
|
||||
</simple_screen-content_area>
|
||||
</view>
|
||||
</component>
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
@@ -89,7 +138,12 @@ Example
|
||||
|
||||
<!-- my_list.xml -->
|
||||
<component>
|
||||
<api>
|
||||
<slot name="header"/>
|
||||
</api>
|
||||
|
||||
<view flex_flow="column">
|
||||
<lv_obj name="header" width="100%"/>
|
||||
<my_button button_label="First"/>
|
||||
<my_button button_label="Wifi" button_icon="img_wifi"/>
|
||||
<my_button button_label="Third"/>
|
||||
@@ -255,6 +309,9 @@ LVGL's UI Editor generates this:
|
||||
lv_obj_t * my_widget_add_indicator(lv_obj_t * parent, lv_color_t color, int32_t max_value);
|
||||
void my_widget_set_indicator_value(lv_obj_t * obj, int32_t value);
|
||||
|
||||
|
||||
.. _xml_api_element_get:
|
||||
|
||||
access="get"
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
+34
-20
@@ -844,43 +844,57 @@ static void view_start_element_handler(void * user_data, const char * name, cons
|
||||
|
||||
resolve_consts(attrs, &state->scope);
|
||||
|
||||
void * item = NULL;
|
||||
state->item = NULL;
|
||||
/* Select the widget specific parser type based on the name */
|
||||
lv_widget_processor_t * p = lv_xml_widget_get_processor(name);
|
||||
if(p) {
|
||||
item = p->create_cb(state, attrs);
|
||||
state->item = item;
|
||||
state->item = p->create_cb(state, attrs);
|
||||
if(state->item) {
|
||||
/*If it's a widget remove all styles. E.g. if it extends an `lv_button`
|
||||
*now it has the button theme styles. However if it were a real widget
|
||||
*it had e.g. `my_widget_class` so the button's theme wouldn't apply on it.
|
||||
*Removing the style will ensure a better preview*/
|
||||
if(state->scope.is_widget && is_view) lv_obj_remove_style_all(state->item);
|
||||
|
||||
|
||||
/*If it's a widget remove all styles. E.g. if it extends an `lv_button`
|
||||
*now it has the button theme styles. However if it were a real widget
|
||||
*it had e.g. `my_widget_class` so the button's theme wouldn't apply on it.
|
||||
*Removing the style will ensure a better preview*/
|
||||
if(state->scope.is_widget && is_view) lv_obj_remove_style_all(item);
|
||||
|
||||
/*Apply the attributes from e.g. `<lv_slider value="30" x="20">`*/
|
||||
if(item) {
|
||||
/*Apply the attributes from e.g. `<lv_slider value="30" x="20">`*/
|
||||
p->apply_cb(state, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
/* If not a widget, check if it is a component */
|
||||
if(item == NULL) {
|
||||
item = lv_xml_component_process(state, name, attrs);
|
||||
state->item = item;
|
||||
if(state->item == NULL) {
|
||||
state->item = lv_xml_component_process(state, name, attrs);
|
||||
}
|
||||
|
||||
/* If it isn't a component either then it is unknown */
|
||||
if(item == NULL) {
|
||||
LV_LOG_WARN("'%s' is not a known widget, element, or component", name);
|
||||
/* If not a component either, check if it is a slot, e.g. my_button-icon */
|
||||
if(state->item == NULL) {
|
||||
char buf[128];
|
||||
if(lv_strlen(name) >= sizeof(buf)) {
|
||||
LV_LOG_WARN("Component/slot name '%s' is too long (max 127 chars); skipping slot parsing.", name);
|
||||
}
|
||||
else {
|
||||
lv_strlcpy(buf, name, sizeof(buf));
|
||||
char * bufp = buf;
|
||||
const char * comp_name = lv_xml_split_str(&bufp, '-');
|
||||
const char * slot_name = bufp;
|
||||
lv_xml_component_scope_t * comp_scope = lv_xml_component_get_scope(comp_name);
|
||||
if(comp_scope && lv_streq(comp_name, comp_scope->name)) {
|
||||
state->item = lv_obj_find_by_name(state->parent, slot_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If it isn't a slot either then it is unknown */
|
||||
if(state->item == NULL) {
|
||||
LV_LOG_WARN("'%s' is not a known widget, element, component, or slot", name);
|
||||
return;
|
||||
}
|
||||
|
||||
void ** new_parent = lv_ll_ins_tail(&state->parent_ll);
|
||||
*new_parent = item;
|
||||
*new_parent = state->item;
|
||||
|
||||
if(is_view) {
|
||||
state->view = item;
|
||||
state->view = state->item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ static void end_metadata_handler(void * user_data, const char * name);
|
||||
static void process_const_element(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
static void process_font_element(lv_xml_parser_state_t * state, const char * type, const char ** attrs);
|
||||
static void process_image_element(lv_xml_parser_state_t * state, const char * type, const char ** attrs);
|
||||
static void process_prop_element(lv_xml_parser_state_t * state, const char ** attrs);
|
||||
static void process_prop_element(lv_xml_parser_state_t * state, const char * name, const char ** attrs);
|
||||
static char * extract_view_content(const char * xml_definition);
|
||||
static style_prop_anim_type_t style_prop_anim_get_type(lv_style_prop_t prop);
|
||||
static void anim_exec_cb(lv_anim_t * a, int32_t v);
|
||||
@@ -107,7 +107,7 @@ lv_obj_t * lv_xml_component_process(lv_xml_parser_state_t * state, const char *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Apply the properties of the component, e.g. <my_button x="20" styles="red"/> */
|
||||
/* Apply the properties of the component, e.g. <my_button x="20" width="300"/> */
|
||||
state->item = item;
|
||||
lv_widget_processor_t * extended_proc = lv_xml_widget_get_extended_widget_processor(scope->extends);
|
||||
extended_proc->apply_cb(state, attrs);
|
||||
@@ -129,6 +129,8 @@ lv_obj_t * lv_xml_component_process(lv_xml_parser_state_t * state, const char *
|
||||
|
||||
lv_xml_component_scope_t * lv_xml_component_get_scope(const char * component_name)
|
||||
{
|
||||
if(component_name == NULL) return NULL;
|
||||
|
||||
lv_xml_component_scope_t * scope;
|
||||
LV_LL_READ(&component_scope_ll, scope) {
|
||||
if(lv_streq(scope->name, component_name)) return scope;
|
||||
@@ -868,8 +870,10 @@ static void process_grad_stop_element(lv_xml_parser_state_t * state, const char
|
||||
dsc->stops_count++;
|
||||
}
|
||||
|
||||
static void process_prop_element(lv_xml_parser_state_t * state, const char ** attrs)
|
||||
static void process_prop_element(lv_xml_parser_state_t * state, const char * name, const char ** attrs)
|
||||
{
|
||||
if(!lv_streq(name, "prop")) return;
|
||||
|
||||
lv_xml_param_t * prop = lv_ll_ins_tail(&state->scope.param_ll);
|
||||
lv_memzero(prop, sizeof(lv_xml_param_t));
|
||||
|
||||
@@ -904,7 +908,7 @@ static void start_metadata_handler(void * user_data, const char * name, const ch
|
||||
switch(state->section) {
|
||||
case LV_XML_PARSER_SECTION_API:
|
||||
if(old_section != state->section) return; /*Ignore the section opening, e.g. <api>*/
|
||||
process_prop_element(state, attrs);
|
||||
process_prop_element(state, name, attrs);
|
||||
break;
|
||||
|
||||
case LV_XML_PARSER_SECTION_CONSTS:
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#if LV_BUILD_TEST
|
||||
#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_slot_1(void)
|
||||
{
|
||||
const char * my_button =
|
||||
"<component>"
|
||||
" <api>"
|
||||
" <slot name=\"slot1\"/>"
|
||||
" <prop name=\"label\" type=\"string\" default=\"Hello world\"/>"
|
||||
" </api>"
|
||||
""
|
||||
" <view width=\"content\" height=\"content\">"
|
||||
" <lv_button name=\"slot1\" flex_flow=\"row\">"
|
||||
" <lv_label text=\"$label\"/>"
|
||||
" </lv_button>"
|
||||
" </view>"
|
||||
"</component>";
|
||||
|
||||
const char * my_list =
|
||||
"<component>"
|
||||
" <view flex_flow=\"column\" width=\"300\" height=\"400\">"
|
||||
" <my_button/>"
|
||||
" <my_button label=\"Custom label\">"
|
||||
" <my_button-slot1>"
|
||||
" <lv_label text=\"New label\" style_text_color=\"0xf00\"/>"
|
||||
" </my_button-slot1>"
|
||||
" </my_button>"
|
||||
" </view>"
|
||||
"</component>";
|
||||
|
||||
lv_result_t res;
|
||||
|
||||
res = lv_xml_register_component_from_data("my_button", my_button);
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_OK, res);
|
||||
|
||||
res = lv_xml_register_component_from_data("my_list", my_list);
|
||||
TEST_ASSERT_EQUAL_INT(LV_RESULT_OK, res);
|
||||
|
||||
lv_obj_t * my_list_0 = lv_xml_create(lv_screen_active(), "my_list", NULL);
|
||||
|
||||
lv_obj_t * new_label = lv_obj_get_child_by_name(my_list_0, "my_button_1/slot1/lv_label_1");
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("New label", lv_label_get_text(new_label));
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user