Repository: lvgl/lvgl
Pull request #8207: Don't squash - further XML stuff
Author: login: kisvegabor
Created: 2025-05-06T08:39:25Z | Merged: 2025-05-06T18:40:38Z


### Notes
- Update the [Documentation](https://github.com/lvgl/lvgl/tree/master/docs) if needed.
- Add [Examples](https://github.com/lvgl/lvgl/tree/master/examples) if relevant.
- Add [Tests](https://github.com/lvgl/lvgl/blob/master/tests/README.md) if applicable.
- If you added new options to `lv_conf_template.h` run [lv_conf_internal_gen.py](https://github.com/lvgl/lvgl/blob/master/scripts/lv_conf_internal_gen.py) and update [Kconfig](https://github.com/lvgl/lvgl/blob/master/Kconfig).
- Run `scripts/code-format.py` (`astyle v3.4.12` needs to installed by running `cd scripts; ./install_astyle.sh`) and follow the [Code Conventions](https://docs.lvgl.io/master/CODING_STYLE.html).
- Mark the Pull request as [Draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request) while you are working on the first version, and mark is as _Ready_ when it's ready for review.
- When changes were requested, [re-request review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) to notify the maintainers.
- Help us to review this Pull Request! Anyone can [approve or request changes](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/approving-a-pull-request-with-required-reviews).



Diff:
diff --git a/demos/widgets/lv_demo_widgets.c b/demos/widgets/lv_demo_widgets.c
index 3851fe0290be..0d3b06837316 100644
--- a/demos/widgets/lv_demo_widgets.c
+++ b/demos/widgets/lv_demo_widgets.c
@@ -1323,7 +1323,7 @@ static void birthday_event_cb(lv_event_t * e)
                 lv_obj_align(calendar, LV_ALIGN_CENTER, 0, 30);
                 lv_obj_add_event_cb(calendar, calendar_event_cb, LV_EVENT_ALL, ta);
 
-                lv_calendar_header_dropdown_create(calendar);
+                lv_calendar_add_header_dropdown(calendar);
             }
         }
     }
diff --git a/docs/src/details/widgets/calendar.rst b/docs/src/details/widgets/calendar.rst
index 7f849d95502c..e5447428dc90 100644
--- a/docs/src/details/widgets/calendar.rst
+++ b/docs/src/details/widgets/calendar.rst
@@ -154,14 +154,14 @@ the API of the headers has been changed.**
 Arrow buttons
 -------------
 
-:cpp:expr:`lv_calendar_header_arrow_create(calendar)` creates a header that
+:cpp:expr:`lv_calendar_add_header_arrow(calendar)` creates a header that
 contains a left and right arrow on the sides and text between the arrows showing the
 current year and month.
 
 Drop-down
 ---------
 
-:cpp:expr:`lv_calendar_header_dropdown_create(calendar)` creates a header that
+:cpp:expr:`lv_calendar_add_header_dropdown(calendar)` creates a header that
 contains 2 Drop-Drown List Widgets for the year and month.
 
 .. _lv_calendar_example:
diff --git a/examples/widgets/calendar/lv_example_calendar_1.c b/examples/widgets/calendar/lv_example_calendar_1.c
index 7abc876c7b9e..35d006834899 100644
--- a/examples/widgets/calendar/lv_example_calendar_1.c
+++ b/examples/widgets/calendar/lv_example_calendar_1.c
@@ -41,9 +41,9 @@ void lv_example_calendar_1(void)
     lv_calendar_set_highlighted_dates(calendar, highlighted_days, 3);
 
 #if LV_USE_CALENDAR_HEADER_DROPDOWN
-    lv_calendar_header_dropdown_create(calendar);
+    lv_calendar_add_header_dropdown(calendar);
 #elif LV_USE_CALENDAR_HEADER_ARROW
-    lv_calendar_header_arrow_create(calendar);
+    lv_calendar_add_header_arrow(calendar);
 #endif
 }
 
diff --git a/examples/widgets/calendar/lv_example_calendar_2.c b/examples/widgets/calendar/lv_example_calendar_2.c
index 17aa511f8c19..5b26b96d4e12 100644
--- a/examples/widgets/calendar/lv_example_calendar_2.c
+++ b/examples/widgets/calendar/lv_example_calendar_2.c
@@ -11,9 +11,9 @@ void lv_example_calendar_2(void)
     lv_calendar_set_month_shown(calendar, 2024, 03);
 
 #if LV_USE_CALENDAR_HEADER_DROPDOWN
-    lv_calendar_header_dropdown_create(calendar);
+    lv_calendar_add_header_dropdown(calendar);
 #elif LV_USE_CALENDAR_HEADER_ARROW
-    lv_calendar_header_arrow_create(calendar);
+    lv_calendar_add_header_arrow(calendar);
 #endif
 
     lv_calendar_set_chinese_mode(calendar, true);
diff --git a/src/lv_api_map_v9_1.h b/src/lv_api_map_v9_1.h
index 8a55c003526d..162101365b43 100644
--- a/src/lv_api_map_v9_1.h
+++ b/src/lv_api_map_v9_1.h
@@ -119,6 +119,9 @@ extern "C" {
 
 #define lv_slider_set_left_value lv_slider_set_start_value
 
+#define lv_calendar_header_arrow_create     lv_calendar_add_header_arrow
+#define lv_calendar_header_dropdown_create  lv_calendar_add_header_dropdown
+
 #ifdef __cplusplus
 } /*extern "C"*/
 #endif
diff --git a/src/others/xml/lv_xml.c b/src/others/xml/lv_xml.c
index bfaeae7e9125..6a8918ce25cb 100644
--- a/src/others/xml/lv_xml.c
+++ b/src/others/xml/lv_xml.c
@@ -37,6 +37,8 @@
 #include "parsers/lv_xml_keyboard_parser.h"
 #include "parsers/lv_xml_arc_parser.h"
 #include "parsers/lv_xml_checkbox_parser.h"
+#include "parsers/lv_xml_canvas_parser.h"
+#include "parsers/lv_xml_calendar_parser.h"
 #include "parsers/lv_xml_event_parser.h"
 #include "../../libs/expat/expat.h"
 #include "../../draw/lv_draw_image.h"
@@ -101,6 +103,12 @@ void lv_xml_init(void)
     lv_xml_widget_register("lv_keyboard", lv_xml_keyboard_create, lv_xml_keyboard_apply);
     lv_xml_widget_register("lv_arc", lv_xml_arc_create, lv_xml_arc_apply);
     lv_xml_widget_register("lv_checkbox", lv_xml_checkbox_create, lv_xml_checkbox_apply);
+    lv_xml_widget_register("lv_canvas", lv_xml_canvas_create, lv_xml_canvas_apply);
+    lv_xml_widget_register("lv_calendar", lv_xml_calendar_create, lv_xml_calendar_apply);
+    lv_xml_widget_register("lv_calendar-header_arrow", lv_xml_calendar_header_arrow_create,
+                           lv_xml_calendar_header_arrow_apply);
+    lv_xml_widget_register("lv_calendar-header_dropdown", lv_xml_calendar_header_dropdown_create,
+                           lv_xml_calendar_header_dropdown_apply);
 
     lv_xml_widget_register("lv_event-call_function", lv_xml_event_call_function_create, lv_xml_event_call_function_apply);
 }
