diff --git a/lv_conf_template.h b/lv_conf_template.h index 908e18ce6..c9a8a62d0 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -145,11 +145,11 @@ typedef void * lv_group_user_data_t; /* 1: Enable alpha indexed images */ #define LV_IMG_CF_ALPHA 1 -/*1: Add a `user_data` to drivers and objects*/ -#define LV_USE_USER_DATA_SINGLE 1 +/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_img_decoder_user_data_t; -/*1: Add separate `user_data` for every callback*/ -#define LV_USE_USER_DATA_MULTI 0 +/*1: Add a `user_data` to drivers and objects*/ +#define LV_USE_USER_DATA 1 /*===================== * Compiler settings @@ -165,7 +165,6 @@ typedef void * lv_group_user_data_t; * E.g. __attribute__((aligned(4))) */ #define LV_ATTRIBUTE_MEM_ALIGN - /* 1: Variable length array is supported*/ #define LV_COMPILER_VLA_SUPPORTED 1 diff --git a/src/lv_conf_checker.h b/src/lv_conf_checker.h index 770a84ae5..8be7b83d9 100644 --- a/src/lv_conf_checker.h +++ b/src/lv_conf_checker.h @@ -205,13 +205,8 @@ #endif /*1: Add a `user_data` to drivers and objects*/ -#ifndef LV_USE_USER_DATA_SINGLE -#define LV_USE_USER_DATA_SINGLE 1 -#endif - -/*1: Add separate `user_data` for every callback*/ -#ifndef LV_USE_USER_DATA_MULTI -#define LV_USE_USER_DATA_MULTI 0 +#ifndef LV_USE_USER_DATA +#define LV_USE_USER_DATA 1 #endif /*===================== diff --git a/src/lv_core/lv_group.c b/src/lv_core/lv_group.c index 7d6cfa1fd..fd5f25753 100644 --- a/src/lv_core/lv_group.c +++ b/src/lv_core/lv_group.c @@ -74,16 +74,10 @@ lv_group_t * lv_group_create(void) group->refocus_policy = LV_GROUP_REFOCUS_POLICY_PREV; group->wrap = 1; -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA memset(&group->user_data, 0, sizeof(lv_group_user_data_t)); #endif -#if LV_USE_USER_DATA_MULTI - memset(&group->focus_user_data, 0, sizeof(lv_group_user_data_t)); - memset(&group->style_mod_user_data, 0, sizeof(lv_group_user_data_t)); - memset(&group->style_mod_edit_user_data, 0, sizeof(lv_group_user_data_t)); -#endif - /*Initialize style modification callbacks from current theme*/ refresh_theme(group, lv_theme_get_current()); @@ -285,7 +279,15 @@ lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c) lv_obj_t * act = lv_group_get_focused(group); if(act == NULL) return LV_RES_OK; - return act->signal_cb(act, LV_SIGNAL_CONTROL, &c); + lv_res_t res; + + res = act->signal_cb(act, LV_SIGNAL_CONTROL, &c); + if(res != LV_RES_OK) return res; + + res = lv_event_send(act, LV_EVENT_KEY, &c); + if(res != LV_RES_OK) return res; + + return res; } /** @@ -401,7 +403,7 @@ lv_obj_t * lv_group_get_focused(const lv_group_t * group) return *group->obj_focus; } -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA /** * Get a pointer to the group's user data * @param group pointer to an group diff --git a/src/lv_core/lv_group.h b/src/lv_core/lv_group.h index 02edca0d2..89d71ee8b 100644 --- a/src/lv_core/lv_group.h +++ b/src/lv_core/lv_group.h @@ -25,19 +25,23 @@ extern "C" { * DEFINES *********************/ /*Predefined keys to control the focused object via lv_group_send(group, c)*/ -/*For compatibility in signal function define the keys regardless to LV_GROUP*/ -#define LV_KEY_UP 17 /*0x11*/ -#define LV_KEY_DOWN 18 /*0x12*/ -#define LV_KEY_RIGHT 19 /*0x13*/ -#define LV_KEY_LEFT 20 /*0x14*/ -#define LV_KEY_ESC 27 /*0x1B*/ -#define LV_KEY_DEL 127 /*0x7F*/ -#define LV_KEY_BACKSPACE 8 /*0x08*/ -#define LV_KEY_ENTER 10 /*0x0A, '\n'*/ -#define LV_KEY_NEXT 9 /*0x09, '\t'*/ -#define LV_KEY_PREV 11 /*0x0B, '*/ -#define LV_KEY_HOME 2 /*0x02, STX*/ -#define LV_KEY_END 3 /*0x03, ETX*/ +/*For compatibility in signal function define the keys regardless to `LV_USE_GROUP`*/ + +enum { + LV_KEY_UP = 17, /*0x11*/ + LV_KEY_DOWN = 18, /*0x12*/ + LV_KEY_RIGHT = 19, /*0x13*/ + LV_KEY_LEFT = 20, /*0x14*/ + LV_KEY_ESC = 27, /*0x1B*/ + LV_KEY_DEL = 127, /*0x7F*/ + LV_KEY_BACKSPACE = 8, /*0x08*/ + LV_KEY_ENTER = 10, /*0x0A, '\n'*/ + LV_KEY_NEXT = 9, /*0x09, '\t'*/ + LV_KEY_PREV=11, /*0x0B, '*/ + LV_KEY_HOME = 2, /*0x02, STX*/ + LV_KEY_END = 3, /*0x03, ETX*/ +}; +typedef uint8_t lv_key_t; #if LV_USE_GROUP != 0 /********************** @@ -57,16 +61,10 @@ typedef struct _lv_group_t lv_group_style_mod_cb_t style_mod_edit_cb; /*A function which modifies the style of the edited object*/ lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/ lv_style_t style_tmp; /*Stores the modified style of the focused object */ -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA lv_group_user_data_t user_data; #endif -#if LV_USE_USER_DATA_MULTI - lv_group_user_data_t focus_user_data; - lv_group_user_data_t style_mod_user_data; - lv_group_user_data_t style_mod_edit_user_data; -#endif - uint8_t frozen : 1; /*1: can't focus to new object*/ uint8_t editing : 1; /*1: Edit mode, 0: Navigate mode*/ uint8_t click_focus : 1; /*1: If an object in a group is clicked by an indev then it will be @@ -213,7 +211,7 @@ lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style); */ lv_obj_t * lv_group_get_focused(const lv_group_t * group); -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA /** * Get a pointer to the group's user data * @param group pointer to an group diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 416937af8..f2ab53c3c 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -876,15 +876,13 @@ static void indev_proc_release(lv_indev_proc_t * proc) if(proc->reset_query != 0) return; - /*Handle click focus*/ + /*Handle click focus*/ #if LV_USE_GROUP - /*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/ lv_group_t * g = lv_obj_get_group(proc->types.pointer.act_obj); - if(lv_group_get_editing(g)) lv_group_set_editing(g, false); /*Check, if the parent is in a group focus on it.*/ - if(lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_CLICK_FOCUS) == - false) { /*Respect the click focus protection*/ + /*Respect the click focus protection*/ + if(lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_CLICK_FOCUS) == false) { lv_obj_t * parent = proc->types.pointer.act_obj; while(g == NULL) { diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 499322f23..1ca30a706 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -82,7 +82,7 @@ void lv_init(void) /*Initialize the lv_misc modules*/ lv_mem_init(); - lv_task_init(); + lv_task_core_init(); #if LV_USE_FILESYSTEM lv_fs_init(); @@ -90,7 +90,7 @@ void lv_init(void) lv_font_init(); #if LV_USE_ANIMATION - lv_anim_init(); + lv_anim_core_init(); #endif #if LV_USE_GROUP @@ -109,6 +109,8 @@ void lv_init(void) /*Init the input device handling*/ lv_indev_init(); + lv_img_decoder_init(); + lv_initialized = true; LV_LOG_INFO("lv_init ready"); } @@ -183,14 +185,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->event_cb = NULL; /*Init. user date*/ -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA memset(&new_obj->user_data, 0, sizeof(lv_obj_user_data_t)); #endif -#if LV_USE_USER_DATA_MULTI - memset(&new_obj->event_user_data, 0, sizeof(lv_obj_user_data_t)); - memset(&new_obj->signal_user_data, 0, sizeof(lv_obj_user_data_t)); - memset(&new_obj->design_user_data, 0, sizeof(lv_obj_user_data_t)); -#endif #if LV_USE_GROUP new_obj->group_p = NULL; @@ -271,14 +268,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) #endif /*Init. user date*/ -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA memset(&new_obj->user_data, 0, sizeof(lv_obj_user_data_t)); #endif -#if LV_USE_USER_DATA_MULTI - memset(&new_obj->event_user_data, 0, sizeof(lv_obj_user_data_t)); - memset(&new_obj->signal_user_data, 0, sizeof(lv_obj_user_data_t)); - memset(&new_obj->design_user_data, 0, sizeof(lv_obj_user_data_t)); -#endif #if LV_USE_GROUP new_obj->group_p = NULL; @@ -315,15 +307,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) #endif /*Set free data*/ -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA memcpy(&new_obj->user_data, ©->user_data, sizeof(lv_obj_user_data_t)); #endif -#if LV_USE_USER_DATA_MULTI - memcpy(&new_obj->event_user_data, ©->event_user_data, sizeof(lv_obj_user_data_t)); - memcpy(&new_obj->signal_user_data, ©->signal_user_data, sizeof(lv_obj_user_data_t)); - memcpy(&new_obj->design_user_data, ©->design_user_data, sizeof(lv_obj_user_data_t)); -#endif - /*Copy realign*/ #if LV_USE_OBJ_REALIGN new_obj->realign.align = copy->realign.align; @@ -360,7 +346,12 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) } #endif - lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy)); + /*Set the same coordinates for non screen objects*/ + if(lv_obj_get_parent(copy) != NULL && parent != NULL) { + lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy)); + } else { + lv_obj_set_pos(new_obj, 0, 0); + } LV_LOG_INFO("Object create ready"); } @@ -1984,7 +1975,7 @@ void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf) } } -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA /** * Get the object's user data diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 048e6353b..28b320809 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -22,6 +22,7 @@ extern "C" { #include #include #include "lv_style.h" +#include "../lv_misc/lv_types.h" #include "../lv_misc/lv_area.h" #include "../lv_misc/lv_mem.h" #include "../lv_misc/lv_ll.h" @@ -64,13 +65,6 @@ typedef uint8_t lv_design_mode_t; typedef bool (*lv_design_cb_t)(struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); -enum { - LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action - function or an operation was failed*/ - LV_RES_OK, /*The object is valid (no deleted) after the action*/ -}; -typedef uint8_t lv_res_t; - enum { LV_EVENT_PRESSED, /*The object has been pressed*/ LV_EVENT_PRESSING, /*The object is being pressed (called continuously while pressing)*/ @@ -84,6 +78,7 @@ enum { LV_EVENT_DRAG_BEGIN, LV_EVENT_DRAG_END, LV_EVENT_DRAG_THROW_BEGIN, + LV_EVENT_KEY, LV_EVENT_FOCUSED, LV_EVENT_DEFOCUSED, LV_EVENT_VALUE_CHANGED, @@ -224,16 +219,10 @@ typedef struct _lv_obj_t lv_reailgn_t realign; #endif -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA lv_obj_user_data_t user_data; #endif -#if LV_USE_USER_DATA_MULTI - lv_obj_user_data_t event_user_data; - lv_obj_user_data_t signal_user_data; - lv_obj_user_data_t design_user_data; -#endif - } lv_obj_t; /*Protect some attributes (max. 8 bit)*/ @@ -913,7 +902,7 @@ void * lv_obj_get_ext_attr(const lv_obj_t * obj); */ void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf); -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA /** * Get the object's user data * @param obj pointer to an object diff --git a/src/lv_core/lv_style.c b/src/lv_core/lv_style.c index ea6b3bb59..2d6b67fda 100644 --- a/src/lv_core/lv_style.c +++ b/src/lv_core/lv_style.c @@ -26,16 +26,6 @@ /********************** * TYPEDEFS **********************/ -#if LV_USE_ANIMATION -typedef struct -{ - lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it - will be modified too*/ - lv_style_t style_end; - lv_style_t * style_anim; - lv_anim_ready_cb_t ready_cb; -} lv_style_anim_dsc_t; -#endif /********************** * STATIC PROTOTYPES @@ -286,44 +276,38 @@ void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * #if LV_USE_ANIMATION -/** - * Create an animation from a pre-configured 'lv_style_anim_t' variable - * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) - * @return pointer to a descriptor. Really this variable will be animated. (Can be used in - * `lv_anim_del(dsc, NULL)`) - */ -void * lv_style_anim_create(lv_style_anim_t * anim) + +void lv_style_anim_init(lv_anim_t * a) { - lv_style_anim_dsc_t * dsc; - dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t)); - lv_mem_assert(dsc); - if(dsc == NULL) return NULL; + lv_anim_init(a); + a->start = 0; + a->end = STYLE_MIX_MAX; + a->exec_cb = (lv_anim_exec_cb_t)style_animator; + a->path_cb = lv_anim_path_linear; + a->ready_cb = style_animation_common_end_cb; - dsc->style_anim = anim->style_anim; - memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t)); - memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t)); - memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t)); - dsc->ready_cb = anim->ready_cb; + lv_style_anim_dsc_t * dsc; + dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t)); + lv_mem_assert(dsc); + if(dsc == NULL) return; + dsc->ready_cb = NULL; + dsc->style_anim = NULL; + lv_style_copy(&dsc->style_start, &lv_style_plain); + lv_style_copy(&dsc->style_end, &lv_style_plain); - lv_anim_t a; - a.var = (void *)dsc; - a.start = 0; - a.end = STYLE_MIX_MAX; - a.exec_cb = (lv_anim_exec_cb_t)style_animator; - a.path_cb = lv_anim_path_linear; - a.ready_cb = style_animation_common_end_cb; - a.act_time = anim->act_time; - a.time = anim->time; - a.playback = anim->playback; - a.playback_pause = anim->playback_pause; - a.repeat = anim->repeat; - a.repeat_pause = anim->repeat_pause; + a->var = (void *)dsc; - lv_anim_create(&a); - - return dsc; } +void lv_style_anim_set_styles(lv_anim_t * a, lv_style_t * to_anim, const lv_style_t * start, const lv_style_t * end) +{ + + lv_style_anim_dsc_t * dsc = a->var; + dsc->style_anim = to_anim; + memcpy(&dsc->style_start, start, sizeof(lv_style_t)); + memcpy(&dsc->style_end, end, sizeof(lv_style_t)); + memcpy(dsc->style_anim, start, sizeof(lv_style_t)); +} #endif /********************** * STATIC FUNCTIONS diff --git a/src/lv_core/lv_style.h b/src/lv_core/lv_style.h index 4f4ac19b4..a4d5b6f8e 100644 --- a/src/lv_core/lv_style.h +++ b/src/lv_core/lv_style.h @@ -112,41 +112,12 @@ typedef struct #if LV_USE_ANIMATION typedef struct { - const lv_style_t * style_start; /*Pointer to the starting style*/ - const lv_style_t * style_end; /*Pointer to the destination style*/ - lv_style_t * style_anim; /*Pointer to a style to animate*/ - lv_anim_ready_cb_t ready_cb; /*Call it when the animation is ready (NULL if unused)*/ - int16_t time; /*Animation time in ms*/ - int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ - uint16_t playback_pause; /*Wait before play back*/ - uint16_t repeat_pause; /*Wait before repeat*/ -#if LV_USE_USER_DATA_SINGLE - lv_anim_user_data_t user_data; /*Custom user data*/ -#endif - -#if LV_USE_USER_DATA_MULTI - lv_anim_user_data_t ready_user_data; -#endif - - uint8_t playback : 1; /*When the animation is ready play it back*/ - uint8_t repeat : 1; /*Repeat the animation infinitely*/ -} lv_style_anim_t; - -/* Example initialization -lv_style_anim_t a; -a.style_anim = &style_to_anim; -a.style_start = &style_1; -a.style_end = &style_2; -a.act_time = 0; -a.time = 1000; -a.playback = 0; -a.playback_pause = 0; -a.repeat = 0; -a.repeat_pause = 0; -a.ready_cb = NULL; -a.user_data = NULL; -lv_style_anim_create(&a); - */ + lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it + will be modified too*/ + lv_style_t style_end; + lv_style_t * style_anim; + lv_anim_ready_cb_t ready_cb; +} lv_style_anim_dsc_t; #endif /********************** @@ -178,12 +149,124 @@ void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * #if LV_USE_ANIMATION /** - * Create an animation from a pre-configured 'lv_style_anim_t' variable - * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) - * @return pointer to a descriptor. Really this variable will be animated. (Can be used in - * `lv_anim_del(dsc, NULL)`) + * Initialize an animation variable. + * E.g.: + * lv_anim_t a; + * lv_style_anim__init(&a); + * lv_style_anim_set_...(&a); + * lv_style_anim_create(&a); + * @param a pointer to an `lv_anim_t` variable to initialize */ -void * lv_style_anim_create(lv_style_anim_t * anim); +void lv_style_anim_init(lv_anim_t * a); + +/** + * + * @param a pointer to an initialized `lv_anim_t` variable + * @param to_anim pointer to the style to animate + * @param start pointer to a style to animate from (start value) + * @param end pointer to a style to animate to (end value) + */ +void lv_style_anim_set_styles(lv_anim_t * a, lv_style_t * to_anim, const lv_style_t * start, const lv_style_t * end); + +/** + * Set the duration and delay of an animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param duration duration of the animation in milliseconds + * @param delay delay before the animation in milliseconds + */ +static inline void lv_style_anim_set_time(lv_anim_t * a, uint16_t duration, uint16_t delay) +{ + lv_anim_set_time(a, duration, delay); +} + +/** + * Set a function call when the animation is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param ready_cb a function call when the animation is ready + */ +static inline void lv_style_anim_set_ready_cb(lv_anim_t * a, lv_anim_ready_cb_t ready_cb) +{ + lv_style_anim_dsc_t * dsc = a->var; + dsc->ready_cb = ready_cb; +} + +/** + * Make the animation to play back to when the forward direction is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param wait_time time in milliseconds to wait before starting the back direction + */ +static inline void lv_style_anim_set_playback(lv_anim_t * a, uint16_t wait_time) +{ + lv_anim_set_playback(a, wait_time); +} + +/** + * Disable playback. (Disabled after `lv_anim_init()`) + * @param a pointer to an initialized `lv_anim_t` variable + */ +static inline void lv_style_anim_clear_playback(lv_anim_t * a) +{ + lv_anim_clear_playback(a); +} + +/** + * Make the animation to start again when ready. + * @param a pointer to an initialized `lv_anim_t` variable + * @param wait_time time in milliseconds to wait before starting the animation again + */ +static inline void lv_style_anim_set_repeat(lv_anim_t * a, uint16_t wait_time) +{ + lv_anim_set_repeat(a, wait_time); +} + +/** + * Disable repeat. (Disabled after `lv_anim_init()`) + * @param a pointer to an initialized `lv_anim_t` variable + */ +static inline void lv_style_anim_clear_repeat(lv_anim_t * a) +{ + lv_anim_clear_repeat(a); +} + +/** + * Set a user specific data for the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param user_data the user data + */ +static inline void lv_style_anim_set_user_data(lv_anim_t * a, lv_anim_user_data_t user_data) +{ + lv_anim_set_user_data(a, user_data); +} + +/** + * Get the user data + * @param a pointer to an initialized `lv_anim_t` variable + * @return the user data + */ +static inline lv_anim_user_data_t lv_style_anim_get_user_data(lv_anim_t * a) +{ + return lv_anim_get_user_data(a); +} + +/** + * Get pointer to the user data + * @param a pointer to an initialized `lv_anim_t` variable + * @return pointer to the user data + */ +static inline lv_anim_user_data_t * lv_style_anim_get_user_data_ptr(lv_anim_t * a) +{ + return lv_style_anim_get_user_data_ptr(a); +} + +/** + * Create an animation + * @param a an initialized 'anim_t' variable. Not required after call. + */ +static inline void lv_style_anim_create(lv_anim_t * a) +{ + return lv_anim_create(a); +} + #endif /************************* diff --git a/src/lv_draw/lv_draw.h b/src/lv_draw/lv_draw.h index 0d346653a..8d3d281a7 100644 --- a/src/lv_draw/lv_draw.h +++ b/src/lv_draw/lv_draw.h @@ -21,30 +21,16 @@ extern "C" { #include "../lv_core/lv_style.h" #include "../lv_misc/lv_txt.h" +#include "lv_img_decoder.h" /********************* * DEFINES *********************/ -/*If image pixels contains alpha we need to know how much byte is a pixel*/ -#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 -#define LV_IMG_PX_SIZE_ALPHA_BYTE 2 -#elif LV_COLOR_DEPTH == 16 -#define LV_IMG_PX_SIZE_ALPHA_BYTE 3 -#elif LV_COLOR_DEPTH == 32 -#define LV_IMG_PX_SIZE_ALPHA_BYTE 4 -#endif /********************** * TYPEDEFS **********************/ -enum { - LV_IMG_SRC_VARIABLE, - LV_IMG_SRC_FILE, - LV_IMG_SRC_SYMBOL, - LV_IMG_SRC_UNKNOWN, -}; -typedef uint8_t lv_img_src_t; /********************** * GLOBAL PROTOTYPES diff --git a/src/lv_draw/lv_draw.mk b/src/lv_draw/lv_draw.mk index ac9e76041..43b5ee48a 100644 --- a/src/lv_draw/lv_draw.mk +++ b/src/lv_draw/lv_draw.mk @@ -6,6 +6,7 @@ CSRCS += lv_draw_line.c CSRCS += lv_draw_img.c CSRCS += lv_draw_arc.c CSRCS += lv_draw_triangle.c +CSRCS += lv_img_decoder.c DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_draw VPATH += :$(LVGL_DIR)/lvgl/src/lv_draw diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index c09bf3279..0986f1af4 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -7,7 +7,6 @@ * INCLUDES *********************/ #include "lv_draw_img.h" -#include "../lv_misc/lv_fs.h" /********************* * DEFINES @@ -23,33 +22,9 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, lv_opa_t opa_scale); -static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style); -static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); -static void lv_img_decoder_close(void); -static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf); -static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf); - /********************** * STATIC VARIABLES **********************/ -static bool decoder_custom; -static const void * decoder_src; -static lv_img_src_t decoder_src_type; -static lv_img_header_t decoder_header; -static const lv_style_t * decoder_style; -#if LV_USE_FILESYSTEM -static lv_fs_file_t decoder_file; -#endif -#if LV_IMG_CF_INDEXED -static lv_color_t decoder_index_map[256]; -#endif - -static lv_img_decoder_info_f_t lv_img_decoder_info_custom; -static lv_img_decoder_open_f_t lv_img_decoder_open_custom; -static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom; -static lv_img_decoder_close_f_t lv_img_decoder_close_custom; /********************** * MACROS @@ -90,63 +65,6 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * } } -/** - * Initialize and `lv_img_dsc_t` variable with the image's info - * @param src variable, filename or symbol - * @param header store the result here - * @return LV_RES_OK: succeeded; LV_RES_INV: failed - */ -lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header) -{ - header->always_zero = 0; - /*Try to get info with the custom functions first*/ - if(lv_img_decoder_info_custom) { - lv_res_t custom_res; - custom_res = lv_img_decoder_info_custom(src, header); - if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/ - } - - lv_img_src_t src_type = lv_img_src_get_type(src); - if(src_type == LV_IMG_SRC_VARIABLE) { - header->w = ((lv_img_dsc_t *)src)->header.w; - header->h = ((lv_img_dsc_t *)src)->header.h; - header->cf = ((lv_img_dsc_t *)src)->header.cf; - } -#if LV_USE_FILESYSTEM - else if(src_type == LV_IMG_SRC_FILE) { - lv_fs_file_t file; - lv_fs_res_t res; - uint32_t rn; - res = lv_fs_open(&file, src, LV_FS_MODE_RD); - if(res == LV_FS_RES_OK) { - res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn); - lv_fs_close(&file); - } - - /*Create a dummy header on fs error*/ - if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) { - header->w = LV_DPI; - header->h = LV_DPI; - header->cf = LV_IMG_CF_UNKNOWN; - return LV_RES_INV; - } - } -#endif - else if(src_type == LV_IMG_SRC_SYMBOL) { - /*The size depend on the font but it is unknown here. It should be handled outside of the - * function*/ - header->w = 1; - header->h = 1; - /* Symbols always have transparent parts. Important because of cover check in the design - * function. The actual value doesn't matter because lv_draw_label will draw it*/ - header->cf = LV_IMG_CF_ALPHA_1BIT; - } else { - LV_LOG_WARN("Image get info found unknown src type"); - return LV_RES_INV; - } - return LV_RES_OK; -} - /** * Get the color of an image's pixel * @param dsc an image descriptor @@ -512,24 +430,6 @@ lv_img_src_t lv_img_src_get_type(const void * src) return img_src_type; } -/** - * Set custom decoder functions. See the typdefs of the function typed above for more info about - * them - * @param info_fp info get function - * @param open_fp open function - * @param read_fp read line function - * @param close_fp clode function - */ -void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, - lv_img_decoder_read_line_f_t read_fp, - lv_img_decoder_close_f_t close_fp) -{ - lv_img_decoder_info_custom = info_fp; - lv_img_decoder_open_custom = open_fp; - lv_img_decoder_read_line_custom = read_fp; - lv_img_decoder_close_custom = close_fp; -} - /********************** * STATIC FUNCTIONS **********************/ @@ -552,20 +452,20 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas lv_img_header_t header; lv_res_t header_res; - header_res = lv_img_dsc_get_info(src, &header); + header_res = lv_img_decoder_get_info(src, &header); if(header_res != LV_RES_OK) { LV_LOG_WARN("Image draw can't get image info"); - lv_img_decoder_close(); return LV_RES_INV; } bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf); bool alpha_byte = lv_img_color_format_has_alpha(header.cf); - const uint8_t * img_data = lv_img_decoder_open(src, style); + lv_img_decoder_dsc_t dsc; + const uint8_t * img_data = lv_img_decoder_open(&dsc, src, style); if(img_data == LV_IMG_DECODER_OPEN_FAIL) { LV_LOG_WARN("Image draw cannot open the image resource"); - lv_img_decoder_close(); + lv_img_decoder_close(&dsc); return LV_RES_INV; } @@ -593,9 +493,9 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas lv_coord_t row; lv_res_t read_res; for(row = mask_com.y1; row <= mask_com.y2; row++) { - read_res = lv_img_decoder_read_line(x, y, width, buf); + read_res = lv_img_decoder_read_line(&dsc, x, y, width, buf); if(read_res != LV_RES_OK) { - lv_img_decoder_close(); + lv_img_decoder_close(&dsc); LV_LOG_WARN("Image draw can't read the line"); return LV_RES_INV; } @@ -607,412 +507,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas } } - lv_img_decoder_close(); + lv_img_decoder_close(&dsc); return LV_RES_OK; } - -static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style) -{ - decoder_custom = false; - - /*Try to open with the custom functions first*/ - if(lv_img_decoder_open_custom) { - const uint8_t * custom_res; - custom_res = lv_img_decoder_open_custom(src, style); - if(custom_res != LV_IMG_DECODER_OPEN_FAIL) { - decoder_custom = - true; /*Mark that custom decoder function should be used for this img source.*/ - return custom_res; /*Custom open supported this source*/ - } - } - - decoder_src = src; - decoder_style = style; - decoder_src_type = lv_img_src_get_type(src); - - lv_res_t header_res; - header_res = lv_img_dsc_get_info(src, &decoder_header); - if(header_res == LV_RES_INV) { - decoder_src = NULL; - decoder_src_type = LV_IMG_SRC_UNKNOWN; - LV_LOG_WARN("Built-in image decoder can't get the header info"); - return LV_IMG_DECODER_OPEN_FAIL; - } - - /*Open the file if it's a file*/ - if(decoder_src_type == LV_IMG_SRC_FILE) { -#if LV_USE_FILESYSTEM - lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD); - if(res != LV_FS_RES_OK) { - LV_LOG_WARN("Built-in image decoder can't open the file"); - return LV_IMG_DECODER_OPEN_FAIL; - } -#else - LV_LOG_WARN("Image built-in decoder can read file because LV_USE_FILESYSTEM = 0"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } - - /*Process the different color formats*/ - lv_img_cf_t cf = decoder_header.cf; - if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || - cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { - if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - /*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's - * pointer*/ - return ((lv_img_dsc_t *)decoder_src)->data; - } else { - /*If it's file it need to be read line by line later*/ - return NULL; - } - } else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || - cf == LV_IMG_CF_INDEXED_4BIT || cf == LV_IMG_CF_INDEXED_8BIT) { - -#if LV_IMG_CF_INDEXED -#if LV_USE_FILESYSTEM - lv_color32_t palette_file[256]; -#endif - - lv_color32_t * palette_p = NULL; - uint8_t px_size = lv_img_color_format_get_px_size(cf); - uint32_t palette_size = 1 << px_size; - - if(decoder_src_type == LV_IMG_SRC_FILE) { - /*Read the palette from file*/ -#if LV_USE_FILESYSTEM - lv_fs_seek(&decoder_file, 4); /*Skip the header*/ - lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL); - palette_p = palette_file; -#else - LV_LOG_WARN( - "Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } else { - /*The palette begins in the beginning of the image data. Just point to it.*/ - palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data; - } - - uint32_t i; - for(i = 0; i < palette_size; i++) { - decoder_index_map[i] = - lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue); - } - return NULL; -#else - LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || - cf == LV_IMG_CF_ALPHA_4BIT || cf == LV_IMG_CF_ALPHA_8BIT) { -#if LV_IMG_CF_ALPHA - return NULL; /*Nothing to process*/ -#else - LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA"); - return LV_IMG_DECODER_OPEN_FAIL; -#endif - } else { - LV_LOG_WARN("Image decoder open: unknown color format") - return LV_IMG_DECODER_OPEN_FAIL; - } -} - -static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) -{ - /*Try to read the line with the custom functions*/ - if(decoder_custom) { - if(lv_img_decoder_read_line_custom) { - lv_res_t custom_res; - custom_res = lv_img_decoder_read_line_custom(x, y, len, buf); - return custom_res; - } else { - LV_LOG_WARN("Image open with custom decoder but read not supported") - } - return LV_RES_INV; /*It"s an error if not returned earlier*/ - } - - if(decoder_src_type == LV_IMG_SRC_FILE) { -#if LV_USE_FILESYSTEM - uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); - - lv_fs_res_t res; - - if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR || - decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || - decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { - uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3; - pos += 4; /*Skip the header*/ - res = lv_fs_seek(&decoder_file, pos); - if(res != LV_FS_RES_OK) { - LV_LOG_WARN("Built-in image decoder seek failed"); - return false; - } - uint32_t btr = len * (px_size >> 3); - uint32_t br = 0; - lv_fs_read(&decoder_file, buf, btr, &br); - if(res != LV_FS_RES_OK || btr != br) { - LV_LOG_WARN("Built-in image decoder read failed"); - return false; - } - } else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT || - decoder_header.cf == LV_IMG_CF_ALPHA_2BIT || - decoder_header.cf == LV_IMG_CF_ALPHA_4BIT || - decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) { - - lv_img_built_in_decoder_line_alpha(x, y, len, buf); - } else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT || - decoder_header.cf == LV_IMG_CF_INDEXED_2BIT || - decoder_header.cf == LV_IMG_CF_INDEXED_4BIT || - decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) { - lv_img_built_in_decoder_line_indexed(x, y, len, buf); - } else { - LV_LOG_WARN("Built-in image decoder read not supports the color format"); - return false; - } -#else - LV_LOG_WARN("Image built-in decoder can't read file because LV_USE_FILESYSTEM = 0"); - return false; -#endif - } else if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - const lv_img_dsc_t * img_dsc = decoder_src; - - if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || - img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || - img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || - img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { - lv_img_built_in_decoder_line_alpha(x, y, len, buf); - } else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || - img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT || - img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || - img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { - lv_img_built_in_decoder_line_indexed(x, y, len, buf); - } else { - LV_LOG_WARN("Built-in image decoder not supports the color format"); - return false; - } - } - - return true; -} - -static void lv_img_decoder_close(void) -{ - /*Try to close with the custom functions*/ - if(decoder_custom) { - if(lv_img_decoder_close_custom) lv_img_decoder_close_custom(); - return; - } - - /*It was opened with built-in decoder*/ - if(decoder_src) { -#if LV_USE_FILESYSTEM - if(decoder_src_type == LV_IMG_SRC_FILE) { - lv_fs_close(&decoder_file); - } -#endif - decoder_src_type = LV_IMG_SRC_UNKNOWN; - decoder_src = NULL; - } -} - -static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf) -{ - -#if LV_IMG_CF_ALPHA - const lv_opa_t alpha1_opa_table[2] = { - 0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ - const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ - const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ - 68, 85, 102, 119, 136, 153, - 170, 187, 204, 221, 238, 255}; - - /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/ - lv_color_t bg_color = decoder_style->image.color; - lv_coord_t i; - for(i = 0; i < len; i++) { -#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full; -#elif LV_COLOR_DEPTH == 16 - /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF; - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF; -#elif LV_COLOR_DEPTH == 32 - *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full; -#else -#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" -#endif - } - - const lv_opa_t * opa_table = NULL; - uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); - uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ - - lv_coord_t w = 0; - uint32_t ofs = 0; - int8_t pos = 0; - switch(decoder_header.cf) { - case LV_IMG_CF_ALPHA_1BIT: - w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ - if(decoder_header.w & 0x7) w++; - ofs += w * y + (x >> 3); /*First pixel*/ - pos = 7 - (x & 0x7); - opa_table = alpha1_opa_table; - break; - case LV_IMG_CF_ALPHA_2BIT: - w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ - if(decoder_header.w & 0x3) w++; - ofs += w * y + (x >> 2); /*First pixel*/ - pos = 6 - ((x & 0x3) * 2); - opa_table = alpha2_opa_table; - break; - case LV_IMG_CF_ALPHA_4BIT: - w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ - if(decoder_header.w & 0x1) w++; - ofs += w * y + (x >> 1); /*First pixel*/ - pos = 4 - ((x & 0x1) * 4); - opa_table = alpha4_opa_table; - break; - case LV_IMG_CF_ALPHA_8BIT: - w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ - ofs += w * y + x; /*First pixel*/ - pos = 0; - break; - } - -#if LV_USE_FILESYSTEM -#if LV_COMPILER_VLA_SUPPORTED - uint8_t fs_buf[w]; -#else - uint8_t fs_buf[LV_HOR_RES_MAX]; -#endif -#endif - const uint8_t * data_tmp = NULL; - if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - const lv_img_dsc_t * img_dsc = decoder_src; - data_tmp = img_dsc->data + ofs; - } else { -#if LV_USE_FILESYSTEM - lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ - lv_fs_read(&decoder_file, fs_buf, w, NULL); - data_tmp = fs_buf; -#else - LV_LOG_WARN( - "Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0"); - data_tmp = NULL; /*To avoid warnings*/ - return LV_RES_INV; -#endif - } - - uint8_t byte_act = 0; - uint8_t val_act; - for(i = 0; i < len; i++) { - val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; - - buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = - decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act]; - - pos -= px_size; - if(pos < 0) { - pos = 8 - px_size; - data_tmp++; - } - } - - return LV_RES_OK; - -#else - LV_LOG_WARN( - "Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h"); - return LV_RES_INV; -#endif -} - -static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf) -{ - -#if LV_IMG_CF_INDEXED - uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf); - uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ - - lv_coord_t w = 0; - int8_t pos = 0; - uint32_t ofs = 0; - switch(decoder_header.cf) { - case LV_IMG_CF_INDEXED_1BIT: - w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ - if(decoder_header.w & 0x7) w++; - ofs += w * y + (x >> 3); /*First pixel*/ - ofs += 8; /*Skip the palette*/ - pos = 7 - (x & 0x7); - break; - case LV_IMG_CF_INDEXED_2BIT: - w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ - if(decoder_header.w & 0x3) w++; - ofs += w * y + (x >> 2); /*First pixel*/ - ofs += 16; /*Skip the palette*/ - pos = 6 - ((x & 0x3) * 2); - break; - case LV_IMG_CF_INDEXED_4BIT: - w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ - if(decoder_header.w & 0x1) w++; - ofs += w * y + (x >> 1); /*First pixel*/ - ofs += 64; /*Skip the palette*/ - pos = 4 - ((x & 0x1) * 4); - break; - case LV_IMG_CF_INDEXED_8BIT: - w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ - ofs += w * y + x; /*First pixel*/ - ofs += 1024; /*Skip the palette*/ - pos = 0; - break; - } - -#if LV_USE_FILESYSTEM -#if LV_COMPILER_VLA_SUPPORTED - uint8_t fs_buf[w]; -#else - uint8_t fs_buf[LV_HOR_RES_MAX]; -#endif -#endif - const uint8_t * data_tmp = NULL; - if(decoder_src_type == LV_IMG_SRC_VARIABLE) { - const lv_img_dsc_t * img_dsc = decoder_src; - data_tmp = img_dsc->data + ofs; - } else { -#if LV_USE_FILESYSTEM - lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/ - lv_fs_read(&decoder_file, fs_buf, w, NULL); - data_tmp = fs_buf; -#else - LV_LOG_WARN( - "Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0"); - data_tmp = NULL; /*To avoid warnings*/ - return LV_RES_INV; -#endif - } - - uint8_t byte_act = 0; - uint8_t val_act; - lv_coord_t i; - lv_color_t * cbuf = (lv_color_t *)buf; - for(i = 0; i < len; i++) { - val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; - cbuf[i] = decoder_index_map[val_act]; - - pos -= px_size; - if(pos < 0) { - pos = 8 - px_size; - data_tmp++; - } - } - - return LV_RES_OK; -#else - LV_LOG_WARN( - "Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h"); - return LV_RES_INV; -#endif -} diff --git a/src/lv_draw/lv_draw_img.h b/src/lv_draw/lv_draw_img.h index 33d332d23..5db721af7 100644 --- a/src/lv_draw/lv_draw_img.h +++ b/src/lv_draw/lv_draw_img.h @@ -14,109 +14,15 @@ extern "C" { * INCLUDES *********************/ #include "lv_draw.h" -#include "../lv_core/lv_obj.h" +#include "lv_img_decoder.h" /********************* * DEFINES *********************/ -#define LV_IMG_DECODER_OPEN_FAIL ((void *)(-1)) /********************** * TYPEDEFS **********************/ -struct _lv_img_t; - -typedef struct -{ - - /* The first 8 bit is very important to distinguish the different source types. - * For more info see `lv_img_get_src_type()` in lv_img.c */ - uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/ - uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a - non-printable character*/ - - uint32_t reserved : 2; /*Reserved to be used later*/ - - uint32_t w : 11; /*Width of the image map*/ - uint32_t h : 11; /*Height of the image map*/ -} lv_img_header_t; - -/*Image color format*/ -enum { - LV_IMG_CF_UNKNOWN = 0, - - LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ - LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder - function*/ - LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs - custom decoder function*/ - - LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ - LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ - LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels - will be transparent*/ - - LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ - LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ - - LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ - LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ - LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ - LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ -}; -typedef uint8_t lv_img_cf_t; - -/* Image header it is compatible with - * the result image converter utility*/ -typedef struct -{ - lv_img_header_t header; - uint32_t data_size; - const uint8_t * data; -} lv_img_dsc_t; - -/* Decoder function definitions */ - -/** - * Get info from an image and store in the `header` - * @param src the image source. Can be a pointer to a C array or a file name (Use - * `lv_img_src_get_type` to determine the type) - * @param header store the info here - * @return LV_RES_OK: info written correctly; LV_RES_INV: failed - */ -typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header); - -/** - * Open an image for decoding. Prepare it as it is required to read it later - * @param src the image source. Can be a pointer to a C array or a file name (Use - * `lv_img_src_get_type` to determine the type) - * @param style the style of image (maybe it will be required to determine a color or something) - * @return there are 3 possible return values: - * 1) buffer with the decoded image - * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image - * line-by-line 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an - * error occurred - */ -typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); - -/** - * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. - * Required only if the "open" function can't return with the whole decoded pixel array. - * @param x start x coordinate - * @param y startt y coordinate - * @param len number of pixels to decode - * @param buf a buffer to store the decoded pixels - * @return LV_RES_OK: ok; LV_RES_INV: failed - */ -typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, - uint8_t * buf); - -/** - * Close the pending decoding. Free resources etc. - */ -typedef void (*lv_img_decoder_close_f_t)(void); /********************** * GLOBAL PROTOTYPES @@ -133,14 +39,6 @@ typedef void (*lv_img_decoder_close_f_t)(void); void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style, lv_opa_t opa_scale); -/** - * Initialize and `lv_img_dsc_t` variable with the image's info - * @param src variable, filename or symbol - * @param header store the result here - * @return LV_RES_OK: succeeded; LV_RES_INV: failed - */ -lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); - /** * Get the type of an image source * @param src pointer to an image source: @@ -151,18 +49,6 @@ lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); */ lv_img_src_t lv_img_src_get_type(const void * src); -/** - * Set custom decoder functions. See the typdefs of the function typed above for more info about - * them - * @param info_fp info get function - * @param open_fp open function - * @param read_fp read line function - * @param close_fp clode function - */ -void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, - lv_img_decoder_read_line_f_t read_fp, - lv_img_decoder_close_f_t close_fp); - /** * Get the color of an image's pixel * @param dsc an image descriptor diff --git a/src/lv_draw/lv_img_decoder.c b/src/lv_draw/lv_img_decoder.c new file mode 100644 index 000000000..a66303cbf --- /dev/null +++ b/src/lv_draw/lv_img_decoder.c @@ -0,0 +1,694 @@ +/** + * @file lv_img_decoder.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_img_decoder.h" +#include "../lv_draw/lv_draw_img.h" +#include "../lv_misc/lv_ll.h" +#include "../lv_misc/lv_color.h" +#include "../lv_misc/lv_gc.h" + +#if defined(LV_GC_INCLUDE) +#include LV_GC_INCLUDE +#endif /* LV_ENABLE_GC */ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_fs_file_t * f; + lv_color_t * palette; +}lv_img_decoder_built_in_data_t; + + +/********************** + * STATIC PROTOTYPES + **********************/ + +static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header); +static const uint8_t * lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc); +static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); +static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc); +static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); +static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf); +static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf); + + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the image decoder module + * */ +void lv_img_decoder_init(void) +{ + lv_ll_init(&LV_GC_ROOT(_lv_img_defoder_ll), sizeof(lv_img_decoder_t)); + + lv_img_decoder_t * decoder; + + /*Create a decoder for the built in color format*/ + decoder = lv_img_decoder_create(); + if(decoder == NULL) { + LV_LOG_WARN("lv_img_decoder_init: out of memory"); + lv_mem_assert(decoder); + return; + } + + lv_img_decoder_set_info_cb(decoder, lv_img_decoder_built_in_info); + lv_img_decoder_set_open_cb(decoder, lv_img_decoder_built_in_open); + lv_img_decoder_set_read_line_cb(decoder, lv_img_decoder_built_in_read_line); + lv_img_decoder_set_close_cb(decoder, lv_img_decoder_built_in_close); +} + +/** + * Get information about an image. + * Try the created image decoder one by one. Once one is able to get info that info will be used. + * @param src the image source. E.g. file name or variable. + * @param header the image info will be stored here + * @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image + */ +lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header) +{ + header->always_zero = 0; + + lv_res_t res; + lv_img_decoder_t * d; + LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d) { + res = LV_RES_INV; + if(d->info_cb) { + res = d->info_cb(d, src, header); + if(res == LV_RES_OK) break; + } + } + + return res; +} + +/** + * Open an image. + * Try the created image decoder one by one. Once one is able to open the image that decoder is save in `dsc` + * @param dsc describe a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable. + * @param src the image source. Can be + * 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`) + * 2) Variable: Pointer to an `lv_img_dsc_t` variable + * 3) Symbol: E.g. `LV_SYMBOL_OK` + * @param style the style of the image + * @return LV_IMG_DECODER_OPEN_FAIL: can open the image + * NULL: the image is opened but `lv_img_decoder_read_line` needs to be used to get the info line by line + * Else: a pointer to a buffer which holds the uncompressed pixels of the image + */ +const uint8_t * lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style) +{ + dsc->style = style; + dsc->src = src; + dsc->src_type = lv_img_src_get_type(src); + dsc->user_data = NULL; + + lv_res_t header_res; + header_res = lv_img_decoder_get_info(src, &dsc->header); + if(header_res != LV_RES_OK) return LV_IMG_DECODER_OPEN_FAIL; + + const uint8_t * res = NULL; + lv_img_decoder_t * d; + LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d) { + res = NULL; + dsc->decoder = d; + if(d->open_cb) res = d->open_cb(d, dsc); + + if(res != LV_IMG_DECODER_OPEN_FAIL) break; + } + + return res; +} + +/** + * Read a line from an opened image + * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open` + * @param x start X coordinate (from left) + * @param y start Y coordinate (from top) + * @param len number of pixels to read + * @param buf store the data here + * @return LV_RES_OK: success; LV_RES_INV: an error occurred + */ +lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + lv_res_t res = LV_RES_INV; + if(dsc->decoder->read_line_cb)res = dsc->decoder->read_line_cb(dsc->decoder, dsc, x, y, len, buf); + + return res; +} + +/** + * Close a decoding session + * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open` + */ +void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc) +{ + if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc); +} + +/** + * Create a new image decoder + * @return pointer to the new image decoder + */ +lv_img_decoder_t * lv_img_decoder_create(void) +{ + lv_img_decoder_t * decoder; + decoder = lv_ll_ins_head(&LV_GC_ROOT(_lv_img_defoder_ll)); + lv_mem_assert(decoder); + if(decoder == NULL) return NULL; + + memset(decoder, 0, sizeof(lv_img_decoder_t)); + + return decoder; +} + +/** + * Delete an image decoder + * @param decoder pointer to an image decoder + */ +void lv_img_decoder_delete(lv_img_decoder_t * decoder) +{ + lv_ll_rem(&LV_GC_ROOT(_lv_img_defoder_ll), decoder); + lv_mem_free(decoder); +} + +/** + * Set a callback to get information about the image + * @param decoder pointer to an image decoder + * @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct) + */ +void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb) +{ + decoder->info_cb = info_cb; +} + +/** + * Set a callback to open an image + * @param decoder pointer to an image decoder + * @param open_cb a function to open an image + */ +void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb) +{ + decoder->open_cb = open_cb; +} + +/** + * Set a callback to a decoded line of an image + * @param decoder pointer to an image decoder + * @param read_line_cb a function to read a line of an image + */ +void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb) +{ + decoder->read_line_cb = read_line_cb; +} + +/** + * Set a callback to close a decoding session. E.g. close files and free other resources. + * @param decoder pointer to an image decoder + * @param close_cb a function to close a decoding session + */ +void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb) +{ + decoder->close_cb = close_cb; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header) +{ + (void)decoder; /*Unused*/ + + lv_img_src_t src_type = lv_img_src_get_type(src); + if(src_type == LV_IMG_SRC_VARIABLE) { + header->w = ((lv_img_dsc_t *)src)->header.w; + header->h = ((lv_img_dsc_t *)src)->header.h; + header->cf = ((lv_img_dsc_t *)src)->header.cf; + } +#if LV_USE_FILESYSTEM + else if(src_type == LV_IMG_SRC_FILE) { + lv_fs_file_t file; + lv_fs_res_t res; + uint32_t rn; + res = lv_fs_open(&file, src, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn); + lv_fs_close(&file); + } + + /*Create a dummy header on fs error*/ + if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) { + header->w = LV_DPI; + header->h = LV_DPI; + header->cf = LV_IMG_CF_UNKNOWN; + return LV_RES_INV; + } + } +#endif + else if(src_type == LV_IMG_SRC_SYMBOL) { + /*The size depend on the font but it is unknown here. It should be handled outside of the + * function*/ + header->w = 1; + header->h = 1; + /* Symbols always have transparent parts. Important because of cover check in the design + * function. The actual value doesn't matter because lv_draw_label will draw it*/ + header->cf = LV_IMG_CF_ALPHA_1BIT; + } else { + LV_LOG_WARN("Image get info found unknown src type"); + return LV_RES_INV; + } + return LV_RES_OK; +} + +static const uint8_t * lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) +{ + /*Open the file if it's a file*/ + if(dsc->src_type == LV_IMG_SRC_FILE) { +#if LV_USE_FILESYSTEM + lv_fs_file_t f; + lv_fs_res_t res = lv_fs_open(&f, dsc->src, LV_FS_MODE_RD); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder can't open the file"); + return LV_IMG_DECODER_OPEN_FAIL; + } + + /*If the file was open successfully save the file descriptor*/ + if(dsc->user_data == NULL) { + dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t)); + if(dsc->user_data == NULL) { + LV_LOG_ERROR("img_decoder_built_in_open: out of memory"); + lv_mem_assert(dsc->user_data); + } + memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t)); + } + + lv_img_decoder_built_in_data_t * user_data = dsc->user_data; + user_data->f = lv_mem_alloc(sizeof(f)); + if(user_data->f == NULL) { + LV_LOG_ERROR("img_decoder_built_in_open: out of memory"); + lv_mem_assert(user_data->f); + } + + memcpy(user_data->f, &f, sizeof(f)); + +#else + LV_LOG_WARN("Image built-in decoder can read file because LV_USE_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } + + lv_img_cf_t cf = dsc->header.cf; + /*Process true color formats*/ + if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { + if(dsc->src_type == LV_IMG_SRC_VARIABLE) { + /* In case of uncompressed formats the image stored in the ROM/RAM. + * So simply give its pointer*/ + return ((lv_img_dsc_t *)dsc->src)->data; + } else { + /*If it's a file it need to be read line by line later*/ + return NULL; + } + } + /*Process indexed images. Build a palette*/ + else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || + cf == LV_IMG_CF_INDEXED_4BIT || cf == LV_IMG_CF_INDEXED_8BIT) { + +#if LV_IMG_CF_INDEXED + uint8_t px_size = lv_img_color_format_get_px_size(cf); + uint32_t palette_size = 1 << px_size; + + /*Allocate the palette*/ + if(dsc->user_data == NULL) { + dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t)); + if(dsc->user_data == NULL) { + LV_LOG_ERROR("img_decoder_built_in_open: out of memory"); + lv_mem_assert(dsc->user_data); + } + memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t)); + } + + lv_img_decoder_built_in_data_t * user_data = dsc->user_data; + user_data->palette = lv_mem_alloc(sizeof(palette_size * sizeof(lv_color_t))); + if(user_data->palette == NULL) { + LV_LOG_ERROR("img_decoder_built_in_open: out of memory"); + lv_mem_assert(user_data->f); + } +#if LV_USE_FILESYSTEM + lv_color32_t palette_tmp[256]; +#endif + lv_color32_t * palette_p; + + if(dsc->src_type == LV_IMG_SRC_FILE) { + /*Read the palette from file*/ +#if LV_USE_FILESYSTEM + lv_fs_seek(user_data->f, 4); /*Skip the header*/ + lv_fs_read(user_data->f, palette_tmp, palette_size * sizeof(lv_color_t), NULL); + palette_p = palette_tmp; +#else + LV_LOG_WARN( + "Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } else { + /*The palette begins in the beginning of the image data. Just point to it.*/ + palette_p = (lv_color32_t *)((lv_img_dsc_t *)dsc->src)->data; + } + + uint32_t i; + for(i = 0; i < palette_size; i++) { + user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue); + } + return NULL; +#else + LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } + /*Alpha indexed images. */ + else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || + cf == LV_IMG_CF_ALPHA_4BIT || cf == LV_IMG_CF_ALPHA_8BIT) { +#if LV_IMG_CF_ALPHA + return NULL; /*Nothing to process*/ +#else + LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA"); + return LV_IMG_DECODER_OPEN_FAIL; +#endif + } + /*Unknown format. Can't decode it.*/ + else { + /*Free the potentially allocated memories*/ + lv_img_decoder_built_in_close(decoder, dsc); + + LV_LOG_WARN("Image decoder open: unknown color format") + return LV_IMG_DECODER_OPEN_FAIL; + } +} + + + +static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + (void)decoder; /*Unused*/ + + lv_res_t res = LV_RES_INV; + + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || + dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || + dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) + { + /* For TRUE_COLOE images read line required only for files. + * For variables the image data was returned in `open`*/ + if(dsc->src_type == LV_IMG_SRC_FILE) { + res = lv_img_decoder_built_in_line_true_color(dsc, x, y, len, buf); + } + } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || + dsc->header.cf == LV_IMG_CF_ALPHA_2BIT || + dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || + dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) { + + res = lv_img_decoder_built_in_line_alpha(dsc, x, y, len, buf); + } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || + dsc->header.cf == LV_IMG_CF_INDEXED_2BIT || + dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || + dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) { + res = lv_img_decoder_built_in_line_indexed(dsc, x, y, len, buf); + } else { + LV_LOG_WARN("Built-in image decoder read not supports the color format"); + return false; + } + + return res; +} + +static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) +{ + (void)decoder; /*Unused*/ + + lv_img_decoder_built_in_data_t * user_data = dsc->user_data; + if(user_data) { + if(user_data->f) lv_mem_free(user_data->f); + if(user_data->palette) lv_mem_free(user_data->palette); + + lv_mem_free(user_data); + + dsc->user_data = NULL; + } +} + + +static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf) +{ + lv_img_decoder_built_in_data_t * user_data = dsc->user_data; + lv_fs_res_t res; + uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + + uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3; + pos += 4; /*Skip the header*/ + res = lv_fs_seek(user_data->f, pos); + if(res != LV_FS_RES_OK) { + LV_LOG_WARN("Built-in image decoder seek failed"); + return LV_RES_INV; + } + uint32_t btr = len * (px_size >> 3); + uint32_t br = 0; + lv_fs_read(user_data->f, buf, btr, &br); + if(res != LV_FS_RES_OK || btr != br) { + LV_LOG_WARN("Built-in image decoder read failed"); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf) +{ + +#if LV_IMG_CF_ALPHA + const lv_opa_t alpha1_opa_table[2] = { + 0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/ + const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/ + const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/ + 68, 85, 102, 119, 136, 153, + 170, 187, 204, 221, 238, 255}; + + /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/ + lv_color_t bg_color = dsc->style->image.color; + lv_coord_t i; + for(i = 0; i < len; i++) { +#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full; +#elif LV_COLOR_DEPTH == 16 + /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/ + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF; + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF; +#elif LV_COLOR_DEPTH == 32 + *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full; +#else +#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h" +#endif + } + + const lv_opa_t * opa_table = NULL; + uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + uint32_t ofs = 0; + int8_t pos = 0; + switch(dsc->header.cf) { + case LV_IMG_CF_ALPHA_1BIT: + w = (dsc->header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(dsc->header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + pos = 7 - (x & 0x7); + opa_table = alpha1_opa_table; + break; + case LV_IMG_CF_ALPHA_2BIT: + w = (dsc->header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(dsc->header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + pos = 6 - ((x & 0x3) * 2); + opa_table = alpha2_opa_table; + break; + case LV_IMG_CF_ALPHA_4BIT: + w = (dsc->header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(dsc->header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + pos = 4 - ((x & 0x1) * 4); + opa_table = alpha4_opa_table; + break; + case LV_IMG_CF_ALPHA_8BIT: + w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + pos = 0; + break; + } + +#if LV_USE_FILESYSTEM + lv_img_decoder_built_in_data_t * user_data = dsc->user_data; +#if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +#else + uint8_t fs_buf[LV_HOR_RES_MAX]; +#endif +#endif + const uint8_t * data_tmp = NULL; + if(dsc->src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = dsc->src; + + data_tmp = img_dsc->data + ofs; + } else { +#if LV_USE_FILESYSTEM + lv_fs_seek(user_data->f, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(user_data->f, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN( "Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + uint8_t byte_act = 0; + uint8_t val_act; + for(i = 0; i < len; i++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + + buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = + dsc->header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; + +#else + LV_LOG_WARN( + "Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} + +static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf) +{ + +#if LV_IMG_CF_INDEXED + uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf); + uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/ + + lv_coord_t w = 0; + int8_t pos = 0; + uint32_t ofs = 0; + switch(dsc->header.cf) { + case LV_IMG_CF_INDEXED_1BIT: + w = (dsc->header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/ + if(dsc->header.w & 0x7) w++; + ofs += w * y + (x >> 3); /*First pixel*/ + ofs += 8; /*Skip the palette*/ + pos = 7 - (x & 0x7); + break; + case LV_IMG_CF_INDEXED_2BIT: + w = (dsc->header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/ + if(dsc->header.w & 0x3) w++; + ofs += w * y + (x >> 2); /*First pixel*/ + ofs += 16; /*Skip the palette*/ + pos = 6 - ((x & 0x3) * 2); + break; + case LV_IMG_CF_INDEXED_4BIT: + w = (dsc->header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/ + if(dsc->header.w & 0x1) w++; + ofs += w * y + (x >> 1); /*First pixel*/ + ofs += 64; /*Skip the palette*/ + pos = 4 - ((x & 0x1) * 4); + break; + case LV_IMG_CF_INDEXED_8BIT: + w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/ + ofs += w * y + x; /*First pixel*/ + ofs += 1024; /*Skip the palette*/ + pos = 0; + break; + } + + lv_img_decoder_built_in_data_t * user_data = dsc->user_data; + +#if LV_USE_FILESYSTEM +#if LV_COMPILER_VLA_SUPPORTED + uint8_t fs_buf[w]; +#else + uint8_t fs_buf[LV_HOR_RES_MAX]; +#endif +#endif + const uint8_t * data_tmp = NULL; + if(dsc->src_type == LV_IMG_SRC_VARIABLE) { + const lv_img_dsc_t * img_dsc = dsc->src; + data_tmp = img_dsc->data + ofs; + } else { +#if LV_USE_FILESYSTEM + lv_fs_seek(user_data->f, ofs + 4); /*+4 to skip the header*/ + lv_fs_read(user_data->f, fs_buf, w, NULL); + data_tmp = fs_buf; +#else + LV_LOG_WARN( + "Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0"); + data_tmp = NULL; /*To avoid warnings*/ + return LV_RES_INV; +#endif + } + + uint8_t byte_act = 0; + uint8_t val_act; + lv_coord_t i; + lv_color_t * cbuf = (lv_color_t *)buf; + for(i = 0; i < len; i++) { + val_act = (data_tmp[byte_act] & (mask << pos)) >> pos; + cbuf[i] = user_data->palette[val_act]; + + pos -= px_size; + if(pos < 0) { + pos = 8 - px_size; + data_tmp++; + } + } + + return LV_RES_OK; +#else + LV_LOG_WARN( + "Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h"); + return LV_RES_INV; +#endif +} + + + diff --git a/src/lv_draw/lv_img_decoder.h b/src/lv_draw/lv_img_decoder.h new file mode 100644 index 000000000..811247869 --- /dev/null +++ b/src/lv_draw/lv_img_decoder.h @@ -0,0 +1,307 @@ +/** + * @file lv_img_decoder.h + * + */ + +#ifndef LV_IMG_DEOCER_H +#define LV_IMG_DEOCER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../../lv_conf.h" +#endif + +#include +#include "../lv_misc/lv_fs.h" +#include "../lv_misc/lv_types.h" +#include "../lv_misc/lv_area.h" +#include "../lv_core/lv_style.h" + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + + +#define LV_IMG_DECODER_OPEN_FAIL ((void *)(-1)) + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_IMG_SRC_VARIABLE, + LV_IMG_SRC_FILE, + LV_IMG_SRC_SYMBOL, + LV_IMG_SRC_UNKNOWN, +}; + +typedef uint8_t lv_img_src_t; + +typedef struct +{ + + /* The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c */ + uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a + non-printable character*/ + + uint32_t reserved : 2; /*Reserved to be used later*/ + + uint32_t w : 11; /*Width of the image map*/ + uint32_t h : 11; /*Height of the image map*/ +} lv_img_header_t; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKNOWN = 0, + + LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder + function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs + custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels + will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + +struct _lv_img_decoder; +struct _lv_img_decoder_dsc; + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use + * `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(struct _lv_img_decoder * decoder, const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param src the image source. Can be a pointer to a C array or a file name (Use + * `lv_img_src_get_type` to determine the type) + * @param style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image + * line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an + * error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param x start x coordinate + * @param y start y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc); + +typedef struct _lv_img_decoder { + lv_img_decoder_info_f_t info_cb; + lv_img_decoder_open_f_t open_cb; + lv_img_decoder_read_line_f_t read_line_cb; + lv_img_decoder_close_f_t close_cb; + +#if LV_USE_USER_DATA + lv_img_decoder_user_data_t user_data; +#endif +}lv_img_decoder_t; + + +typedef struct _lv_img_decoder_dsc { + lv_img_decoder_t * decoder; + const lv_style_t * style; + const void * src; + lv_img_src_t src_type; + lv_img_header_t header; + +#if LV_USE_USER_DATA + void * user_data; +#endif +}lv_img_decoder_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the image decoder module + */ +void lv_img_decoder_init(void); + +/** + * Get information about an image. + * Try the created image decoder one by one. Once one is able to get info that info will be used. + * @param src the image source. Can be + * 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`) + * 2) Variable: Pointer to an `lv_img_dsc_t` variable + * 3) Symbol: E.g. `LV_SYMBOL_OK` + * @param header the image info will be stored here + * @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image + */ +lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header); + +/** + * Open an image. + * Try the created image decoder one by one. Once one is able to open the image that decoder is save in `dsc` + * @param dsc describe a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable. + * @param src the image source. Can be + * 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`) + * 2) Variable: Pointer to an `lv_img_dsc_t` variable + * 3) Symbol: E.g. `LV_SYMBOL_OK` + * @param style the style of the image + * @return LV_IMG_DECODER_OPEN_FAIL: can open the image + * NULL: the image is opened but `lv_img_decoder_read_line` needs to be used to get the info line by line + * Else: a pointer to a buffer which holds the uncompressed pixels of the image + */ +const uint8_t * lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style); + +/** + * Read a line from an opened image + * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open` + * @param x start X coordinate (from left) + * @param y start Y coordinate (from top) + * @param len number of pixels to read + * @param buf store the data here + * @return LV_RES_OK: success; LV_RES_INV: an error occurred + */ +lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close a decoding session + * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open` + */ +void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc); + +/** + * Create a new image decoder + * @return pointer to the new image decoder + */ +lv_img_decoder_t * lv_img_decoder_create(void); + +/** + * Delete an image decoder + * @param decoder pointer to an image decoder + */ +void lv_img_decoder_delete(lv_img_decoder_t * decoder); + +/** + * Set a callback to get information about the image + * @param decoder pointer to an image decoder + * @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct) + */ +void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb); + +/** + * Set a callback to open an image + * @param decoder pointer to an image decoder + * @param open_cb a function to open an image + */ +void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb); + +/** + * Set a callback to a decoded line of an image + * @param decoder pointer to an image decoder + * @param read_line_cb a function to read a line of an image + */ +void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb); + +/** + * Set a callback to close a decoding session. E.g. close files and free other resources. + * @param decoder pointer to an image decoder + * @param close_cb a function to close a decoding session + */ +void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb); + +/** + * Set a custom user data in an image decoder. + * @param decoder pointer to an image decoder + * @param user_data the user data to set + */ +static inline void lv_img_decoder_set_user_data(lv_img_decoder_t * decoder, lv_img_decoder_t user_data) +{ + memcpy(&decoder->user_data, &user_data, sizeof(user_data)); +} + +/** + * Get the user data + * @param decoder pointer to an image decoder + * @return the user data + */ +static inline lv_img_decoder_user_data_t lv_img_decoder_get_user_data(lv_img_decoder_t * decoder) +{ + return decoder->user_data; +} + +/** + * Get a pointer to the user data + * @param decoder pointer to an image decoder + * @return pointer to the user data + */ +static inline lv_img_decoder_user_data_t * lv_img_decoder_get_user_data_ptr(lv_img_decoder_t * decoder) +{ + return &decoder->user_data; +} + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/src/lv_hal/lv_hal_disp.h b/src/lv_hal/lv_hal_disp.h index 320af018e..ba35b6c67 100644 --- a/src/lv_hal/lv_hal_disp.h +++ b/src/lv_hal/lv_hal_disp.h @@ -99,19 +99,10 @@ typedef struct _disp_drv_t const lv_area_t * fill_area, lv_color_t color); #endif -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA lv_disp_drv_user_data_t user_data; #endif -#if LV_USE_USER_DATA_MULTI - lv_disp_drv_user_data_t flush_user_data; - lv_disp_drv_user_data_t mem_blend_user_data; - lv_disp_drv_user_data_t mem_fill_user_data; - lv_disp_drv_user_data_t rounder_user_data; - lv_disp_drv_user_data_t set_px_user_data; - lv_disp_drv_user_data_t monitor_user_data; -#endif - } lv_disp_drv_t; struct _lv_obj_t; diff --git a/src/lv_hal/lv_hal_indev.h b/src/lv_hal/lv_hal_indev.h index d5ac7f4f2..cea6ebba7 100644 --- a/src/lv_hal/lv_hal_indev.h +++ b/src/lv_hal/lv_hal_indev.h @@ -81,16 +81,10 @@ typedef struct _lv_indev_drv_t /*Called when an action happened on the input device.*/ void (*feedback_cb)(struct _lv_indev_drv_t *, uint8_t); -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA lv_indev_drv_user_data_t user_data; #endif -#if LV_USE_USER_DATA_MULTI - lv_indev_drv_user_data_t read_user_data; - lv_indev_drv_user_data_t feedback_user_data; -#endif - - /*Pointer to the assigned display*/ struct _disp_t * disp; diff --git a/src/lv_misc/lv_anim.c b/src/lv_misc/lv_anim.c index ef2d6696c..40e9eec8b 100644 --- a/src/lv_misc/lv_anim.c +++ b/src/lv_misc/lv_anim.c @@ -53,7 +53,7 @@ static bool anim_list_changed; /** * Init. the animation module */ -void lv_anim_init(void) +void lv_anim_core_init(void) { lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t)); last_task_run = lv_tick_get(); @@ -61,15 +61,30 @@ void lv_anim_init(void) } /** - * Create an animation - * @param anim_p an initialized 'anim_t' variable. Not required after call. + * Initialize an animation variable. + * E.g.: + * lv_anim_t a; + * lv_anim_init(&a); + * lv_anim_set_...(&a); + * lv_anim_craete(&a); + * @param a pointer to an `lv_anim_t` variable to initialize */ -void lv_anim_create(lv_anim_t * anim_p) +void lv_anim_init(lv_anim_t * a) +{ + memset(a, 0, sizeof(lv_anim_t)); + a->time = 500; + a->end = 100; +} +/** + * Create an animation + * @param a an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * a) { LV_LOG_TRACE("animation create started") /* Do not let two animations for the same 'var' with the same 'fp'*/ - if(anim_p->exec_cb != NULL) - lv_anim_del(anim_p->var, anim_p->exec_cb); /*fp == NULL would delete all animations of var*/ + if(a->exec_cb != NULL) + lv_anim_del(a->var, a->exec_cb); /*fp == NULL would delete all animations of var*/ /*Add the new animation to the animation linked list*/ lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll)); @@ -77,8 +92,8 @@ void lv_anim_create(lv_anim_t * anim_p) if(new_anim == NULL) return; /*Initialize the animation descriptor*/ - anim_p->playback_now = 0; - memcpy(new_anim, anim_p, sizeof(lv_anim_t)); + a->playback_now = 0; + memcpy(new_anim, a, sizeof(lv_anim_t)); /*Set the start value*/ if(new_anim->exec_cb != NULL) new_anim->exec_cb(new_anim->var, new_anim->start); @@ -91,13 +106,13 @@ void lv_anim_create(lv_anim_t * anim_p) } /** - * Delete an animation for a variable with a given animator function + * Delete an animation of a variable with a given animator function * @param var pointer to variable - * @param fp a function pointer which is animating 'var', - * or NULL to delete all animations of 'var' + * @param exec_cb a function pointer which is animating 'var', + * or NULL to delete all the animations of 'var' * @return true: at least 1 animation is deleted, false: no animation is deleted */ -bool lv_anim_del(void * var, lv_anim_exec_cb_t fp) +bool lv_anim_del(void * var, lv_anim_exec_cb_t exec_cb) { lv_anim_t * a; lv_anim_t * a_next; @@ -107,7 +122,7 @@ bool lv_anim_del(void * var, lv_anim_exec_cb_t fp) /*'a' might be deleted, so get the next object while 'a' is valid*/ a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a); - if(a->var == var && (a->exec_cb == fp || fp == NULL)) { + if(a->var == var && (a->exec_cb == exec_cb || exec_cb == NULL)) { lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a); lv_mem_free(a); anim_list_changed = true; /*Read by `anim_task`. It need to know if a delete occurred in diff --git a/src/lv_misc/lv_anim.h b/src/lv_misc/lv_anim.h index 95444d60b..552b7ac14 100644 --- a/src/lv_misc/lv_anim.h +++ b/src/lv_misc/lv_anim.h @@ -23,6 +23,7 @@ extern "C" { #include #include +#include /********************* * DEFINES @@ -32,19 +33,28 @@ extern "C" { * TYPEDEFS **********************/ -typedef int16_t lv_anim_value_t; /*Type of the animated value*/ - struct _lv_anim_t; -/*Generic prototype of "animator" functions*/ +/*Type of the animated value*/ +typedef int16_t lv_anim_value_t; + +/* Generic prototype of "animator" functions. + * First parameter is the variable to animate. + * Second parameter is the value to set. + * Compatible with `lv_xxx_set_yyy(obj, value)` functions*/ typedef void (*lv_anim_exec_cb_t)(void *, lv_anim_value_t); -/*Get the current value in an animation*/ +/* Same as `lv_anim_exec_cb_t` but receives `lv_anim_t *` as the first parameter. + * It's more consistent but less convenient. Might be used by binding generator functions.*/ +typedef void (*lv_anim_custom_exec_cb_t)(struct _lv_anim_t *, lv_anim_value_t); + +/*Get the current value during an animation*/ typedef lv_anim_value_t (*lv_anim_path_cb_t)(const struct _lv_anim_t *); -/*Callback for animation ready*/ +/*Callback to call when the animation is ready*/ typedef void (*lv_anim_ready_cb_t)(struct _lv_anim_t *); +/*Describe an animation*/ typedef struct _lv_anim_t { void * var; /*Variable to animate*/ @@ -57,40 +67,17 @@ typedef struct _lv_anim_t int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ uint16_t playback_pause; /*Wait before play back*/ uint16_t repeat_pause; /*Wait before repeat*/ -#if LV_USE_USER_DATA_SINGLE +#if LV_USE_USER_DATA lv_anim_user_data_t user_data; /*Custom user data*/ #endif -#if LV_USE_USER_DATA_MULTI - lv_anim_user_data_t exec_user_data; - lv_anim_user_data_t path_user_data; - lv_anim_user_data_t ready_user_data; -#endif - uint8_t playback : 1; /*When the animation is ready play it back*/ uint8_t repeat : 1; /*Repeat the animation infinitely*/ /*Animation system use these - user shouldn't set*/ uint8_t playback_now : 1; /*Play back is in progress*/ - uint32_t has_run : 1; /*Indicates the animation has run it this round*/ + uint32_t has_run : 1; /*Indicates the animation has run in this round*/ } lv_anim_t; -/*Example initialization -lv_anim_t a; -a.var = obj; -a.start = lv_obj_get_height(obj); -a.end = new_height; -a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_height; -a.path_cb = lv_anim_path_linear; -a.ready_cb = NULL; -a.act_time = 0; -a.time = 200; -a.playback = 0; -a.playback_pause = 0; -a.repeat = 0; -a.repeat_pause = 0; -a.user_data = NULL; -lv_anim_create(&a); - */ /********************** * GLOBAL PROTOTYPES **********************/ @@ -98,22 +85,199 @@ lv_anim_create(&a); /** * Init. the animation module */ -void lv_anim_init(void); +void lv_anim_core_init(void); + +/** + * Initialize an animation variable. + * E.g.: + * lv_anim_t a; + * lv_anim_init(&a); + * lv_anim_set_...(&a); + * lv_anim_create(&a); + * @param a pointer to an `lv_anim_t` variable to initialize + */ +void lv_anim_init(lv_anim_t * a); + +/** + * Set a variable to animate + * @param a pointer to an initialized `lv_anim_t` variable + * @param var pointer to a variable to animate + */ +static inline void lv_anim_set_var(lv_anim_t * a, void * var) +{ + a->var = var; +} + +/** + * Set the duration and delay of an animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param duration duration of the animation in milliseconds + * @param delay delay before the animation in milliseconds + */ +static inline void lv_anim_set_time(lv_anim_t * a, uint16_t duration, uint16_t delay) +{ + a->time = duration; + a->act_time = -delay; +} + +/** + * Set the start and end values of an animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param start the start value + * @param end the end value + */ +static inline void lv_anim_set_values(lv_anim_t * a, lv_anim_value_t start, lv_anim_value_t end) +{ + a->start = start; + a->end = end; +} + +/** + * Set a function to execute by the aniamtion + * @param a pointer to an initialized `lv_anim_t` variable + * @param exec_cb a function to execute. + * LittelvGL's built-in functions can be used. + * E.g. lv_obj_set_x + */ +static inline void lv_anim_set_exec_cb(lv_anim_t * a, lv_anim_exec_cb_t exec_cb) +{ + a->exec_cb = exec_cb; +} + +/** + * The same as `lv_anim_set_exec_cb` but `lv_anim_custom_exec_cb_t` receives + * `lv_anim_t * ` as its first parameter instead of `void *`. + * This function might be used when LittlevGL is binded to other languages because + * it's more consistent to have `lv_anim_t *` as first parameter. + * @param a pointer to an initialized `lv_anim_t` variable + * @param exec_cb a function to execute. + */ +static inline void lv_anim_set_custom_exec_cb(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb) +{ + a->exec_cb = (lv_anim_exec_cb_t)exec_cb; +} + +/** + * Set the path (curve) of the animation. + * @param a pointer to an initialized `lv_anim_t` variable + * @param path_cb a function the get the current value of the animation. + * The built in functions starts with `lv_anim_path_...` + */ +static inline void lv_anim_set_path_cb(lv_anim_t * a, lv_anim_path_cb_t path_cb) +{ + a->path_cb = path_cb; +} + +/** + * Set a function call when the animation is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param ready_cb a function call when the animation is ready + */ +static inline void lv_anim_set_ready_cb(lv_anim_t * a, lv_anim_ready_cb_t ready_cb) +{ + a->ready_cb = ready_cb; +} + +/** + * Make the animation to play back to when the forward direction is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param wait_time time in milliseconds to wait before starting the back direction + */ +static inline void lv_anim_set_playback(lv_anim_t * a, uint16_t wait_time) +{ + a->playback = 1; + a->playback_pause = wait_time; +} + +/** + * Disable playback. (Disabled after `lv_anim_init()`) + * @param a pointer to an initialized `lv_anim_t` variable + */ +static inline void lv_anim_clear_playback(lv_anim_t * a) +{ + a->playback = 0; +} + +/** + * Make the animation to start again when ready. + * @param a pointer to an initialized `lv_anim_t` variable + * @param wait_time time in milliseconds to wait before starting the animation again + */ +static inline void lv_anim_set_repeat(lv_anim_t * a, uint16_t wait_time) +{ + a->repeat = 1; + a->repeat_pause = wait_time; +} + +/** + * Disable repeat. (Disabled after `lv_anim_init()`) + * @param a pointer to an initialized `lv_anim_t` variable + */ +static inline void lv_anim_clear_repeat(lv_anim_t * a) +{ + a->repeat = 0; +} + +/** + * Set a user specific data for the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param user_data the user data + */ +static inline void lv_anim_set_user_data(lv_anim_t * a, lv_anim_user_data_t user_data) +{ + memcpy(&a->user_data, &user_data, sizeof(user_data)); +} + +/** + * Get the user data + * @param a pointer to an initialized `lv_anim_t` variable + * @return the user data + */ +static inline lv_anim_user_data_t lv_anim_get_user_data(lv_anim_t * a) +{ + return a->user_data; +} + +/** + * Get pointer to the user data + * @param a pointer to an initialized `lv_anim_t` variable + * @return pointer to the user data + */ +static inline lv_anim_user_data_t * lv_anim_get_user_data_ptr(lv_anim_t * a) +{ + return &a->user_data; +} /** * Create an animation - * @param anim_p an initialized 'anim_t' variable. Not required after call. + * @param a an initialized 'anim_t' variable. Not required after call. */ -void lv_anim_create(lv_anim_t * anim_p); +void lv_anim_create(lv_anim_t * a); /** - * Delete an animation for a variable with a given animatior function + * Delete an animation of a variable with a given animator function * @param var pointer to variable - * @param fp a function pointer which is animating 'var', - * or NULL to ignore it and delete all animation with 'var + * @param exec_cb a function pointer which is animating 'var', + * or NULL to ignore it and delete all the animations of 'var * @return true: at least 1 animation is deleted, false: no animation is deleted */ -bool lv_anim_del(void * var, lv_anim_exec_cb_t fp); +bool lv_anim_del(void * var, lv_anim_exec_cb_t exec_cb); + +/** + * Delete an aniamation by getting the animated variable from `a`. + * Only animations with `exec_cb` will be deleted. + * This function exist becasue it's logical that all anim functions receives an + * `lv_anim_t` as their first parameter. It's not practical in C but might makes + * the API more conequent and makes easier to genrate bindings. + * @param a pointer to an animation. + * @param exec_cb a function pointer which is animating 'var', + * or NULL to ignore it and delete all the animations of 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +static inline bool lv_anim_custom_del(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb) +{ + return lv_anim_del(a->var, (lv_anim_exec_cb_t)exec_cb); +} /** * Get the number of currently running animations diff --git a/src/lv_misc/lv_gc.h b/src/lv_misc/lv_gc.h index 97aeb6b79..ac9d93f3d 100644 --- a/src/lv_misc/lv_gc.h +++ b/src/lv_misc/lv_gc.h @@ -37,6 +37,7 @@ extern "C" { prefix lv_ll_t _lv_file_ll; \ prefix lv_ll_t _lv_anim_ll; \ prefix lv_ll_t _lv_group_ll; \ + prefix lv_ll_t _lv_img_defoder_ll; \ prefix void * _lv_task_act; #define LV_NO_PREFIX diff --git a/src/lv_misc/lv_ll.c b/src/lv_misc/lv_ll.c index c979f91da..7901a87ad 100644 --- a/src/lv_misc/lv_ll.c +++ b/src/lv_misc/lv_ll.c @@ -371,6 +371,9 @@ void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after) /*If `n_act` was moved before NULL then it become the new tail*/ if(n_after == NULL) ll_p->tail = n_act; + + /*If `n_act` was moved before `NULL` then it's the new head*/ + if(n_before == NULL) ll_p->head = n_act; } /** diff --git a/src/lv_misc/lv_mem.c b/src/lv_misc/lv_mem.c index bfea3490b..6dfcea849 100644 --- a/src/lv_misc/lv_mem.c +++ b/src/lv_misc/lv_mem.c @@ -126,7 +126,9 @@ void * lv_mem_alloc(uint32_t size) #endif void * alloc = NULL; -#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/ + +#if LV_MEM_CUSTOM == 0 + /*Use the built-in allocators*/ lv_mem_ent_t * e = NULL; // Search for a appropriate entry @@ -141,7 +143,8 @@ void * lv_mem_alloc(uint32_t size) // End if there is not next entry OR the alloc. is successful } while(e != NULL && alloc == NULL); -#else /*Use custom, user defined malloc function*/ +#else +/*Use custom, user defined malloc function*/ #if LV_ENABLE_GC == 1 /*gc must not include header*/ alloc = LV_MEM_CUSTOM_ALLOC(size); #else /* LV_ENABLE_GC */ @@ -150,6 +153,7 @@ void * lv_mem_alloc(uint32_t size) if(alloc != NULL) { ((lv_mem_ent_t *)alloc)->header.s.d_size = size; ((lv_mem_ent_t *)alloc)->header.s.used = 1; + alloc = &((lv_mem_ent_t *)alloc)->first_data; } #endif /* LV_ENABLE_GC */ diff --git a/src/lv_misc/lv_task.c b/src/lv_misc/lv_task.c index af7c105aa..4b35e3997 100644 --- a/src/lv_misc/lv_task.c +++ b/src/lv_misc/lv_task.c @@ -20,6 +20,8 @@ * DEFINES *********************/ #define IDLE_MEAS_PERIOD 500 /*[ms]*/ +#define DEF_PRIO LV_TASK_PRIO_MID +#define DEF_PERIOD 500 /********************** * TYPEDEFS @@ -28,7 +30,7 @@ /********************** * STATIC PROTOTYPES **********************/ -static bool lv_task_exec(lv_task_t * lv_task_p); +static bool lv_task_exec(lv_task_t * task); /********************** * STATIC VARIABLES @@ -49,7 +51,7 @@ static bool task_created; /** * Init the lv_task module */ -void lv_task_init(void) +void lv_task_core_init(void) { lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t)); @@ -159,6 +161,59 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) LV_LOG_TRACE("lv_task_handler ready"); } +/** + * Create an "empty" task. It needs to initialzed with at least + * `lv_task_set_cb` and `lv_task_set_period` + * @return pointer to the craeted task + */ +lv_task_t * lv_task_create_basic(void) +{ + lv_task_t * new_task = NULL; + lv_task_t * tmp; + + /*Create task lists in order of priority from high to low*/ + tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); + + /*It's the first task*/ + if(NULL == tmp) { + new_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll)); + lv_mem_assert(new_task); + if(new_task == NULL) return NULL; + } + /*Insert the new task to proper place according to its priority*/ + else { + do { + if(tmp->prio <= DEF_PRIO) { + new_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp); + lv_mem_assert(new_task); + if(new_task == NULL) return NULL; + break; + } + tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp); + } while(tmp != NULL); + + /*Only too high priority tasks were found. Add the task to the end*/ + if(tmp == NULL) { + new_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll)); + lv_mem_assert(new_task); + if(new_task == NULL) return NULL; + } + } + + new_task->period = DEF_PERIOD; + new_task->task_cb = NULL; + new_task->prio = DEF_PRIO; + + new_task->once = 0; + new_task->last_run = lv_tick_get(); + + new_task->user_data= NULL; + + task_created = true; + + return new_task; +} + /** * Create a new lv_task @@ -168,127 +223,106 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void) * @param user_data custom parameter * @return pointer to the new task */ -lv_task_t * lv_task_create(void (*task)(lv_task_t *), uint32_t period, lv_task_prio_t prio, void * user_data) +lv_task_t * lv_task_create(lv_task_cb_t task_cb, uint32_t period, lv_task_prio_t prio, void * user_data) { - lv_task_t * new_lv_task = NULL; - lv_task_t * tmp; + lv_task_t * new_task = lv_task_create_basic(); + lv_mem_assert(new_task); + if(new_task == NULL) return NULL; - /*Create task lists in order of priority from high to low*/ - tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll)); - if(NULL == tmp) { /*First task*/ - new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll)); - lv_mem_assert(new_lv_task); - if(new_lv_task == NULL) return NULL; - } else { - do { - if(tmp->prio <= prio) { - new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp); - lv_mem_assert(new_lv_task); - if(new_lv_task == NULL) return NULL; - break; - } - tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp); - } while(tmp != NULL); + lv_task_set_cb(new_task, task_cb); + lv_task_set_period(new_task, period); + lv_task_set_prio(new_task, prio); + new_task->user_data = user_data; - if(tmp == NULL) { /*Only too high priority tasks were found*/ - new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll)); - lv_mem_assert(new_lv_task); - if(new_lv_task == NULL) return NULL; - } - } + return new_task; +} - new_lv_task->period = period; - new_lv_task->task_cb = task; - new_lv_task->prio = prio; - - new_lv_task->once = 0; - new_lv_task->last_run = lv_tick_get(); - - new_lv_task->user_data = user_data; - -#if LV_USE_USER_DATA_MULTI - new_lv_task->task_user_data = NULL; -#endif - - task_created = true; - - return new_lv_task; +/** + * Set the callback the task (the function to call periodically) + * @param task pointer to a task + * @param task_cb teh function to call periodically + */ +void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb) +{ + task->task_cb = task_cb; } /** * Delete a lv_task - * @param lv_task_p pointer to task created by lv_task_p + * @param task pointer to task created by task */ -void lv_task_del(lv_task_t * lv_task_p) +void lv_task_del(lv_task_t * task) { - lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p); + lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), task); - lv_mem_free(lv_task_p); + lv_mem_free(task); - if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true; /*The active task was deleted*/ + if(LV_GC_ROOT(_lv_task_act) == task) task_deleted = true; /*The active task was deleted*/ } /** * Set new priority for a lv_task - * @param lv_task_p pointer to a lv_task + * @param task pointer to a lv_task * @param prio the new priority */ -void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio) +void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio) { + if(task->prio == prio) return; + /*Find the tasks with new priority*/ lv_task_t * i; LV_LL_READ(LV_GC_ROOT(_lv_task_ll), i) { if(i->prio <= prio) { - if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i); + if(i != task) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, i); break; } } /*There was no such a low priority so far then add the node to the tail*/ if(i == NULL) { - lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL); + lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, NULL); } - lv_task_p->prio = prio; + task->prio = prio; } /** * Set new period for a lv_task - * @param lv_task_p pointer to a lv_task + * @param task pointer to a lv_task * @param period the new period */ -void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period) +void lv_task_set_period(lv_task_t * task, uint32_t period) { - lv_task_p->period = period; + task->period = period; } /** * Make a lv_task ready. It will not wait its period. - * @param lv_task_p pointer to a lv_task. + * @param task pointer to a lv_task. */ -void lv_task_ready(lv_task_t * lv_task_p) +void lv_task_ready(lv_task_t * task) { - lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1; + task->last_run = lv_tick_get() - task->period - 1; } /** * Delete the lv_task after one call - * @param lv_task_p pointer to a lv_task. + * @param task pointer to a lv_task. */ -void lv_task_once(lv_task_t * lv_task_p) +void lv_task_once(lv_task_t * task) { - lv_task_p->once = 1; + task->once = 1; } /** * Reset a lv_task. * It will be called the previously set period milliseconds later. - * @param lv_task_p pointer to a lv_task. + * @param task pointer to a lv_task. */ -void lv_task_reset(lv_task_t * lv_task_p) +void lv_task_reset(lv_task_t * task) { - lv_task_p->last_run = lv_tick_get(); + task->last_run = lv_tick_get(); } /** @@ -315,25 +349,25 @@ uint8_t lv_task_get_idle(void) /** * Execute task if its the priority is appropriate - * @param lv_task_p pointer to lv_task + * @param task pointer to lv_task * @return true: execute, false: not executed */ -static bool lv_task_exec(lv_task_t * lv_task_p) +static bool lv_task_exec(lv_task_t * task) { bool exec = false; /*Execute if at least 'period' time elapsed*/ - uint32_t elp = lv_tick_elaps(lv_task_p->last_run); - if(elp >= lv_task_p->period) { - lv_task_p->last_run = lv_tick_get(); + uint32_t elp = lv_tick_elaps(task->last_run); + if(elp >= task->period) { + task->last_run = lv_tick_get(); task_deleted = false; task_created = false; - lv_task_p->task_cb(lv_task_p); + if(task->task_cb) task->task_cb(task); /*Delete if it was a one shot lv_task*/ if(task_deleted == false) { /*The task might be deleted by itself as well*/ - if(lv_task_p->once != 0) { - lv_task_del(lv_task_p); + if(task->once != 0) { + lv_task_del(task); } } exec = true; diff --git a/src/lv_misc/lv_task.h b/src/lv_misc/lv_task.h index 0a01a6acf..7a814a6ff 100644 --- a/src/lv_misc/lv_task.h +++ b/src/lv_misc/lv_task.h @@ -34,6 +34,14 @@ extern "C" { /********************** * TYPEDEFS **********************/ + +struct _lv_task_t; + +/** + * Tasks execte this type type of functions. + */ +typedef void (*lv_task_cb_t)(struct _lv_task_t *); + /** * Possible priorities for lv_tasks */ @@ -55,14 +63,10 @@ typedef struct _lv_task_t { uint32_t period; uint32_t last_run; - void (*task_cb)(struct _lv_task_t *); + lv_task_cb_t task_cb; void * user_data; -#if LV_USE_USER_DATA_MULTI - void * task_user_data; -#endif - uint8_t prio : 3; uint8_t once : 1; } lv_task_t; @@ -74,61 +78,75 @@ typedef struct _lv_task_t /** * Init the lv_task module */ -void lv_task_init(void); +void lv_task_core_init(void); /** * Call it periodically to handle lv_tasks. */ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); +/** + * Create an "empty" task. It needs to initialzed with at least + * `lv_task_set_cb` and `lv_task_set_period` + * @return pointer to the craeted task + */ +lv_task_t * lv_task_create_basic(void); + /** * Create a new lv_task * @param task a function which is the task itself * @param period call period in ms unit * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) * @param user_data custom parameter - * @return pointer to the new task_cb + * @return pointer to the new task */ -lv_task_t * lv_task_create(void (*task)(lv_task_t *), uint32_t period, lv_task_prio_t prio, void * user_data); +lv_task_t * lv_task_create(lv_task_cb_t task_cb, uint32_t period, lv_task_prio_t prio, void * user_data); /** * Delete a lv_task - * @param lv_task_p pointer to task_cb created by lv_task_p + * @param task pointer to task_cb created by task */ -void lv_task_del(lv_task_t * lv_task_p); +void lv_task_del(lv_task_t * task); + +/** + * Set the callback the task (the function to call periodically) + * @param task pointer to a task + * @param taack_cb teh function to call periodically + */ +void lv_task_set_cb(lv_task_t * task, lv_task_cb_t taack_cb); /** * Set new priority for a lv_task - * @param lv_task_p pointer to a lv_task + * @param task pointer to a lv_task * @param prio the new priority */ -void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio); +void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio); /** * Set new period for a lv_task - * @param lv_task_p pointer to a lv_task + * @param task pointer to a lv_task * @param period the new period */ -void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period); +void lv_task_set_period(lv_task_t * task, uint32_t period); /** * Make a lv_task ready. It will not wait its period. - * @param lv_task_p pointer to a lv_task. + * @param task pointer to a lv_task. */ -void lv_task_ready(lv_task_t * lv_task_p); +void lv_task_ready(lv_task_t * task); /** * Delete the lv_task after one call - * @param lv_task_p pointer to a lv_task. + * @param task pointer to a lv_task. */ -void lv_task_once(lv_task_t * lv_task_p); +void lv_task_once(lv_task_t * task); /** * Reset a lv_task. * It will be called the previously set period milliseconds later. - * @param lv_task_p pointer to a lv_task. + * @param task pointer to a lv_task. */ -void lv_task_reset(lv_task_t * lv_task_p); +void lv_task_reset(lv_task_t * task); /** * Enable or disable the whole lv_task handling diff --git a/src/lv_misc/lv_types.h b/src/lv_misc/lv_types.h new file mode 100644 index 000000000..bdd860f56 --- /dev/null +++ b/src/lv_misc/lv_types.h @@ -0,0 +1,44 @@ +/** + * @file lv_types.h + * + */ + +#ifndef LV_TYPES_H +#define LV_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action + function or an operation was failed*/ + LV_RES_OK, /*The object is valid (no deleted) after the action*/ +}; +typedef uint8_t lv_res_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TYPES_H*/ diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index 510ad9f58..f9eca884d 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -15,6 +15,7 @@ #endif #include "../lv_themes/lv_theme.h" +#include "../lv_draw/lv_img_decoder.h" #include "../lv_misc/lv_fs.h" #include "../lv_misc/lv_txt.h" #include "../lv_misc/lv_log.h" @@ -148,7 +149,7 @@ void lv_img_set_src(lv_obj_t * img, const void * src_img) } lv_img_header_t header; - lv_img_dsc_get_info(src_img, &header); + lv_img_decoder_get_info(src_img, &header); /*Save the source*/ if(src_type == LV_IMG_SRC_VARIABLE) { diff --git a/src/lv_objx/lv_imgbtn.c b/src/lv_objx/lv_imgbtn.c index cf98c82b1..952644087 100644 --- a/src/lv_objx/lv_imgbtn.c +++ b/src/lv_objx/lv_imgbtn.c @@ -281,7 +281,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig src = ext->img_src_left[state]; if(src) { - lv_img_dsc_get_info(src, &header); + lv_img_decoder_get_info(src, &header); left_w = header.w; coords.x1 = imgbtn->coords.x1; coords.y1 = imgbtn->coords.y1; @@ -292,7 +292,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig src = ext->img_src_right[state]; if(src) { - lv_img_dsc_get_info(src, &header); + lv_img_decoder_get_info(src, &header); right_w = header.w; coords.x1 = imgbtn->coords.x2 - header.w + 1; coords.y1 = imgbtn->coords.y1; @@ -305,7 +305,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig if(src) { lv_coord_t obj_w = lv_obj_get_width(imgbtn); lv_coord_t i; - lv_img_dsc_get_info(src, &header); + lv_img_decoder_get_info(src, &header); coords.x1 = imgbtn->coords.x1 + left_w; coords.y1 = imgbtn->coords.y1; @@ -375,7 +375,7 @@ static void refr_img(lv_obj_t * imgbtn) #endif lv_res_t info_res; - info_res = lv_img_dsc_get_info(src, &header); + info_res = lv_img_decoder_get_info(src, &header); if(info_res == LV_RES_OK) { ext->act_cf = header.cf; #if LV_IMGBTN_TILED == 0 diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index 3d7e9dee4..6d06470a7 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -582,8 +582,8 @@ const lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type switch(type) { case LV_LIST_STYLE_BG: style = lv_page_get_style(list, LV_PAGE_STYLE_BG); break; - case LV_LIST_STYLE_SCRL: style = lv_page_get_style(list, LV_PAGE_STYLE_SB); break; - case LV_LIST_STYLE_SB: style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL); break; + case LV_LIST_STYLE_SCRL: style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL); break; + case LV_LIST_STYLE_SB: style = lv_page_get_style(list, LV_PAGE_STYLE_SB); break; case LV_LIST_STYLE_EDGE_FLASH: style = lv_page_get_style(list, LV_PAGE_STYLE_EDGE_FLASH); break; diff --git a/src/lv_objx/lv_mbox.c b/src/lv_objx/lv_mbox.c index cb9de0e2a..2a5aa026e 100644 --- a/src/lv_objx/lv_mbox.c +++ b/src/lv_objx/lv_mbox.c @@ -218,6 +218,7 @@ void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay) lv_anim_create(&a); a.start = lv_obj_get_width(mbox); + a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_width; a.ready_cb = lv_mbox_close_ready_cb; lv_anim_create(&a); diff --git a/src/lv_objx/lv_page.c b/src/lv_objx/lv_page.c index e07b04dac..361e33977 100644 --- a/src/lv_objx/lv_page.c +++ b/src/lv_objx/lv_page.c @@ -1124,15 +1124,16 @@ static void lv_page_sb_refresh(lv_obj_t * page) return; } - /*Horizontal scrollbar*/ + /*Full sized horizontal scrollbar*/ if(scrl_w <= - obj_w - style->body.padding.left - style->body.padding.right) { /*Full sized scroll bar*/ + obj_w - style->body.padding.left - style->body.padding.right) { lv_area_set_width(&ext->sb.hor_area, obj_w - 2 * sb_hor_pad); lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad, - obj_h - ext->sb.style->body.padding.inner - - ext->sb.style->body.padding.bottom); + obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.bottom); if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 0; - } else { + } + /*Smaller horizontal scrollbar*/ + else { size_tmp = (obj_w * (obj_w - (2 * sb_hor_pad))) / (scrl_w + style->body.padding.left + style->body.padding.right); if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE; @@ -1149,16 +1150,16 @@ static void lv_page_sb_refresh(lv_obj_t * page) if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 1; } - /*Vertical scrollbar*/ - if(scrl_h <= - obj_h - style->body.padding.top - style->body.padding.bottom) { /*Full sized scroll bar*/ + /*Full sized vertical scroll bar*/ + if(scrl_h <= obj_h - style->body.padding.top - style->body.padding.bottom) { lv_area_set_height(&ext->sb.ver_area, obj_h - 2 * sb_ver_pad); lv_area_set_pos(&ext->sb.ver_area, - obj_w - ext->sb.style->body.padding.inner - - ext->sb.style->body.padding.right, + obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.right, sb_ver_pad); if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.ver_draw = 0; - } else { + } + /*Smaller vertical scroll bar*/ + else { size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) / (scrl_h + style->body.padding.top + style->body.padding.bottom); if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE; @@ -1166,7 +1167,7 @@ static void lv_page_sb_refresh(lv_obj_t * page) lv_area_set_pos( &ext->sb.ver_area, - obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.bottom, + obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.right, sb_ver_pad + (-(lv_obj_get_y(scrl) - ext->sb.style->body.padding.bottom) * (obj_h - size_tmp - 2 * sb_ver_pad)) /