From eb006b3d39b55adc8a262c5a361bb28aac2fbb1a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 25 Jun 2020 12:37:46 +0200 Subject: [PATCH] finialze screen animations --- src/lv_core/lv_disp.c | 223 +++++++++++++++++++++++++++++++++-- src/lv_core/lv_disp.h | 58 ++++++++- src/lv_core/lv_obj.c | 6 +- src/lv_core/lv_refr.c | 25 +++- src/lv_draw/lv_img_decoder.c | 3 + src/lv_hal/lv_hal_disp.c | 9 ++ src/lv_hal/lv_hal_disp.h | 10 +- 7 files changed, 312 insertions(+), 22 deletions(-) diff --git a/src/lv_core/lv_disp.c b/src/lv_core/lv_disp.c index 722be31ca..d3c6321f4 100644 --- a/src/lv_core/lv_disp.c +++ b/src/lv_core/lv_disp.c @@ -8,6 +8,7 @@ *********************/ #include "lv_disp.h" #include "../lv_misc/lv_math.h" +#include "../lv_core/lv_refr.h" /********************* * DEFINES @@ -20,7 +21,12 @@ /********************** * STATIC PROTOTYPES **********************/ + +#if LV_USE_ANIMATION static void scr_load_anim_start(lv_anim_t * a); +static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v); +static void scr_anim_ready(lv_anim_t * a); +#endif /********************** * STATIC VARIABLES @@ -44,13 +50,30 @@ lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp) { if(!disp) disp = lv_disp_get_default(); if(!disp) { - LV_LOG_WARN("lv_scr_act: no display registered to get its act. screen"); + LV_LOG_WARN("no display registered to get its active screen"); return NULL; } return disp->act_scr; } +/** + * Return with a pointer to the previous screen. Only used during screen transitions. + * @param disp pointer to display which previous screen should be get. (NULL to use the default + * screen) + * @return pointer to the previous screen object or NULL if not used now + */ +lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp) +{ + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("no display registered to get its previous screen"); + return NULL; + } + + return disp->prev_scr; +} + /** * Make a screen active * @param scr pointer to a screen @@ -97,6 +120,7 @@ lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp) return disp->sys_layer; } + /** * Assign a screen to a display. * @param disp pointer to a display where to assign the screen @@ -116,21 +140,176 @@ void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr) _lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr, true); } -void lv_scr_load_anim(lv_obj_t * scr) +/** + * Set the background color of a display + * @param disp pointer to a display + * @param color color of the background + */ +void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color) { - lv_disp_t * d = lv_obj_get_disp(scr); + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("no display registered"); + return; + } + + disp->bg_color = color; + + lv_area_t a; + lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1); + _lv_inv_area(disp, &a); - lv_anim_t a; - lv_anim_init(&a); - lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_obj_set_x); - lv_anim_set_start_cb(&a, scr_load_anim_start); - lv_anim_set_time(&a, 2000); - lv_anim_set_delay(&a, 1000); - lv_anim_set_values(&a, lv_disp_get_hor_res(d), 0); - lv_anim_set_var(&a, scr); - lv_anim_start(&a); } +/** + * Set the background image of a display + * @param disp pointer to a display + * @param img_src path to file or pointer to an `lv_img_dsc_t` variable + */ +void lv_disp_set_bg_image(lv_disp_t * disp, const void * img_src) +{ + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("no display registered"); + return; + } + + disp->bg_img = img_src; + + lv_area_t a; + lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1); + _lv_inv_area(disp, &a); +} + + +/** + * Opacity of the background + * @param disp pointer to a display + * @param opa opacity (0..255) + */ +void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa) +{ + if(!disp) disp = lv_disp_get_default(); + if(!disp) { + LV_LOG_WARN("no display registered"); + return; + } + + disp->bg_opa = opa; + + lv_area_t a; + lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1); + _lv_inv_area(disp, &a); +} + +#if LV_USE_ANIMATION + +/** + * Switch screen with animation + * @param scr pointer to the new screen to load + * @param anim_type type of the animation from `lv_scr_load_anim_t`. E.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT` + * @param time time of the animation + * @param delay delay before the transition + * @param auto_del true: automatically delete the old screen + */ +void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del) +{ + lv_disp_t * d = lv_obj_get_disp(new_scr); + + if(d->prev_scr && d->del_prev) { + lv_obj_del(d->prev_scr); + d->prev_scr = NULL; + } + + d->del_prev = auto_del; + + /*Be sure there is no other animation on the screens*/ + lv_anim_del(new_scr, NULL); + lv_anim_del(lv_scr_act(), NULL); + + /*Be sure both screens are in a normal position*/ + lv_obj_set_pos(new_scr, 0, 0); + lv_obj_set_pos(lv_scr_act(), 0, 0); + lv_style_remove_prop(lv_obj_get_local_style(new_scr, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); + lv_style_remove_prop(lv_obj_get_local_style(lv_scr_act(), LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); + + lv_anim_t a_new; + lv_anim_init(&a_new); + lv_anim_set_var(&a_new, new_scr); + lv_anim_set_start_cb(&a_new, scr_load_anim_start); + lv_anim_set_ready_cb(&a_new, scr_anim_ready); + lv_anim_set_time(&a_new, time); + lv_anim_set_delay(&a_new, delay); + + lv_anim_t a_old; + lv_anim_init(&a_old); + lv_anim_set_var(&a_old, d->act_scr); + lv_anim_set_time(&a_old, time); + lv_anim_set_delay(&a_old, delay); + + switch(anim_type) { + case LV_SCR_LOAD_ANIM_NONE: + /* Create a dummy animation to apply the delay*/ + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_new, 0, 0); + break; + case LV_SCR_LOAD_ANIM_OVER_LEFT: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0); + break; + case LV_SCR_LOAD_ANIM_OVER_RIGHT: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0); + break; + case LV_SCR_LOAD_ANIM_OVER_TOP: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y); + lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0); + break; + case LV_SCR_LOAD_ANIM_OVER_BOTTOM: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y); + lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0); + break; + case LV_SCR_LOAD_ANIM_MOVE_LEFT: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0); + + lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d)); + break; + case LV_SCR_LOAD_ANIM_MOVE_RIGHT: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0); + + lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_x); + lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d)); + break; + case LV_SCR_LOAD_ANIM_MOVE_TOP: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y); + lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0); + + lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_y); + lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d)); + break; + case LV_SCR_LOAD_ANIM_MOVE_BOTTOM: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y); + lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0); + + lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_y); + lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d)); + break; + + case LV_SCR_LOAD_ANIM_FADE_ON: + lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) opa_scale_anim); + lv_anim_set_values(&a_new, LV_OPA_TRANSP, LV_OPA_COVER); + break; + } + + lv_anim_start(&a_new); + lv_anim_start(&a_old); +} + +#endif + /** * Get elapsed time since last user activity on a display (e.g. click) * @param disp pointer to an display (NULL to get the overall smallest inactivity) @@ -195,7 +374,27 @@ lv_task_t * _lv_disp_get_refr_task(lv_disp_t * disp) * STATIC FUNCTIONS **********************/ +#if LV_USE_ANIMATION static void scr_load_anim_start(lv_anim_t * a) { + lv_disp_t * d = lv_obj_get_disp(a->var); + d->prev_scr = lv_scr_act(); + lv_disp_load_scr(a->var); } + +static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v) +{ + lv_obj_set_style_local_opa_scale(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, v); +} + + +static void scr_anim_ready(lv_anim_t * a) +{ + lv_disp_t * d = lv_obj_get_disp(a->var); + + if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr); + d->prev_scr = NULL; + lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); +} +#endif diff --git a/src/lv_core/lv_disp.h b/src/lv_core/lv_disp.h index b09fc1dc6..dba2ddc37 100644 --- a/src/lv_core/lv_disp.h +++ b/src/lv_core/lv_disp.h @@ -24,6 +24,19 @@ extern "C" { * TYPEDEFS **********************/ +typedef enum { + LV_SCR_LOAD_ANIM_NONE, + LV_SCR_LOAD_ANIM_OVER_LEFT, + LV_SCR_LOAD_ANIM_OVER_RIGHT, + LV_SCR_LOAD_ANIM_OVER_TOP, + LV_SCR_LOAD_ANIM_OVER_BOTTOM, + LV_SCR_LOAD_ANIM_MOVE_LEFT, + LV_SCR_LOAD_ANIM_MOVE_RIGHT, + LV_SCR_LOAD_ANIM_MOVE_TOP, + LV_SCR_LOAD_ANIM_MOVE_BOTTOM, + LV_SCR_LOAD_ANIM_FADE_ON, +}lv_scr_load_anim_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -36,6 +49,14 @@ extern "C" { */ lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp); +/** + * Return with a pointer to the previous screen. Only used during screen transitions. + * @param disp pointer to display which previous screen should be get. (NULL to use the default + * screen) + * @return pointer to the previous screen object or NULL if not used now + */ +lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp); + /** * Make a screen active * @param scr pointer to a screen @@ -64,6 +85,41 @@ lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp); */ void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr); + +/** + * Set the background color of a display + * @param disp pointer to a display + * @param color color of the background + */ +void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color); + +/** + * Set the background image of a display + * @param disp pointer to a display + * @param img_src path to file or pointer to an `lv_img_dsc_t` variable + */ +void lv_disp_set_bg_image(lv_disp_t * disp, const void * img_src); + +/** + * Opacity of the background + * @param disp pointer to a display + * @param opa opacity (0..255) + */ +void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa); + +#if LV_USE_ANIMATION + +/** + * Switch screen with animation + * @param scr pointer to the new screen to load + * @param anim_type type of the animation from `lv_scr_load_anim_t`. E.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT` + * @param time time of the animation + * @param delay delay before the transition + * @param auto_del true: automatically delete the old screen + */ +void lv_scr_load_anim(lv_obj_t * scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del); + +#endif /** * Get elapsed time since last user activity on a display (e.g. click) * @param disp pointer to an display (NULL to get the overall smallest inactivity) @@ -123,8 +179,6 @@ static inline void lv_scr_load(lv_obj_t * scr) } -void lv_scr_load_anim(lv_obj_t * scr); - /********************** * MACROS **********************/ diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index e5fc6f1d5..dd7df33ca 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -501,10 +501,12 @@ void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area) if(lv_obj_get_hidden(obj)) return; - /*Invalidate the object only if it belongs to the 'LV_GC_ROOT(_lv_act_scr)'*/ + /*Invalidate the object only if it belongs to the curent or previous'*/ lv_obj_t * obj_scr = lv_obj_get_screen(obj); lv_disp_t * disp = lv_obj_get_disp(obj_scr); - if(obj_scr == lv_disp_get_scr_act(disp) || obj_scr == lv_disp_get_layer_top(disp) || + if(obj_scr == lv_disp_get_scr_act(disp) || + obj_scr == lv_disp_get_scr_prev(disp) || + obj_scr == lv_disp_get_layer_top(disp) || obj_scr == lv_disp_get_layer_sys(disp)) { /*Truncate the area to the object*/ diff --git a/src/lv_core/lv_refr.c b/src/lv_core/lv_refr.c index 5ba13e5fa..9644a0459 100644 --- a/src/lv_core/lv_refr.c +++ b/src/lv_core/lv_refr.c @@ -506,11 +506,28 @@ static void lv_refr_area_part(const lv_area_t * area_p) /*Draw a display background if there is no top object*/ if(top_act_scr == NULL && top_prev_scr == NULL) { - lv_draw_rect_dsc_t dsc; - lv_draw_rect_dsc_init(&dsc); - dsc.bg_color = LV_COLOR_RED; + if(disp_refr->bg_img) { + lv_draw_img_dsc_t dsc; + lv_draw_img_dsc_init(&dsc); + dsc.opa = disp_refr->bg_opa; + lv_img_header_t header; + lv_res_t res; + res = lv_img_decoder_get_info(disp_refr->bg_img, &header); + if(res == LV_RES_OK) { + lv_area_t a; + lv_area_set(&a, 0, 0, header.w - 1, header.h - 1); + lv_draw_img(&a, &start_mask, disp_refr->bg_img, &dsc); + } else { + LV_LOG_WARN("Can't draw the background image") + } + } else { + lv_draw_rect_dsc_t dsc; + lv_draw_rect_dsc_init(&dsc); + dsc.bg_color = disp_refr->bg_color; + dsc.bg_opa = disp_refr->bg_opa; + lv_draw_rect(&start_mask, &start_mask, &dsc); - lv_draw_rect(&start_mask, &start_mask, &dsc); + } } /*Refresh the previous screen if any*/ if(disp_refr->prev_scr) { diff --git a/src/lv_draw/lv_img_decoder.c b/src/lv_draw/lv_img_decoder.c index 490260870..245ab4711 100644 --- a/src/lv_draw/lv_img_decoder.c +++ b/src/lv_draw/lv_img_decoder.c @@ -89,6 +89,9 @@ void _lv_img_decoder_init(void) lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header) { header->always_zero = 0; + header->h = 0; + header->w = 0; + header->cf = LV_IMG_CF_UNKNOWN; lv_res_t res = LV_RES_INV; lv_img_decoder_t * d; diff --git a/src/lv_hal/lv_hal_disp.c b/src/lv_hal/lv_hal_disp.c index 09d9648e7..d87afb55f 100644 --- a/src/lv_hal/lv_hal_disp.c +++ b/src/lv_hal/lv_hal_disp.c @@ -144,6 +144,15 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver) disp->inv_p = 0; disp->last_activity_time = 0; + disp->bg_color = LV_COLOR_WHITE; + disp->bg_img = NULL; +#if LV_COLOR_SCREEN_TRANSP + disp->bg_opa = LV_OPA_TRANSP; +#else + disp->bg_opa = LV_OPA_COVER; +#endif + + disp->prev_scr = NULL; disp->act_scr = lv_obj_create(NULL, NULL); /*Create a default screen on the display*/ disp->top_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/ disp->sys_layer = lv_obj_create(NULL, NULL); /*Create sys layer on the display*/ diff --git a/src/lv_hal/lv_hal_disp.h b/src/lv_hal/lv_hal_disp.h index f607390b9..a3c627489 100644 --- a/src/lv_hal/lv_hal_disp.h +++ b/src/lv_hal/lv_hal_disp.h @@ -146,11 +146,17 @@ typedef struct _disp_t { /** Screens of the display*/ lv_ll_t scr_ll; - struct _lv_obj_t * act_scr; /**< Currently active screen on this display */ - struct _lv_obj_t * prev_scr; /**< Previous screen. Used during screen animations */ + struct _lv_obj_t * act_scr; /**< Currently active screen on this display */ + struct _lv_obj_t * prev_scr; /**< Previous screen. Used during screen animations */ struct _lv_obj_t * top_layer; /**< @see lv_disp_get_layer_top */ struct _lv_obj_t * sys_layer; /**< @see lv_disp_get_layer_sys */ + uint8_t del_prev :1; /**< 1: Automatically delete the previous screen when the screen load animation is ready */ + + lv_color_t bg_color; /**< Default display color when screens are transparent*/ + const void * bg_img; /**< An image source to display as wallpaper*/ + lv_opa_t bg_opa; /**