mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-24 08:16:29 +08:00
feat(xml): load fonts and images from XML
This commit is contained in:
@@ -163,6 +163,6 @@ A ``globals.xml`` file of a component library can look like this:
|
||||
</images>
|
||||
|
||||
<fonts>
|
||||
<tinyttf name="big" src="A:/fonts/arial.ttf" size="28"/>
|
||||
<tiny_ttf name="big" src="A:/fonts/arial.ttf" size="28"/>
|
||||
</fonts>
|
||||
</globals>
|
||||
|
||||
@@ -29,7 +29,7 @@ In ``<styles>`` and ``<view>``, fonts can be referenced by their name, e.g.,
|
||||
|
||||
<style name="style1" text_font="medium"/>
|
||||
|
||||
The tag name determines how the font is loaded. Currently, only ``tinyttf as_file="true"`` is supported.
|
||||
The tag name determines how the font is loaded. Currently, only ``tiny_ttf as_file="true"`` is supported.
|
||||
|
||||
- ``bin``:
|
||||
|
||||
@@ -38,7 +38,7 @@ The tag name determines how the font is loaded. Currently, only ``tinyttf as_fil
|
||||
- If ``as_file="false"`` (default): On export, the font file will be converted to a C array LVGL font
|
||||
that can be used directly by LVGL.
|
||||
|
||||
- ``tinyttf``:
|
||||
- ``tiny_ttf``:
|
||||
|
||||
- If ``as_file="true"``: Can be loaded directly by ``lv_tiny_ttf_create_file()``.
|
||||
- If ``as_file="false"`` (default): The font file will be converted to a raw C array on export
|
||||
|
||||
@@ -15,7 +15,7 @@ void lv_example_xml_2(void)
|
||||
lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml");
|
||||
lv_xml_component_register_from_file("A:lvgl/examples/others/xml/view.xml");
|
||||
|
||||
lv_xml_register_font("lv_montserrat_18", &lv_font_montserrat_18);
|
||||
lv_xml_register_font(NULL, "lv_montserrat_18", &lv_font_montserrat_18);
|
||||
|
||||
lv_obj_t * obj = lv_xml_create(lv_screen_active(), "view", NULL);
|
||||
lv_obj_set_pos(obj, 10, 10);
|
||||
|
||||
@@ -195,7 +195,7 @@ const lv_font_t * lv_xml_get_font(lv_xml_component_ctx_t * ctx, const char * nam
|
||||
}
|
||||
|
||||
/*If not found in the component check the global space*/
|
||||
if(!lv_streq(ctx->name, "globals")) {
|
||||
if(ctx == NULL || !lv_streq(ctx->name, "globals")) {
|
||||
ctx = lv_xml_component_get_ctx("globals");
|
||||
if(ctx) {
|
||||
LV_LL_READ(&ctx->font_ll, f) {
|
||||
@@ -233,7 +233,7 @@ lv_subject_t * lv_xml_get_subject(lv_xml_component_ctx_t * ctx, const char * nam
|
||||
}
|
||||
|
||||
/*If not found in the component check the global space*/
|
||||
if(!lv_streq(ctx->name, "globals")) {
|
||||
if(ctx == NULL || !lv_streq(ctx->name, "globals")) {
|
||||
ctx = lv_xml_component_get_ctx("globals");
|
||||
if(ctx) {
|
||||
LV_LL_READ(&ctx->subjects_ll, s) {
|
||||
@@ -277,7 +277,7 @@ const char * lv_xml_get_const(lv_xml_component_ctx_t * ctx, const char * name)
|
||||
}
|
||||
|
||||
/*If not found in the component check the global space*/
|
||||
if(!lv_streq(ctx->name, "globals")) {
|
||||
if(ctx == NULL || !lv_streq(ctx->name, "globals")) {
|
||||
ctx = lv_xml_component_get_ctx("globals");
|
||||
if(ctx) {
|
||||
LV_LL_READ(&ctx->const_ll, cnst) {
|
||||
@@ -325,7 +325,7 @@ const void * lv_xml_get_image(lv_xml_component_ctx_t * ctx, const char * name)
|
||||
}
|
||||
|
||||
/*If not found in the component check the global space*/
|
||||
if(!lv_streq(ctx->name, "globals")) {
|
||||
if(ctx == NULL || !lv_streq(ctx->name, "globals")) {
|
||||
ctx = lv_xml_component_get_ctx("globals");
|
||||
if(ctx) {
|
||||
LV_LL_READ(&ctx->image_ll, img) {
|
||||
@@ -367,7 +367,7 @@ lv_event_cb_t lv_xml_get_event_cb(lv_xml_component_ctx_t * ctx, const char * nam
|
||||
}
|
||||
|
||||
/*If not found in the component check the global space*/
|
||||
if(!lv_streq(ctx->name, "globals")) {
|
||||
if(ctx == NULL || !lv_streq(ctx->name, "globals")) {
|
||||
ctx = lv_xml_component_get_ctx("globals");
|
||||
if(ctx) {
|
||||
LV_LL_READ(&ctx->event_ll, e) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lv_xml_component.h"
|
||||
#if LV_USE_XML
|
||||
|
||||
#include "../../lvgl.h"
|
||||
#include "lv_xml_component_private.h"
|
||||
#include "lv_xml_private.h"
|
||||
#include "lv_xml_parser.h"
|
||||
@@ -34,6 +35,8 @@
|
||||
static void start_metadata_handler(void * user_data, const char * name, const char ** attrs);
|
||||
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 char * extract_view_content(const char * xml_definition);
|
||||
|
||||
@@ -242,6 +245,19 @@ lv_result_t lv_xml_component_unregister(const char * name)
|
||||
lv_ll_clear(&ctx->param_ll);
|
||||
|
||||
|
||||
lv_xml_font_t * font;
|
||||
LV_LL_READ(&ctx->font_ll, font) {
|
||||
lv_free((char *)font->name);
|
||||
}
|
||||
lv_ll_clear(&ctx->image_ll);
|
||||
|
||||
lv_xml_image_t * image;
|
||||
LV_LL_READ(&ctx->image_ll, image) {
|
||||
lv_free((char *)image->name);
|
||||
lv_free((char *)image->src);
|
||||
}
|
||||
lv_ll_clear(&ctx->image_ll);
|
||||
|
||||
lv_xml_style_t * style;
|
||||
LV_LL_READ(&ctx->style_ll, style) {
|
||||
lv_free((char *)style->name);
|
||||
@@ -294,6 +310,97 @@ static void process_const_element(lv_xml_parser_state_t * state, const char ** a
|
||||
lv_xml_register_const(&state->ctx, name, value);
|
||||
}
|
||||
|
||||
static void process_font_element(lv_xml_parser_state_t * state, const char * type, const char ** attrs)
|
||||
{
|
||||
const char * name = lv_xml_get_value_of(attrs, "name");
|
||||
if(name == NULL) {
|
||||
LV_LOG_WARN("'name' is missing from a font");
|
||||
return;
|
||||
}
|
||||
|
||||
const char * src_path = lv_xml_get_value_of(attrs, "src_path");
|
||||
if(src_path == NULL) {
|
||||
LV_LOG_WARN("'src_path' is missing from a `%s` font", name);
|
||||
return;
|
||||
}
|
||||
|
||||
const char * as_file = lv_xml_get_value_of(attrs, "as_file");
|
||||
if(as_file == NULL || as_file == false) {
|
||||
LV_LOG_INFO("Ignore non-file based font `%s`", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*E.g. <tiny_ttf name="inter_xl" src_path="fonts/Inter-SemiBold.ttf" size="22"/> */
|
||||
if(lv_streq(type, "tiny_ttf")) {
|
||||
const char * size = lv_xml_get_value_of(attrs, "size");
|
||||
if(size == NULL) {
|
||||
LV_LOG_WARN("'size' is missing from a `%s` tiny_ttf font", name);
|
||||
return;
|
||||
}
|
||||
#if LV_TINY_TTF_FILE_SUPPORT
|
||||
lv_font_t * font = lv_tiny_ttf_create_file(src_path, lv_xml_atoi(size));
|
||||
if(font == NULL) {
|
||||
LV_LOG_WARN("Couldn't load `%s` tiny_ttf font", name);
|
||||
return;
|
||||
}
|
||||
lv_result_t res = lv_xml_register_font(&state->ctx, name, font);
|
||||
if(res == LV_RESULT_INVALID) {
|
||||
LV_LOG_WARN("Failed to register `%s` tiny_ttf font", name);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_xml_font_t * f = lv_ll_get_head(&state->ctx.font_ll);
|
||||
f->font_destroy_cb = lv_tiny_ttf_destroy;
|
||||
|
||||
#else
|
||||
LV_LOG_WARN("LV_TINY_TTF_FILE_SUPPORT is not enabled for `%s` font", name);
|
||||
|
||||
#endif
|
||||
}
|
||||
else if(lv_streq(type, "bin")) {
|
||||
lv_font_t * font = lv_binfont_create(src_path);
|
||||
if(font == NULL) {
|
||||
LV_LOG_WARN("Couldn't load `%s` bin font", name);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_result_t res = lv_xml_register_font(&state->ctx, name, font);
|
||||
if(res == LV_RESULT_INVALID) {
|
||||
LV_LOG_WARN("Failed to register `%s` bin font", name);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_xml_font_t * f = lv_ll_get_head(&state->ctx.font_ll);
|
||||
f->font_destroy_cb = lv_binfont_destroy;
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("`%s` is a not supported font type", type);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_image_element(lv_xml_parser_state_t * state, const char * type, const char ** attrs)
|
||||
{
|
||||
const char * name = lv_xml_get_value_of(attrs, "name");
|
||||
if(name == NULL) {
|
||||
LV_LOG_WARN("'name' is missing from a font");
|
||||
return;
|
||||
}
|
||||
|
||||
const char * src_path = lv_xml_get_value_of(attrs, "src_path");
|
||||
if(src_path == NULL) {
|
||||
LV_LOG_WARN("'src_path' is missing from a `%s` font", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* E.g. <file name="avatar" src_path="avatar1.png">*/
|
||||
if(lv_streq(type, "file")) {
|
||||
lv_xml_register_image(&state->ctx, name, src_path);
|
||||
}
|
||||
else {
|
||||
LV_LOG_INFO("Ignore non-file image `%s`", name);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_subject_element(lv_xml_parser_state_t * state, const char * type, const char ** attrs)
|
||||
{
|
||||
const char * name = lv_xml_get_value_of(attrs, "name");
|
||||
@@ -310,7 +417,6 @@ static void process_subject_element(lv_xml_parser_state_t * state, const char *
|
||||
|
||||
lv_subject_t * subject = lv_malloc(sizeof(lv_subject_t));
|
||||
|
||||
|
||||
if(lv_streq(type, "int")) lv_subject_init_int(subject, lv_xml_atoi(value));
|
||||
else if(lv_streq(type, "color")) lv_subject_init_color(subject, lv_xml_to_color(value));
|
||||
else if(lv_streq(type, "string")) {
|
||||
@@ -540,6 +646,14 @@ static void start_metadata_handler(void * user_data, const char * name, const ch
|
||||
if(old_section != state->section) return; /*Ignore the section opening, e.g. <styles>*/
|
||||
lv_xml_style_register(&state->ctx, attrs);
|
||||
break;
|
||||
case LV_XML_PARSER_SECTION_FONTS:
|
||||
if(old_section != state->section) return; /*Ignore the section opening, e.g. <styles>*/
|
||||
process_font_element(state, name, attrs);
|
||||
break;
|
||||
case LV_XML_PARSER_SECTION_IMAGES:
|
||||
if(old_section != state->section) return; /*Ignore the section opening, e.g. <styles>*/
|
||||
process_image_element(state, name, attrs);
|
||||
break;
|
||||
|
||||
case LV_XML_PARSER_SECTION_SUBJECTS:
|
||||
if(old_section != state->section) return; /*Ignore the section opening, e.g. <subjects>*/
|
||||
|
||||
@@ -69,6 +69,14 @@ void lv_xml_parser_start_section(lv_xml_parser_state_t * state, const char * nam
|
||||
state->section = LV_XML_PARSER_SECTION_STYLES;
|
||||
return;
|
||||
}
|
||||
else if(lv_streq(name, "images")) {
|
||||
state->section = LV_XML_PARSER_SECTION_IMAGES;
|
||||
return;
|
||||
}
|
||||
else if(lv_streq(name, "fonts")) {
|
||||
state->section = LV_XML_PARSER_SECTION_FONTS;
|
||||
return;
|
||||
}
|
||||
else if(lv_streq(name, "subjects")) {
|
||||
state->section = LV_XML_PARSER_SECTION_SUBJECTS;
|
||||
return;
|
||||
|
||||
@@ -35,6 +35,8 @@ typedef enum {
|
||||
LV_XML_PARSER_SECTION_GRAD,
|
||||
LV_XML_PARSER_SECTION_GRAD_STOP,
|
||||
LV_XML_PARSER_SECTION_STYLES,
|
||||
LV_XML_PARSER_SECTION_FONTS,
|
||||
LV_XML_PARSER_SECTION_IMAGES,
|
||||
LV_XML_PARSER_SECTION_SUBJECTS,
|
||||
LV_XML_PARSER_SECTION_VIEW
|
||||
} lv_xml_parser_section_t;
|
||||
|
||||
@@ -33,6 +33,7 @@ extern "C" {
|
||||
typedef struct {
|
||||
const char * name;
|
||||
const lv_font_t * font;
|
||||
void (*font_destroy_cb)(lv_font_t *);
|
||||
} lv_xml_font_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
#define LV_USE_OBSERVER 1
|
||||
#define LV_USE_FILE_EXPLORER 1
|
||||
#define LV_USE_TINY_TTF 1
|
||||
#define LV_TINY_TTF_FILE_SUPPORT 1
|
||||
#define LV_USE_SYSMON 1
|
||||
#define LV_USE_MEM_MONITOR 1
|
||||
#define LV_USE_PERF_MONITOR 1
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
<globals>
|
||||
<config name="mylib" help="This is my great component library"/>
|
||||
<globals>
|
||||
<config name="mylib" help="This is my great component library" />
|
||||
|
||||
<consts>
|
||||
<int name="global_int" value="30"/>
|
||||
</consts>
|
||||
<consts>
|
||||
<int name="global_int" value="30" />
|
||||
</consts>
|
||||
|
||||
<styles>
|
||||
<style name="global_red" bg_color="0xf00" radius="global_small_unit" pad_all="12px"/>
|
||||
</styles>
|
||||
<styles>
|
||||
<style name="global_red" bg_color="0xf00"
|
||||
radius="global_small_unit" pad_all="12px" />
|
||||
</styles>
|
||||
|
||||
<subjects>
|
||||
<int name="global_subject" value="22"/>
|
||||
<int name="global_subject" value="22" />
|
||||
</subjects>
|
||||
|
||||
|
||||
<images>
|
||||
<file name="logo"
|
||||
src_path="A:src/test_assets/test_img_lvgl_logo.png" />
|
||||
</images>
|
||||
|
||||
<fonts>
|
||||
<bin name="my_bin_font" src_path="A:src/test_assets/test_font_2.fnt" as_file="true"/>
|
||||
<tiny_ttf name="noto_32"
|
||||
src_path="A:src/test_files/fonts/noto/NotoSansSC-Regular.ttf"
|
||||
size="32" as_file="true"/>
|
||||
</fonts>
|
||||
</globals>
|
||||
@@ -22,6 +22,11 @@ void test_xml_view3_scoping(void)
|
||||
lv_xml_create(lv_screen_active(), "view3", NULL);
|
||||
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/view3.png");
|
||||
|
||||
/*Fonts and image defined in globals.xml*/
|
||||
TEST_ASSERT_NOT_EQUAL(lv_font_get_default(), lv_xml_get_font(NULL, "my_bin_font"));
|
||||
TEST_ASSERT_NOT_EQUAL(lv_font_get_default(), lv_xml_get_font(NULL, "noto_32"));
|
||||
TEST_ASSERT_EQUAL_STRING("A:src/test_assets/test_img_lvgl_logo.png", lv_xml_get_image(NULL, "logo"));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user