diff --git a/lvgl.h b/lvgl.h index 842fd7727..b6e29b61b 100644 --- a/lvgl.h +++ b/lvgl.h @@ -19,6 +19,7 @@ extern "C" { #include "src/lv_misc/lv_log.h" #include "src/lv_misc/lv_task.h" #include "src/lv_misc/lv_math.h" +#include "src/lv_misc/lv_async.h" #include "src/lv_hal/lv_hal.h" diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index b11bbc8d1..f45218d57 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -15,6 +15,7 @@ #include "../lv_draw/lv_draw.h" #include "../lv_misc/lv_anim.h" #include "../lv_misc/lv_task.h" +#include "../lv_misc/lv_async.h" #include "../lv_misc/lv_fs.h" #include "../lv_hal/lv_hal.h" #include @@ -49,6 +50,7 @@ static void report_style_mod_core(void * style_p, lv_obj_t * obj); static void refresh_children_style(lv_obj_t * obj); static void delete_children(lv_obj_t * obj); static void lv_event_mark_deleted(lv_obj_t * obj); +static void lv_obj_del_async_cb(void * obj); static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param); @@ -448,6 +450,12 @@ lv_res_t lv_obj_del(lv_obj_t * obj) return LV_RES_INV; } + +void lv_obj_del_async(lv_obj_t * obj) +{ + lv_async_call(lv_obj_del_async_cb, obj); +} + /** * Delete all children of an object * @param obj pointer to an object @@ -2101,6 +2109,11 @@ bool lv_obj_is_focused(const lv_obj_t * obj) * STATIC FUNCTIONS **********************/ +static void lv_obj_del_async_cb(void * obj) +{ + lv_obj_del(obj); +} + /** * Handle the drawing related tasks of the base objects. * @param obj pointer to an object diff --git a/src/lv_misc/lv_async.c b/src/lv_misc/lv_async.c new file mode 100644 index 000000000..64d7e693b --- /dev/null +++ b/src/lv_misc/lv_async.c @@ -0,0 +1,75 @@ +/** + * @file lv_templ.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_async.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void lv_async_task_cb(lv_task_t *task); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data) +{ + /*Allocate an info structure */ + lv_async_info_t *info = lv_mem_alloc(sizeof(lv_async_info_t)); + + if(info == NULL) + return LV_RES_INV; + + /* Create a new task */ + /* Use highest priority so that it will run before a refresh */ + lv_task_t *task = lv_task_create(lv_async_task_cb, 0, LV_TASK_PRIO_HIGHEST, info); + + if(task == NULL) { + lv_mem_free(info); + return LV_RES_INV; + } + + info->cb = async_xcb; + info->user_data = user_data; + + /* Set the task's user data */ + task->user_data = info; + lv_task_once(task); + return LV_RES_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void lv_async_task_cb(lv_task_t *task) +{ + lv_async_info_t *info = (lv_async_info_t *)task->user_data; + + info->cb(info->user_data); + + lv_mem_free(info); +} diff --git a/src/lv_misc/lv_async.h b/src/lv_misc/lv_async.h new file mode 100644 index 000000000..81fbe91f9 --- /dev/null +++ b/src/lv_misc/lv_async.h @@ -0,0 +1,73 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_task.h" +#include "lv_types.h" + +/********************* + * DEFINES + *********************/ + + + +/********************** + * TYPEDEFS + **********************/ + +/** + * Type for async callback. + */ +typedef void (*lv_async_cb_t)(void *); + +typedef struct _lv_async_info_t { + lv_async_cb_t cb; + void *user_data; +} lv_async_info_t; + +struct _lv_obj_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Call an asynchronous function the next time lv_task_handler() is run. This function is likely to return + * **before** the call actually happens! + * @param task_xcb a callback which is the task itself. + * (the 'x' in the argument name indicates that its not a fully generic function because it not follows + * the `func_name(object, callback, ...)` convention) + * @param user_data custom parameter + */ +lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data); + +/** + * Helper function for asynchronously deleting objects. + * + * Useful for cases where you can't delete an object directly in an `LV_EVENT_DELETE` handler (i.e. parent). + * @param obj object to delete + * @see lv_async_call + */ +void lv_obj_del_async(struct _lv_obj_t *obj); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/src/lv_objx/lv_mbox.c b/src/lv_objx/lv_mbox.c index 6101c4aaa..9a5fa1dd7 100644 --- a/src/lv_objx/lv_mbox.c +++ b/src/lv_objx/lv_mbox.c @@ -40,6 +40,7 @@ static void mbox_realign(lv_obj_t * mbox); static void lv_mbox_close_ready_cb(lv_anim_t * a); #endif static void lv_mbox_default_event_cb(lv_obj_t * mbox, lv_event_t event); +static void lv_mbox_btnm_event_cb(lv_obj_t * btnm, lv_event_t event); /********************** * STATIC VARIABLES @@ -157,7 +158,7 @@ void lv_mbox_add_btns(lv_obj_t * mbox, const char ** btn_map) lv_btnm_set_map(ext->btnm, btn_map); lv_btnm_set_btn_ctrl_all(ext->btnm, LV_BTNM_CTRL_CLICK_TRIG | LV_BTNM_CTRL_NO_REPEAT); - lv_obj_set_parent_event(ext->btnm, true); + lv_obj_set_event_cb(ext->btnm, lv_mbox_btnm_event_cb); mbox_realign(mbox); } @@ -529,4 +530,18 @@ static void lv_mbox_default_event_cb(lv_obj_t * mbox, lv_event_t event) lv_mbox_start_auto_close(mbox, 0); } +static void lv_mbox_btnm_event_cb(lv_obj_t * btnm, lv_event_t event) +{ + lv_obj_t * mbox = lv_obj_get_parent(btnm); + + /*clang-format off*/ + if(event == LV_EVENT_PRESSED || event == LV_EVENT_PRESSING || event == LV_EVENT_PRESS_LOST || + event == LV_EVENT_RELEASED || event == LV_EVENT_SHORT_CLICKED || event == LV_EVENT_CLICKED || + event == LV_EVENT_LONG_PRESSED || event == LV_EVENT_LONG_PRESSED_REPEAT || + event == LV_EVENT_VALUE_CHANGED) { + lv_event_send(mbox, event, lv_event_get_data()); + } + /*clang-format on*/ +} + #endif