@@ -295,7 +303,7 @@ const char * lv_xml_get_const(lv_xml_component_ctx_t * ctx, const char * name)
 {
 
     if(ctx == NULL) ctx = lv_xml_component_get_ctx("globals");
-    if(ctx == NULL) return LV_RESULT_INVALID;
+    if(ctx == NULL) return NULL;
 
     lv_xml_const_t * cnst;
     if(ctx) {
@@ -350,7 +358,7 @@ lv_result_t lv_xml_register_image(lv_xml_component_ctx_t * ctx, const char * nam
 const void * lv_xml_get_image(lv_xml_component_ctx_t * ctx, const char * name)
 {
     if(ctx == NULL) ctx = lv_xml_component_get_ctx("globals");
-    if(ctx == NULL) return LV_RESULT_INVALID;
+    if(ctx == NULL) return NULL;
 
     lv_xml_image_t * img;
     if(ctx) {
@@ -400,7 +408,7 @@ lv_result_t lv_xml_register_event_cb(lv_xml_component_ctx_t * ctx, const char *
 lv_event_cb_t lv_xml_get_event_cb(lv_xml_component_ctx_t * ctx, const char * name)
 {
     if(ctx == NULL) ctx = lv_xml_component_get_ctx("globals");
-    if(ctx == NULL) return LV_RESULT_INVALID;
+    if(ctx == NULL) return NULL;
 
     lv_xml_event_cb_t * e;
     if(ctx) {
diff --git a/src/others/xml/lv_xml_style.c b/src/others/xml/lv_xml_style.c
index 819fd422b355..a186bc3db5fb 100644
--- a/src/others/xml/lv_xml_style.c
+++ b/src/others/xml/lv_xml_style.c
@@ -166,7 +166,11 @@ lv_result_t lv_xml_style_register(lv_xml_component_ctx_t * ctx, const char ** at
             }
         }
         else SET_STYLE_IF(width, lv_xml_to_size(value));
+        else SET_STYLE_IF(min_width, lv_xml_to_size(value));
+        else SET_STYLE_IF(max_width, lv_xml_to_size(value));
         else SET_STYLE_IF(height, lv_xml_to_size(value));
+        else SET_STYLE_IF(min_height, lv_xml_to_size(value));
+        else SET_STYLE_IF(max_height, lv_xml_to_size(value));
         else SET_STYLE_IF(length, lv_xml_to_size(value));
         else SET_STYLE_IF(radius, lv_xml_to_size(value));
 
@@ -267,6 +271,8 @@ lv_result_t lv_xml_style_register(lv_xml_component_ctx_t * ctx, const char ** at
         else SET_STYLE_IF(transform_skew_x, lv_xml_atoi(value));
         else SET_STYLE_IF(bitmap_mask_src, lv_xml_get_image(ctx, value));
         else SET_STYLE_IF(rotary_sensitivity, lv_xml_atoi(value));
+        else SET_STYLE_IF(recolor, lv_xml_to_color(value));
+        else SET_STYLE_IF(recolor_opa, lv_xml_to_opa(value));
 
         else SET_STYLE_IF(layout, lv_xml_layout_to_enum(value));
 
@@ -403,7 +409,11 @@ lv_grad_dsc_t * lv_xml_component_get_grad(lv_xml_component_ctx_t * ctx, const ch
 static lv_style_prop_t style_prop_text_to_enum(const char * txt)
 {
     if(lv_streq(txt, "width")) return LV_STYLE_WIDTH;
+    if(lv_streq(txt, "min_width")) return LV_STYLE_MIN_WIDTH;
+    if(lv_streq(txt, "max_width")) return LV_STYLE_MAX_WIDTH;
     else if(lv_streq(txt, "height")) return LV_STYLE_HEIGHT;
+    else if(lv_streq(txt, "min_height")) return LV_STYLE_MIN_HEIGHT;
+    else if(lv_streq(txt, "max_height")) return LV_STYLE_MAX_HEIGHT;
     else if(lv_streq(txt, "length")) return LV_STYLE_LENGTH;
     else if(lv_streq(txt, "radius")) return LV_STYLE_RADIUS;
 
@@ -497,6 +507,8 @@ static lv_style_prop_t style_prop_text_to_enum(const char * txt)
     else if(lv_streq(txt, "transform_skew_x")) return LV_STYLE_TRANSFORM_SKEW_X;
     else if(lv_streq(txt, "bitmap_mask_src")) return LV_STYLE_BITMAP_MASK_SRC;
     else if(lv_streq(txt, "rotary_sensitivity")) return LV_STYLE_ROTARY_SENSITIVITY;
+    else if(lv_streq(txt, "recolor")) return LV_STYLE_RECOLOR;
+    else if(lv_streq(txt, "recolor_opa")) return LV_STYLE_RECOLOR_OPA;
 
     else if(lv_streq(txt, "layout")) return LV_STYLE_LAYOUT;
 
diff --git a/src/others/xml/parsers/lv_xml_calendar_parser.c b/src/others/xml/parsers/lv_xml_calendar_parser.c
new file mode 100644
index 000000000000..4af1a9ff4e9e
--- /dev/null
+++ b/src/others/xml/parsers/lv_xml_calendar_parser.c
@@ -0,0 +1,104 @@
+/**
+ * @file lv_xml_calendar_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_xml_calendar_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    void * item = lv_xml_state_get_item(state);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+
+    for(int i = 0; attrs[i]; i += 2) {
+        const char * name = attrs[i];
+        const char * value = attrs[i + 1];
+
+        if(lv_streq("today_date", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            int32_t d = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_today_date(item, y, m, d);
+        }
+        else if(lv_streq("shown_month", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_month_shown(item, y, m);
+        }
+    }
+}
+
+void * lv_xml_calendar_header_dropdown_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_add_header_dropdown(lv_xml_state_get_parent(state));
+    return item;
+}
+
+void lv_xml_calendar_header_dropdown_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+}
+
+void * lv_xml_calendar_header_arrow_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_add_header_arrow(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+void lv_xml_calendar_header_arrow_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+}
+
+
+/**********************
+ *   STATIC FUNCTIONS
+ **********************/
+
+#endif /* LV_USE_XML */
diff --git a/src/others/xml/parsers/lv_xml_calendar_parser.h b/src/others/xml/parsers/lv_xml_calendar_parser.h
new file mode 100644
index 000000000000..881101ecb40a
--- /dev/null
+++ b/src/others/xml/parsers/lv_xml_calendar_parser.h
@@ -0,0 +1,43 @@
+/**
+ * @file lv_xml_calendar_parser.h
+ *
+ */
+
+#ifndef LV_CALENDAR_XML_PARSER_H
+#define LV_CALENDAR_XML_PARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "../lv_xml.h"
+#if LV_USE_XML
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs);
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs);
+void * lv_xml_calendar_header_arrow_create(lv_xml_parser_state_t * state, const char ** attrs);
+void lv_xml_calendar_header_arrow_apply(lv_xml_parser_state_t * state, const char ** attrs);
+void * lv_xml_calendar_header_dropdown_create(lv_xml_parser_state_t * state, const char ** attrs);
+void lv_xml_calendar_header_dropdown_apply(lv_xml_parser_state_t * state, const char ** attrs);
+
+/**********************
+ *      MACROS
+ **********************/
+#endif /* LV_USE_XML */
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*LV_CHART_XML_PARSE_H*/
diff --git a/src/others/xml/parsers/lv_xml_canvas_parser.c b/src/others/xml/parsers/lv_xml_canvas_parser.c
new file mode 100644
index 000000000000..dde37c6232fb
--- /dev/null
+++ b/src/others/xml/parsers/lv_xml_canvas_parser.c
@@ -0,0 +1,59 @@
+/**
+ * @file lv_xml_canvas_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+
+#include "lv_xml_canvas_parser.h"
+#if LV_USE_XML
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_canvas_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+
+    void * item = lv_canvas_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+void lv_xml_canvas_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    /*Apply the common properties, e.g. width, height, styles flags etc*/
+    lv_xml_obj_apply(state, attrs);
+}
+
+/**********************
+ *   STATIC FUNCTIONS
+ **********************/
+
+#endif /* LV_USE_XML */
diff --git a/src/others/xml/parsers/lv_xml_canvas_parser.h b/src/others/xml/parsers/lv_xml_canvas_parser.h
new file mode 100644
index 000000000000..040478e6590a
--- /dev/null
+++ b/src/others/xml/parsers/lv_xml_canvas_parser.h
@@ -0,0 +1,41 @@
+/**
+ * @file lv_xml_canvas_parser.h
+ *
+ */
+
+#ifndef LV_CANVAS_XML_PARSER_H
+#define LV_CANVAS_XML_PARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "../lv_xml.h"
+#if LV_USE_XML
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+void * lv_xml_canvas_create(lv_xml_parser_state_t * state, const char ** attrs);
+void lv_xml_canvas_apply(lv_xml_parser_state_t * state, const char ** attrs);
+
+
+/**********************
+ *      MACROS
+ **********************/
+
+#endif /* LV_USE_XML */
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*LV_BUTTON_XML_PARSE_H*/
diff --git a/src/others/xml/parsers/lv_xml_label_parser.c b/src/others/xml/parsers/lv_xml_label_parser.c
index 2ccca4fa6e76..acc99a34ad1f 100644
--- a/src/others/xml/parsers/lv_xml_label_parser.c
+++ b/src/others/xml/parsers/lv_xml_label_parser.c
@@ -24,6 +24,7 @@
  *  STATIC PROTOTYPES
  **********************/
 static lv_label_long_mode_t long_mode_text_to_enum_value(const char * txt);
+static void free_fmt_event_cb(lv_event_t * e);
 
 /**********************
  *  STATIC VARIABLES
@@ -58,12 +59,27 @@ void lv_xml_label_apply(lv_xml_parser_state_t * state, const char ** attrs)
         if(lv_streq("text", name)) lv_label_set_text(item, value);
         if(lv_streq("long_mode", name)) lv_label_set_long_mode(item, long_mode_text_to_enum_value(value));
         if(lv_streq("bind_text", name)) {
-            lv_subject_t * subject = lv_xml_get_subject(&state->ctx, value);
-            if(subject) {
-                lv_label_bind_text(item, subject, NULL);
-            }
-            else {
-                LV_LOG_WARN("Subject \"%s\" doesn't exist in label bind_text", value);
+            char buf[256];
+            lv_strncpy(buf, value, sizeof(buf));
+            char * bufp = buf;
+            char * subject_name = lv_xml_split_str(&bufp, ' ');
+            if(subject_name) {
+                lv_subject_t * subject = lv_xml_get_subject(&state->ctx, subject_name);
+                if(subject) {
+                    char * fmt = bufp; /*The second part is the format text*/
+                    if(fmt && fmt[0] == '\0') fmt = NULL;
+                    if(fmt) {
+                        if(fmt[0] == '\'') fmt++;
+                        size_t fmt_len = lv_strlen(fmt);
+                        if(fmt_len != 0 && fmt[fmt_len - 1] == '\'') fmt[fmt_len - 1] = '\0';
+                        fmt = lv_strdup(fmt);
+                        lv_obj_add_event_cb(item, free_fmt_event_cb, LV_EVENT_DELETE, fmt);
+                    }
+                    lv_label_bind_text(item, subject, fmt);
+                }
+                else {
+                    LV_LOG_WARN("Subject \"%s\" doesn't exist in label bind_text", value);
+                }
             }
         }
     }
@@ -85,4 +101,10 @@ static lv_label_long_mode_t long_mode_text_to_enum_value(const char * txt)
     return 0; /*Return 0 in lack of a better option. */
 }
 
+static void free_fmt_event_cb(lv_event_t * e)
+{
+    void * fmt = lv_event_get_user_data(e);
+    lv_free(fmt);
+}
+
 #endif /* LV_USE_XML */
diff --git a/src/others/xml/parsers/lv_xml_obj_parser.c b/src/others/xml/parsers/lv_xml_obj_parser.c
index a105e58ae7a3..59d9e674dafa 100644
--- a/src/others/xml/parsers/lv_xml_obj_parser.c
+++ b/src/others/xml/parsers/lv_xml_obj_parser.c
@@ -266,7 +266,11 @@ static void apply_styles(lv_xml_parser_state_t * state, lv_obj_t * obj, const ch
     const char * prop_name = lv_xml_style_string_process(name_local, &selector);
 
     SET_STYLE_IF(width, lv_xml_to_size(value));
+    else SET_STYLE_IF(min_width, lv_xml_to_size(value));
+    else SET_STYLE_IF(max_width, lv_xml_to_size(value));
     else SET_STYLE_IF(height, lv_xml_to_size(value));
+    else SET_STYLE_IF(min_height, lv_xml_to_size(value));
+    else SET_STYLE_IF(max_height, lv_xml_to_size(value));
     else SET_STYLE_IF(length, lv_xml_to_size(value));
     else SET_STYLE_IF(radius, lv_xml_to_size(value));
 
@@ -367,6 +371,8 @@ static void apply_styles(lv_xml_parser_state_t * state, lv_obj_t * obj, const ch
     else SET_STYLE_IF(transform_skew_x, lv_xml_atoi(value));
     else SET_STYLE_IF(bitmap_mask_src, lv_xml_get_image(&state->ctx, value));
     else SET_STYLE_IF(rotary_sensitivity, lv_xml_atoi(value));
+    else SET_STYLE_IF(recolor, lv_xml_to_color(value));
+    else SET_STYLE_IF(recolor_opa, lv_xml_to_opa(value));
 
     else SET_STYLE_IF(layout, lv_xml_layout_to_enum(value));
 
diff --git a/src/widgets/calendar/lv_calendar_header_arrow.c b/src/widgets/calendar/lv_calendar_header_arrow.c
index 7234fd62f970..caf0dd52d576 100644
--- a/src/widgets/calendar/lv_calendar_header_arrow.c
+++ b/src/widgets/calendar/lv_calendar_header_arrow.c
@@ -53,7 +53,7 @@ static const char * month_names_def[12] = LV_CALENDAR_DEFAULT_MONTH_NAMES;
  *   GLOBAL FUNCTIONS
  **********************/
 
-lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent)
+lv_obj_t * lv_calendar_add_header_arrow(lv_obj_t * parent)
 {
     lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_header_arrow_class, parent);
     lv_obj_class_init_obj(obj);
diff --git a/src/widgets/calendar/lv_calendar_header_arrow.h b/src/widgets/calendar/lv_calendar_header_arrow.h
index a04b355cc776..54f4fbed7b5b 100644
--- a/src/widgets/calendar/lv_calendar_header_arrow.h
+++ b/src/widgets/calendar/lv_calendar_header_arrow.h
@@ -34,7 +34,7 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_calendar_header_arrow_cl
  * @param parent    pointer to a calendar object.
  * @return          the created header
  */
-lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent);
+lv_obj_t * lv_calendar_add_header_arrow(lv_obj_t * parent);
 
 /**********************
  *      MACROS
diff --git a/src/widgets/calendar/lv_calendar_header_dropdown.c b/src/widgets/calendar/lv_calendar_header_dropdown.c
index b70fbe9175eb..2052981827e0 100644
--- a/src/widgets/calendar/lv_calendar_header_dropdown.c
+++ b/src/widgets/calendar/lv_calendar_header_dropdown.c
@@ -61,7 +61,7 @@ static const char * year_list = {
  *   GLOBAL FUNCTIONS
  **********************/
 
-lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent)
+lv_obj_t * lv_calendar_add_header_dropdown(lv_obj_t * parent)
 {
     lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_header_dropdown_class, parent);
     lv_obj_class_init_obj(obj);
diff --git a/src/widgets/calendar/lv_calendar_header_dropdown.h b/src/widgets/calendar/lv_calendar_header_dropdown.h
index 1ca87762e2eb..13b01304efbd 100644
--- a/src/widgets/calendar/lv_calendar_header_dropdown.h
+++ b/src/widgets/calendar/lv_calendar_header_dropdown.h
@@ -38,7 +38,7 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_calendar_header_dropdown
  * @param parent    pointer to a calendar object.
  * @return          the created header
  */
-lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent);
+lv_obj_t * lv_calendar_add_header_dropdown(lv_obj_t * parent);
 
 /**
  * Sets a custom calendar year list
diff --git a/tests/ref_imgs/xml/lv_calendar.png b/tests/ref_imgs/xml/lv_calendar.png
new file mode 100644
index 000000000000..d336c68379b4
Binary files /dev/null and b/tests/ref_imgs/xml/lv_calendar.png differ
diff --git a/tests/ref_imgs/xml/lv_canvas.png b/tests/ref_imgs/xml/lv_canvas.png
new file mode 100644
index 000000000000..7b9b1b42b932
Binary files /dev/null and b/tests/ref_imgs/xml/lv_canvas.png differ
diff --git a/tests/ref_imgs/xml/lv_label.png b/tests/ref_imgs/xml/lv_label.png
index 0cd970a5402b..38704a98f827 100644
Binary files a/tests/ref_imgs/xml/lv_label.png and b/tests/ref_imgs/xml/lv_label.png differ
diff --git a/tests/ref_imgs_vg_lite/xml/lv_calendar.png b/tests/ref_imgs_vg_lite/xml/lv_calendar.png
new file mode 100644
index 000000000000..5daae3e663d6
Binary files /dev/null and b/tests/ref_imgs_vg_lite/xml/lv_calendar.png differ
diff --git a/tests/ref_imgs_vg_lite/xml/lv_canvas.png b/tests/ref_imgs_vg_lite/xml/lv_canvas.png
new file mode 100644
index 000000000000..7b9b1b42b932
Binary files /dev/null and b/tests/ref_imgs_vg_lite/xml/lv_canvas.png differ
diff --git a/tests/ref_imgs_vg_lite/xml/lv_label.png b/tests/ref_imgs_vg_lite/xml/lv_label.png
index bab25a1dafad..7853c079c523 100644
Binary files a/tests/ref_imgs_vg_lite/xml/lv_label.png and b/tests/ref_imgs_vg_lite/xml/lv_label.png differ
diff --git a/tests/src/test_cases/widgets/test_calendar.c b/tests/src/test_cases/widgets/test_calendar.c
index 2aba76358c49..e671b38fd5c7 100644
--- a/tests/src/test_cases/widgets/test_calendar.c
+++ b/tests/src/test_cases/widgets/test_calendar.c
@@ -164,7 +164,7 @@ void test_calendar_get_highlighted_dates_num(void)
 
 void test_calendar_header_dropdown_create_gui(void)
 {
-    lv_calendar_header_dropdown_create(g_calendar);
+    lv_calendar_add_header_dropdown(g_calendar);
 
     lv_calendar_set_month_shown(g_calendar, 2022, 9);
 
@@ -173,7 +173,7 @@ void test_calendar_header_dropdown_create_gui(void)
 
 void test_calendar_header_arrow_create_gui(void)
 {
-    lv_calendar_header_arrow_create(g_calendar);
+    lv_calendar_add_header_arrow(g_calendar);
 
     lv_calendar_set_month_shown(g_calendar, 2022, 10);    // Use October to avoid month name sliding
 
@@ -213,7 +213,7 @@ void test_calendar_custom_year_list(void)
 {
     lv_obj_t  * calendar = lv_calendar_create(lv_screen_active());
 
-    lv_calendar_header_dropdown_create(calendar);
+    lv_calendar_add_header_dropdown(calendar);
 
     const char * years = "2024\n2023\n2022\n2021\n2020\n2019";
     lv_calendar_header_dropdown_set_year_list(calendar, years);
diff --git a/tests/src/test_cases/xml/test_xml_calendar.c b/tests/src/test_cases/xml/test_xml_calendar.c
new file mode 100644
index 000000000000..ff279fc29c62
--- /dev/null
+++ b/tests/src/test_cases/xml/test_xml_calendar.c
@@ -0,0 +1,42 @@
+
+#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_calendar_with_attrs(void)
+{
+    lv_obj_t * scr = lv_screen_active();
+
+    const char * calendar_attrs[] = {
+        "width", "200",
+        "height", "200",
+        "x", "10",
+        "y", "10",
+        "today_date", "2025 05 06",
+        "shown_month", "2025 05",
+        NULL, NULL,
+    };
+    lv_obj_t * calendar;
+    calendar = lv_xml_create(scr, "lv_calendar", calendar_attrs);
+    lv_xml_create(calendar, "lv_calendar-header_arrow", NULL);
+
+    calendar = lv_xml_create(scr, "lv_calendar", calendar_attrs);
+    lv_obj_set_x(calendar, 250);
+    lv_xml_create(calendar, "lv_calendar-header_dropdown", NULL);
+
+    TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_calendar.png");
+}
+
+#endif
diff --git a/tests/src/test_cases/xml/test_xml_canvas.c b/tests/src/test_cases/xml/test_xml_canvas.c
new file mode 100644
index 000000000000..451e2319929e
--- /dev/null
+++ b/tests/src/test_cases/xml/test_xml_canvas.c
@@ -0,0 +1,39 @@
+#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_canvas_with_attrs(void)
+{
+    lv_obj_t * scr = lv_screen_active();
+
+    const char * canvas1_attrs[] = {
+        "name", "c1",
+        "x", "10",
+        "y", "10",
+        NULL, NULL,
+    };
+
+    lv_xml_create(scr, "lv_canvas", canvas1_attrs);
+
+    lv_obj_t * c1 = lv_obj_find_by_name(NULL, "c1");
+    TEST_ASSERT_NOT_NULL(c1);
+    lv_draw_buf_t  * draw_buf = lv_draw_buf_create(100, 100, LV_COLOR_FORMAT_XRGB8888, LV_STRIDE_AUTO);
+    lv_canvas_set_draw_buf(c1, draw_buf);
+    lv_canvas_fill_bg(c1, lv_color_hex3(0x234), LV_OPA_COVER);
+    TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_canvas.png");
+    lv_draw_buf_destroy(draw_buf);
+}
+
+#endif
diff --git a/tests/src/test_cases/xml/test_xml_label.c b/tests/src/test_cases/xml/test_xml_label.c
index 7b9b10f2569d..6f54e96bbec9 100644
--- a/tests/src/test_cases/xml/test_xml_label.c
+++ b/tests/src/test_cases/xml/test_xml_label.c
@@ -18,7 +18,7 @@ void test_xml_label_with_attrs(void)
 {
     lv_obj_t * scr = lv_screen_active();
 
-    const char * textarea1_attrs[] = {
+    const char * label1_attrs[] = {
         "text", "This is the text with ellipses added automatically",
         "long_mode", "dots",
         "width", "100",
@@ -29,8 +29,20 @@ void test_xml_label_with_attrs(void)
         NULL, NULL,
     };
 
-    lv_xml_create(scr, "lv_label", textarea1_attrs);
+    lv_xml_create(scr, "lv_label", label1_attrs);
 
+    static lv_subject_t s1;
+    lv_subject_init_int(&s1, 20);
+    lv_xml_register_subject(NULL, "s1", &s1);
+
+    const char * label2_attrs[] = {
+        "bind_text", "s1 'We have %d users'",
+        "y", "10",
+        "x", "5",
+        NULL, NULL,
+    };
+
+    lv_xml_create(scr, "lv_label", label2_attrs);
 
     TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_label.png");
 }
diff --git a/xmls/globals.xml b/xmls/globals.xml
index fc39d789565a..e19fd266eb1a 100644
--- a/xmls/globals.xml
+++ b/xmls/globals.xml
@@ -120,7 +120,11 @@
 	    <prop name="x" type="coords"/>
 	    <prop name="y" type="coords"/>
 	    <prop name="height" type="coords"/>
+	    <prop name="min_height" type="coords"/>
+	    <prop name="max_height" type="coords"/>
 	    <prop name="width" type="coords"/>
+	    <prop name="min_width" type="coords"/>
+	    <prop name="max_width" type="coords"/>
 	    <prop name="length" type="coords"/>
 
 	    <prop name="pad_top" type="int"/>
diff --git a/xmls/lv_calendar.xml b/xmls/lv_calendar.xml
index 7afca8a29320..cae4fd3a466c 100644
--- a/xmls/lv_calendar.xml
+++ b/xmls/lv_calendar.xml
@@ -10,24 +10,12 @@ Example
 	    	<param name="month" type="int" help=""/>
 	    	<param name="day" type="int" help=""/>
 	    </prop>
-	    <prop name="shown_date" help="Shown date">
+	    <prop name="month_shown" help="Shown date">
 	    	<param name="year" type="int" help=""/>
 	    	<param name="month" type="int" help=""/>
-	    	<param name="day" type="int" help=""/>
-	    </prop>
-	    <prop name="shown_date" help="Shown date">
-	    	<param name="year" type="int" help=""/>
-	    	<param name="month" type="int" help=""/>
-	    	<param name="day" type="int" help=""/>
-	    </prop>
-	    <prop name="day_names" help="set the names for the days">
-	    	<param name="names" type="string[7]" help="the 7 day names as an array"/>
-	    </prop>
-	    <prop name="chinese_mode" help="">
-		    <param name="enable" type="bool" help=""/>
 	    </prop>
-		<element name="header_arrow" access="explicit" help=""/>
-		<element name="header_dropdown" access="explicit" help="">
+		<element name="header_arrow" access="add" help=""/>
+		<element name="header_dropdown" access="add" help="">
 			<prop name="year_list">
 				<param name="list" type="string" />
 			</prop>
diff --git a/xmls/lv_obj.xml b/xmls/lv_obj.xml
index 061fc3482fe6..601b79c9613b 100644
--- a/xmls/lv_obj.xml
+++ b/xmls/lv_obj.xml
@@ -51,7 +51,11 @@ Example
 	    <prop name="style_x" type="coords"/>
 	    <prop name="style_y" type="coords"/>
 	    <prop name="style_height" type="coords"/>
+	    <prop name="style_min_height" type="coords"/>
+	    <prop name="style_max_height" type="coords"/>
 	    <prop name="style_width" type="coords"/>
+	    <prop name="style_min_width" type="coords"/>
+	    <prop name="style_max_width" type="coords"/>
 	    <prop name="style_align" type="enum:lv_align"/>
 	    <prop name="style_radius" type="int"/>
 	    <prop name="style_bg_color" type="color"/>
@@ -166,32 +170,32 @@ Example
 	    </prop>
 	    <prop name="bind_state_if_eq">
 	    	<param name="subject" type="subject"/>
-	    	<param name="flag" type="enum:lv_obj_flag"/>
+	    	<param name="flag" type="enum:lv_state"/>
 	    	<param name="ref_value" type="int"/>
 	    </prop>
 	    <prop name="bind_state_if_not_eq">
 	    	<param name="subject" type="subject"/>
-	    	<param name="flag" type="enum:lv_obj_flag"/>
+	    	<param name="flag" type="enum:lv_state"/>
 	    	<param name="ref_value" type="int"/>
 	    </prop>
 	    <prop name="bind_state_if_gt">
 	    	<param name="subject" type="subject"/>
-	    	<param name="flag" type="enum:lv_obj_flag"/>
+	    	<param name="flag" type="enum:lv_state"/>
 	    	<param name="ref_value" type="int"/>
 	    </prop>
 	    <prop name="bind_state_if_ge">
 	    	<param name="subject" type="subject"/>
-	    	<param name="flag" type="enum:lv_obj_flag"/>
+	    	<param name="flag" type="enum:lv_state"/>
 	    	<param name="ref_value" type="int"/>
 	    </prop>
 	    <prop name="bind_state_if_lt">
 	    	<param name="subject" type="subject"/>
-	    	<param name="flag" type="enum:lv_obj_flag"/>
+	    	<param name="flag" type="enum:lv_state"/>
 	    	<param name="ref_value" type="int"/>
 	    </prop>
 	    <prop name="bind_state_if_le">
 	    	<param name="subject" type="subject"/>
-	    	<param name="flag" type="enum:lv_obj_flag"/>
+	    	<param name="flag" type="enum:lv_state"/>
 	    	<param name="ref_value" type="int"/>
 	    </prop>
 	</api>


Reviews:
user: login: uLipe
body: Looks good, I have some minor comments
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T15:53:45Z
user: login: kisvegabor
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T16:05:02Z
user: login: kisvegabor
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T16:06:19Z
user: login: uLipe
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T16:07:58Z
user: login: AndreCostaaa
body: Small issues that should be fixed to avoid unexpected crashes

Also, tests are great, we should work towards creating examples from them :rocket: 
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-06T17:12:14Z
user: login: AndreCostaaa
body: Thanks! Looking good 🚀  
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-05-06T17:45:26Z
user: login: uLipe
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T18:24:04Z
user: login: AndreCostaaa
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-06T18:28:51Z

Review comments:
diff_hunk: @@ -0,0 +1,110 @@
+/**
+ * @file lv_xml_calendar_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_xml_calendar_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    void * item = lv_xml_state_get_item(state);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+
+    for(int i = 0; attrs[i]; i += 2) {
+        const char * name = attrs[i];
+        const char * value = attrs[i + 1];
+
+        if(lv_streq("today_date", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            int32_t d = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_today_date(item, y, m, d);
+        }
+        else if(lv_streq("shown_month", name)) {
path: src/others/xml/parsers/lv_xml_calendar_parser.c
user: login: uLipe
body: What happens when both if and else if conditions are not met? Is it okay to not have an else with the default behavior here?
created_at: 2025-05-06T15:52:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,110 @@
+/**
+ * @file lv_xml_calendar_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_xml_calendar_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    void * item = lv_xml_state_get_item(state);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+
+    for(int i = 0; attrs[i]; i += 2) {
+        const char * name = attrs[i];
+        const char * value = attrs[i + 1];
+
+        if(lv_streq("today_date", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            int32_t d = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_today_date(item, y, m, d);
+        }
+        else if(lv_streq("shown_month", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_month_shown(item, y, m);
+        }
+    }
+}
+
+void * lv_xml_calendar_header_dropdown_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_add_header_dropdown(lv_xml_state_get_parent(state));
+    return item;
+}
+
+void lv_xml_calendar_header_dropdown_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(state);
+    LV_UNUSED(attrs);
path: src/others/xml/parsers/lv_xml_calendar_parser.c
user: login: uLipe
body: Why they marked as not used since the inner function actually consumes them?
created_at: 2025-05-06T15:52:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,110 @@
+/**
+ * @file lv_xml_calendar_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_xml_calendar_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    void * item = lv_xml_state_get_item(state);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+
+    for(int i = 0; attrs[i]; i += 2) {
+        const char * name = attrs[i];
+        const char * value = attrs[i + 1];
+
+        if(lv_streq("today_date", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            int32_t d = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_today_date(item, y, m, d);
+        }
+        else if(lv_streq("shown_month", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_month_shown(item, y, m);
+        }
+    }
+}
+
+void * lv_xml_calendar_header_dropdown_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_add_header_dropdown(lv_xml_state_get_parent(state));
+    return item;
+}
+
+void lv_xml_calendar_header_dropdown_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(state);
+    LV_UNUSED(attrs);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+}
+
+void * lv_xml_calendar_header_arrow_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_add_header_arrow(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+void lv_xml_calendar_header_arrow_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(state);
path: src/others/xml/parsers/lv_xml_calendar_parser.c
user: login: uLipe
body: Also here
created_at: 2025-05-06T15:52:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,110 @@
+/**
+ * @file lv_xml_calendar_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_xml_calendar_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    void * item = lv_xml_state_get_item(state);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+
+    for(int i = 0; attrs[i]; i += 2) {
+        const char * name = attrs[i];
+        const char * value = attrs[i + 1];
+
+        if(lv_streq("today_date", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            int32_t d = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_today_date(item, y, m, d);
+        }
+        else if(lv_streq("shown_month", name)) {
path: src/others/xml/parsers/lv_xml_calendar_parser.c
user: login: kisvegabor
body: Yes, in this case the property will be handles somewhere else
created_at: 2025-05-06T16:05:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,110 @@
+/**
+ * @file lv_xml_calendar_parser.c
+ *
+ */
+
+/*********************
+ *      INCLUDES
+ *********************/
+#include "lv_xml_calendar_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ *  STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ *  STATIC VARIABLES
+ **********************/
+
+/**********************
+ *      MACROS
+ **********************/
+
+/**********************
+ *   GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_calendar_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_create(lv_xml_state_get_parent(state));
+
+    return item;
+}
+
+
+void lv_xml_calendar_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    void * item = lv_xml_state_get_item(state);
+
+    lv_xml_obj_apply(state, attrs); /*Apply the common properties, e.g. width, height, styles flags etc*/
+
+    for(int i = 0; attrs[i]; i += 2) {
+        const char * name = attrs[i];
+        const char * value = attrs[i + 1];
+
+        if(lv_streq("today_date", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            int32_t d = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_today_date(item, y, m, d);
+        }
+        else if(lv_streq("shown_month", name)) {
+            const char * bufp = value;
+            int32_t y = lv_xml_atoi_split(&bufp, ' ');
+            int32_t m = lv_xml_atoi_split(&bufp, ' ');
+            lv_calendar_set_month_shown(item, y, m);
+        }
+    }
+}
+
+void * lv_xml_calendar_header_dropdown_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(attrs);
+    void * item = lv_calendar_add_header_dropdown(lv_xml_state_get_parent(state));
+    return item;
+}
+
+void lv_xml_calendar_header_dropdown_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+    LV_UNUSED(state);
+    LV_UNUSED(attrs);
path: src/others/xml/parsers/lv_xml_calendar_parser.c
user: login: kisvegabor
body: Upps, oversight. Both are fixed 
created_at: 2025-05-06T16:06:18Z
author_association: MEMBER
diff_hunk: @@ -58,12 +58,25 @@ void lv_xml_label_apply(lv_xml_parser_state_t * state, const char ** attrs)
         if(lv_streq("text", name)) lv_label_set_text(item, value);
         if(lv_streq("long_mode", name)) lv_label_set_long_mode(item, long_mode_text_to_enum_value(value));
         if(lv_streq("bind_text", name)) {
-            lv_subject_t * subject = lv_xml_get_subject(&state->ctx, value);
-            if(subject) {
-                lv_label_bind_text(item, subject, NULL);
-            }
-            else {
-                LV_LOG_WARN("Subject \"%s\" doesn't exist in label bind_text", value);
+            char buf[256];
+            lv_strncpy(buf, value, sizeof(buf));
+            char * bufp = buf;
+            char * subject_name = lv_xml_split_str(&bufp, ' ');
+            if(subject_name) {
+                lv_subject_t * subject = lv_xml_get_subject(&state->ctx, subject_name);
+                if(subject) {
+                    char * fmt = bufp; /*The second part is the format text*/
+                    if(fmt[0] == '\0') fmt = NULL;
path: src/others/xml/parsers/lv_xml_label_parser.c
user: login: AndreCostaaa
body: 
```suggestion
                    if(fmt && fmt[0] == '\0') fmt = NULL;
```
`fmt[0]` will cause a crash if `fmt` is NULL. This just checks for it, if it's NULL, it doesn't do the assignment which is fine since it's already NULL
created_at: 2025-05-06T17:04:38Z
author_association: COLLABORATOR
diff_hunk: @@ -58,12 +58,25 @@ void lv_xml_label_apply(lv_xml_parser_state_t * state, const char ** attrs)
         if(lv_streq("text", name)) lv_label_set_text(item, value);
         if(lv_streq("long_mode", name)) lv_label_set_long_mode(item, long_mode_text_to_enum_value(value));
         if(lv_streq("bind_text", name)) {
-            lv_subject_t * subject = lv_xml_get_subject(&state->ctx, value);
-            if(subject) {
-                lv_label_bind_text(item, subject, NULL);
-            }
-            else {
-                LV_LOG_WARN("Subject \"%s\" doesn't exist in label bind_text", value);
+            char buf[256];
+            lv_strncpy(buf, value, sizeof(buf));
+            char * bufp = buf;
+            char * subject_name = lv_xml_split_str(&bufp, ' ');
+            if(subject_name) {
+                lv_subject_t * subject = lv_xml_get_subject(&state->ctx, subject_name);
+                if(subject) {
+                    char * fmt = bufp; /*The second part is the format text*/
+                    if(fmt[0] == '\0') fmt = NULL;
+                    if(fmt) {
+                        if(fmt[0] == '\'') fmt++;
+                        size_t fmt_len = lv_strlen(fmt);
+                        if(fmt[fmt_len - 1] == '\'') fmt[fmt_len - 1] = '\0';
path: src/others/xml/parsers/lv_xml_label_parser.c
user: login: AndreCostaaa
body: ```suggestion
                        if(fmt_len != 0 && fmt[fmt_len - 1] == '\'') fmt[fmt_len - 1] = '\0';
```

else `fmt_len - 1` will overflow since we're dealing with `size_t`
created_at: 2025-05-06T17:08:14Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,39 @@
+#if LV_BUILD_TEST || 1
path: tests/src/test_cases/xml/test_xml_canvas.c
user: login: AndreCostaaa
body: ```suggestion
#if LV_BUILD_TEST
```
created_at: 2025-05-06T17:09:52Z
author_association: COLLABORATOR

PR comments:
user: login: kisvegabor
created_at: 2025-05-06T17:42:57Z
body: Thanks @AndreCostaaa, all suggestions were valid and they were added. 
author_association: MEMBER
user: login: kisvegabor
created_at: 2025-05-06T18:16:21Z
body: Sorry, I just found a bug, PTAL.
`fmt` was on stack only its address was saved: https://github.com/lvgl/lvgl/pull/8207/files#diff-8054c85c132615f1884f16ebbebc37b313423dfc1432437bba21c079f6d2beadR75-R76
author_association: MEMBER
user: login: kisvegabor
created_at: 2025-05-06T18:40:47Z
body: Thank you for the quick reviews! :100: 

author_association: MEMBER