diff --git a/examples/others/xml/view.xml b/examples/others/xml/view.xml
index 89390df2b..cca279f6d 100644
--- a/examples/others/xml/view.xml
+++ b/examples/others/xml/view.xml
@@ -12,6 +12,10 @@
-
+
+
+
+
+
diff --git a/src/others/xml/lv_xml.c b/src/others/xml/lv_xml.c
index 255fedd14..feec65c47 100644
--- a/src/others/xml/lv_xml.c
+++ b/src/others/xml/lv_xml.c
@@ -32,6 +32,7 @@
#include "parsers/lv_xml_roller_parser.h"
#include "parsers/lv_xml_scale_parser.h"
#include "parsers/lv_xml_spangroup_parser.h"
+#include "parsers/lv_xml_event_parser.h"
#include "../../libs/expat/expat.h"
#include "../../draw/lv_draw_image.h"
@@ -55,6 +56,7 @@ static void register_builtin_fonts(void);
**********************/
static lv_ll_t font_ll;
static lv_ll_t image_ll;
+static lv_ll_t event_cb_ll;
/**********************
* MACROS
@@ -68,6 +70,7 @@ void lv_xml_init(void)
{
lv_ll_init(&font_ll, sizeof(lv_xml_font_t));
lv_ll_init(&image_ll, sizeof(lv_xml_image_t));
+ lv_ll_init(&event_cb_ll, sizeof(lv_xml_event_cb_t));
lv_xml_component_init();
@@ -96,6 +99,8 @@ void lv_xml_init(void)
lv_xml_widget_register("lv_scale-section", lv_xml_scale_section_create, lv_xml_scale_section_apply);
lv_xml_widget_register("lv_spangroup", lv_xml_spangroup_create, lv_xml_spangroup_apply);
lv_xml_widget_register("lv_spangroup-span", lv_xml_spangroup_span_create, lv_xml_spangroup_span_apply);
+
+ lv_xml_widget_register("lv_event-call_function", lv_xml_event_call_function_create, lv_xml_event_call_function_apply);
}
void * lv_xml_create_from_ctx(lv_obj_t * parent, lv_xml_component_ctx_t * parent_ctx, lv_xml_component_ctx_t * ctx,
@@ -182,7 +187,8 @@ const lv_font_t * lv_xml_get_font(const char * name)
if(lv_streq(f->name, name)) return f->font;
}
- return NULL;
+ LV_LOG_WARN("No font was found with name \"%s\". Using LV_FONT_DEFAULT instead.", name);
+ return LV_FONT_DEFAULT;
}
lv_result_t lv_xml_register_image(const char * name, const void * src)
@@ -206,6 +212,28 @@ const void * lv_xml_get_image(const char * name)
if(lv_streq(img->name, name)) return img->src;
}
+ LV_LOG_WARN("No image was found with name \"%s\"", name);
+ return NULL;
+}
+
+lv_result_t lv_xml_register_event_cb(const char * name, lv_event_cb_t cb)
+{
+ lv_xml_event_cb_t * e = lv_ll_ins_head(&event_cb_ll);
+ e->name = lv_strdup(name);
+ e->cb = cb;
+
+ return LV_RESULT_OK;
+}
+
+
+lv_event_cb_t lv_xml_get_event_cb(const char * name)
+{
+ lv_xml_event_cb_t * e;
+ LV_LL_READ(&event_cb_ll, e) {
+ if(lv_streq(e->name, name)) return e->cb;
+ }
+
+ LV_LOG_WARN("No event_cb was found with name \"%s\"", name);
return NULL;
}
diff --git a/src/others/xml/lv_xml.h b/src/others/xml/lv_xml.h
index 1a0948d9b..ec059e997 100644
--- a/src/others/xml/lv_xml.h
+++ b/src/others/xml/lv_xml.h
@@ -14,6 +14,7 @@ extern "C" {
* INCLUDES
*********************/
#include "../../misc/lv_types.h"
+#include "../../misc/lv_event.h"
#if LV_USE_XML
/*********************
@@ -44,6 +45,10 @@ lv_result_t lv_xml_register_image(const char * name, const void * src);
const void * lv_xml_get_image(const char * name);
+lv_result_t lv_xml_register_event_cb(const char * name, lv_event_cb_t cb);
+
+lv_event_cb_t lv_xml_get_event_cb(const char * name);
+
/**********************
* MACROS
**********************/
diff --git a/src/others/xml/lv_xml_component_private.h b/src/others/xml/lv_xml_component_private.h
index 3f2f37aa9..069758c12 100644
--- a/src/others/xml/lv_xml_component_private.h
+++ b/src/others/xml/lv_xml_component_private.h
@@ -18,6 +18,7 @@ extern "C" {
#include "lv_xml_utils.h"
#include "../../misc/lv_ll.h"
+#include "../../misc/lv_style.h"
/**********************
* TYPEDEFS
@@ -37,6 +38,22 @@ struct _lv_xml_component_ctx_t {
struct _lv_xml_component_ctx_t * next;
};
+typedef struct {
+ const char * name;
+ const char * value;
+} lv_xml_const_t;
+
+typedef struct {
+ const char * name;
+ const char * def;
+ const char * type;
+} lv_xml_param_t;
+
+typedef struct {
+ const char * name;
+ lv_grad_dsc_t grad_dsc;
+} lv_xml_grad_t;
+
/**********************
* GLOBAL PROTOTYPES
**********************/
diff --git a/src/others/xml/lv_xml_parser.h b/src/others/xml/lv_xml_parser.h
index cf95363a4..e040ed23c 100644
--- a/src/others/xml/lv_xml_parser.h
+++ b/src/others/xml/lv_xml_parser.h
@@ -49,22 +49,6 @@ struct _lv_xml_parser_state_t {
lv_xml_parser_section_t section;
};
-typedef struct {
- const char * name;
- const char * value;
-} lv_xml_const_t;
-
-typedef struct {
- const char * name;
- const char * def;
- const char * type;
-} lv_xml_param_t;
-
-typedef struct {
- const char * name;
- lv_grad_dsc_t grad_dsc;
-} lv_xml_grad_t;
-
/**********************
* GLOBAL PROTOTYPES
**********************/
diff --git a/src/others/xml/lv_xml_private.h b/src/others/xml/lv_xml_private.h
index ad67f9bf2..6c6a26b88 100644
--- a/src/others/xml/lv_xml_private.h
+++ b/src/others/xml/lv_xml_private.h
@@ -40,6 +40,11 @@ typedef struct {
const void * src;
} lv_xml_image_t;
+typedef struct {
+ const char * name;
+ lv_event_cb_t cb;
+} lv_xml_event_cb_t;
+
/**********************
* GLOBAL PROTOTYPES
diff --git a/src/others/xml/parsers/lv_xml_event_parser.c b/src/others/xml/parsers/lv_xml_event_parser.c
new file mode 100644
index 000000000..5aef5e33d
--- /dev/null
+++ b/src/others/xml/parsers/lv_xml_event_parser.c
@@ -0,0 +1,167 @@
+/**
+ * @file lv_xml_event_parser.c
+ *
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_xml_event_parser.h"
+#if LV_USE_XML
+
+#include "../../../lvgl.h"
+#include "../../../lvgl_private.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+static lv_event_code_t trigger_text_to_enum_value(const char * txt);
+static void free_user_data_event_cb(lv_event_t * e);
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+void * lv_xml_event_call_function_create(lv_xml_parser_state_t * state, const char ** attrs)
+{
+ LV_UNUSED(attrs);
+
+ const char * cb_txt = lv_xml_get_value_of(attrs, "callback");
+ if(cb_txt == NULL) {
+ LV_LOG_WARN("callback is mandatory for event-call_function");
+ return NULL;
+ }
+
+ lv_event_cb_t cb = lv_xml_get_event_cb(cb_txt);
+ if(cb == NULL) {
+ LV_LOG_WARN("Couldn't add call function event because \"%s\" callback is not found.", cb_txt);
+ return NULL;
+ }
+
+ const char * trigger = lv_xml_get_value_of(attrs, "trigger");
+ lv_event_code_t code = LV_EVENT_CLICKED;
+ if(trigger) code = trigger_text_to_enum_value(trigger);
+ if(code == LV_EVENT_LAST) {
+ LV_LOG_WARN("Couldn't add call function event because \"%s\" trigger is invalid.", trigger);
+ return NULL;
+ }
+
+ const char * user_data_xml = lv_xml_get_value_of(attrs, "user_data");
+ char * user_data = NULL;
+ if(user_data_xml) user_data = lv_strdup(user_data_xml);
+
+ lv_obj_t * obj = lv_xml_state_get_parent(state);
+ lv_obj_add_event_cb(obj, cb, code, user_data);
+ if(user_data) lv_obj_add_event_cb(obj, free_user_data_event_cb, LV_EVENT_DELETE, user_data);
+
+ return obj;
+}
+
+void lv_xml_event_call_function_apply(lv_xml_parser_state_t * state, const char ** attrs)
+{
+ LV_UNUSED(state);
+ LV_UNUSED(attrs);
+ /*Nothing to apply*/
+}
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
+
+static void free_user_data_event_cb(lv_event_t * e)
+{
+ char * user_data = lv_event_get_user_data(e);
+ lv_free(user_data);
+}
+
+static lv_event_code_t trigger_text_to_enum_value(const char * txt)
+{
+
+ if(lv_streq("all", txt)) return LV_EVENT_ALL;
+ if(lv_streq("pressed", txt)) return LV_EVENT_PRESSED;
+ if(lv_streq("pressing", txt)) return LV_EVENT_PRESSING;
+ if(lv_streq("press_lost", txt)) return LV_EVENT_PRESS_LOST;
+ if(lv_streq("short_clicked", txt)) return LV_EVENT_SHORT_CLICKED;
+ if(lv_streq("single_clicked", txt)) return LV_EVENT_SINGLE_CLICKED;
+ if(lv_streq("double_clicked", txt)) return LV_EVENT_DOUBLE_CLICKED;
+ if(lv_streq("triple_clicked", txt)) return LV_EVENT_TRIPLE_CLICKED;
+ if(lv_streq("long_pressed", txt)) return LV_EVENT_LONG_PRESSED;
+ if(lv_streq("long_pressed_repeat", txt)) return LV_EVENT_LONG_PRESSED_REPEAT;
+ if(lv_streq("clicked", txt)) return LV_EVENT_CLICKED;
+ if(lv_streq("released", txt)) return LV_EVENT_RELEASED;
+ if(lv_streq("scroll_begin", txt)) return LV_EVENT_SCROLL_BEGIN;
+ if(lv_streq("scroll_throw_begin", txt)) return LV_EVENT_SCROLL_THROW_BEGIN;
+ if(lv_streq("scroll_end", txt)) return LV_EVENT_SCROLL_END;
+ if(lv_streq("scroll", txt)) return LV_EVENT_SCROLL;
+ if(lv_streq("gesture", txt)) return LV_EVENT_GESTURE;
+ if(lv_streq("key", txt)) return LV_EVENT_KEY;
+ if(lv_streq("rotary", txt)) return LV_EVENT_ROTARY;
+ if(lv_streq("focused", txt)) return LV_EVENT_FOCUSED;
+ if(lv_streq("defocused", txt)) return LV_EVENT_DEFOCUSED;
+ if(lv_streq("leave", txt)) return LV_EVENT_LEAVE;
+ if(lv_streq("hit_test", txt)) return LV_EVENT_HIT_TEST;
+ if(lv_streq("indev_reset", txt)) return LV_EVENT_INDEV_RESET;
+ if(lv_streq("hover_over", txt)) return LV_EVENT_HOVER_OVER;
+ if(lv_streq("hover_leave", txt)) return LV_EVENT_HOVER_LEAVE;
+ if(lv_streq("cover_check", txt)) return LV_EVENT_COVER_CHECK;
+ if(lv_streq("refr_ext_draw_size", txt)) return LV_EVENT_REFR_EXT_DRAW_SIZE;
+ if(lv_streq("draw_main_begin", txt)) return LV_EVENT_DRAW_MAIN_BEGIN;
+ if(lv_streq("draw_main", txt)) return LV_EVENT_DRAW_MAIN;
+ if(lv_streq("draw_main_end", txt)) return LV_EVENT_DRAW_MAIN_END;
+ if(lv_streq("draw_post_begin", txt)) return LV_EVENT_DRAW_POST_BEGIN;
+ if(lv_streq("draw_post", txt)) return LV_EVENT_DRAW_POST;
+ if(lv_streq("draw_post_end", txt)) return LV_EVENT_DRAW_POST_END;
+ if(lv_streq("draw_task_added", txt)) return LV_EVENT_DRAW_TASK_ADDED;
+ if(lv_streq("value_changed", txt)) return LV_EVENT_VALUE_CHANGED;
+ if(lv_streq("insert", txt)) return LV_EVENT_INSERT;
+ if(lv_streq("refresh", txt)) return LV_EVENT_REFRESH;
+ if(lv_streq("ready", txt)) return LV_EVENT_READY;
+ if(lv_streq("cancel", txt)) return LV_EVENT_CANCEL;
+ if(lv_streq("create", txt)) return LV_EVENT_CREATE;
+ if(lv_streq("delete", txt)) return LV_EVENT_DELETE;
+ if(lv_streq("child_changed", txt)) return LV_EVENT_CHILD_CHANGED;
+ if(lv_streq("child_created", txt)) return LV_EVENT_CHILD_CREATED;
+ if(lv_streq("child_deleted", txt)) return LV_EVENT_CHILD_DELETED;
+ if(lv_streq("screen_unload_start", txt)) return LV_EVENT_SCREEN_UNLOAD_START;
+ if(lv_streq("screen_load_start", txt)) return LV_EVENT_SCREEN_LOAD_START;
+ if(lv_streq("screen_loaded", txt)) return LV_EVENT_SCREEN_LOADED;
+ if(lv_streq("screen_unloaded", txt)) return LV_EVENT_SCREEN_UNLOADED;
+ if(lv_streq("size_changed", txt)) return LV_EVENT_SIZE_CHANGED;
+ if(lv_streq("style_changed", txt)) return LV_EVENT_STYLE_CHANGED;
+ if(lv_streq("layout_changed", txt)) return LV_EVENT_LAYOUT_CHANGED;
+ if(lv_streq("get_self_size", txt)) return LV_EVENT_GET_SELF_SIZE;
+ if(lv_streq("invalidate_area", txt)) return LV_EVENT_INVALIDATE_AREA;
+ if(lv_streq("resolution_changed", txt)) return LV_EVENT_RESOLUTION_CHANGED;
+ if(lv_streq("color_format_changed", txt)) return LV_EVENT_COLOR_FORMAT_CHANGED;
+ if(lv_streq("refr_request", txt)) return LV_EVENT_REFR_REQUEST;
+ if(lv_streq("refr_start", txt)) return LV_EVENT_REFR_START;
+ if(lv_streq("refr_ready", txt)) return LV_EVENT_REFR_READY;
+ if(lv_streq("render_start", txt)) return LV_EVENT_RENDER_START;
+ if(lv_streq("render_ready", txt)) return LV_EVENT_RENDER_READY;
+ if(lv_streq("flush_start", txt)) return LV_EVENT_FLUSH_START;
+ if(lv_streq("flush_finish", txt)) return LV_EVENT_FLUSH_FINISH;
+ if(lv_streq("flush_wait_start", txt)) return LV_EVENT_FLUSH_WAIT_START;
+ if(lv_streq("flush_wait_finish", txt)) return LV_EVENT_FLUSH_WAIT_FINISH;
+ if(lv_streq("vsync", txt)) return LV_EVENT_VSYNC;
+
+ LV_LOG_WARN("%s is an unknown value for event's trigger", txt);
+ return LV_EVENT_LAST; /*Indicate error*/
+}
+
+#endif /* LV_USE_XML */
diff --git a/src/others/xml/parsers/lv_xml_event_parser.h b/src/others/xml/parsers/lv_xml_event_parser.h
new file mode 100644
index 000000000..28498fba9
--- /dev/null
+++ b/src/others/xml/parsers/lv_xml_event_parser.h
@@ -0,0 +1,40 @@
+/**
+ * @file lv_xml_event_parser.h
+ *
+ */
+
+#ifndef LV_EVENT_XML_PARSER_H
+#define LV_EVENT_XML_PARSER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "../lv_xml.h"
+#if LV_USE_XML
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+void * lv_xml_event_call_function_create(lv_xml_parser_state_t * state, const char ** attrs);
+
+void lv_xml_event_call_function_apply(lv_xml_parser_state_t * state, const char ** attrs);
+
+/**********************
+ * MACROS
+ **********************/
+
+#endif /* LV_USE_XML */
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*LV_EVENT_XML_PARSE_H*/
diff --git a/tests/src/test_cases/xml/test_xml_event.c b/tests/src/test_cases/xml/test_xml_event.c
new file mode 100644
index 000000000..cb90ce34a
--- /dev/null
+++ b/tests/src/test_cases/xml/test_xml_event.c
@@ -0,0 +1,98 @@
+#if LV_BUILD_TEST
+#include "../lvgl.h"
+
+#include "unity/unity.h"
+#include "lv_test_indev.h"
+#include
+
+void setUp(void)
+{
+ /* Function run before every test */
+}
+
+void tearDown(void)
+{
+ /* Function run after every test */
+ lv_obj_clean(lv_screen_active());
+}
+
+static int32_t cnt;
+static void count_event_cb(lv_event_t * e)
+{
+ const char * user_data = lv_event_get_user_data(e);
+ int inc = atoi(user_data);
+
+ cnt += inc;
+}
+
+void test_xml_event_call_function_attr(void)
+{
+
+ lv_xml_register_event_cb("count_cb", count_event_cb);
+
+ lv_obj_t * scr = lv_screen_active();
+
+ const char * button_attrs[] = {
+ "width", "300",
+ "x", "10",
+ "y", "10",
+ NULL, NULL,
+ };
+
+ lv_obj_t * button = lv_xml_create(scr, "lv_button", button_attrs);
+
+ const char * event_attrs[] = {
+ "callback", "count_cb",
+ "user_data", "3",
+ "trigger", "clicked",
+ NULL, NULL,
+ };
+
+ lv_xml_create(button, "lv_event-call_function", event_attrs);
+
+
+ const char * label_attrs[] = {
+ "text", "Click me!",
+ "align", "center",
+ NULL, NULL,
+ };
+
+ lv_xml_create(button, "lv_label", label_attrs);
+
+ lv_refr_now(NULL); /*Make sure that the coordinates are calculated*/
+
+ cnt = 0;
+ lv_test_mouse_click_at(30, 20);
+ TEST_ASSERT_EQUAL(3, cnt);
+
+ lv_test_indev_wait(100);
+ lv_test_mouse_click_at(30, 20);
+ TEST_ASSERT_EQUAL(6, cnt);
+}
+
+void test_xml_event_call_function_component(void)
+{
+ const char * xml = {
+ ""
+ " "
+ " "
+ " "
+ " "
+ ""
+ };
+
+ lv_xml_register_event_cb("count_cb", count_event_cb);
+ lv_xml_component_register_from_data("my_button", xml);
+ lv_xml_create(lv_screen_active(), "my_button", NULL);
+
+ lv_refr_now(NULL); /*Make sure that the coordinates are calculated*/
+
+ cnt = 0;
+ lv_test_mouse_click_at(30, 10);
+ TEST_ASSERT_EQUAL(3, cnt);
+
+ lv_test_indev_wait(100);
+ lv_test_mouse_click_at(30, 10);
+ TEST_ASSERT_EQUAL(6, cnt);
+}
+#endif
diff --git a/tests/src/test_cases/xml/test_xml_image.c b/tests/src/test_cases/xml/test_xml_image.c
index f7aa06b7d..4ef965727 100644
--- a/tests/src/test_cases/xml/test_xml_image.c
+++ b/tests/src/test_cases/xml/test_xml_image.c
@@ -14,7 +14,7 @@ void tearDown(void)
lv_obj_clean(lv_screen_active());
}
-void test_xml_tabview_with_attrs(void)
+void test_xml_image_with_attrs(void)
{
LV_IMAGE_DECLARE(test_img_lvgl_logo_png);
lv_xml_register_image("logo", &test_img_lvgl_logo_png);