赞
踩
适配 lvgl 8.3
/** *******************************CopyRight ************************************ * @file lv_scr_mgr.c * @author zyf * @date 2023-10-11 13:4:36 * @brief lvgl 页面管理器 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "lvgl.h" #include "lv_scr_mgr.h" typedef struct { uint32_t scr_cnt; void* param; const lv_scr_mgr_handle_t **handles; #if LV_SCR_MGR_PRINTF_MEM uint32_t *max_mem; #endif }scr_mgr_list_handle_t; static scr_mgr_list_handle_t mgr_list; static lv_scr_mgr_stack_node_t* mgr_stack_top = NULL; static lv_scr_mgr_stack_node_t* mgr_stack_root = NULL; static const lv_scr_mgr_handle_t* find_handle_by_id(uint32_t id) { for (int i = 0; i < mgr_list.scr_cnt; i++) { if (mgr_list.handles[i]->scr_id == id) { return mgr_list.handles[i]; } } return NULL; } #if LV_SCR_MGR_PRINTF_MEM static uint32_t* find_mem_addr_by_id(uint32_t id) { for (int i = 0; i < mgr_list.scr_cnt; i++) { if (mgr_list.handles[i]->scr_id == id) { return &mgr_list.max_mem[i]; } } return NULL; } static void mem_max_printf(uint32_t id) { static uint32_t mem_max = 0; lv_mem_monitor_t mon; lv_mem_monitor(&mon); if (mon.total_size - mon.free_size > mem_max) { mem_max = mon.total_size - mon.free_size; LV_LOG_USER("used: %d (%d %%), frag: %d %%, biggest free: %d\n", mem_max, mon.used_pct, mon.frag_pct, (int)mon.free_biggest_size); } } static void page_mem_max_printf(uint32_t id) { lv_mem_monitor_t mon; lv_mem_monitor(&mon); /* 当前界面最大使用内存 */ uint32_t* page_max_mem = find_mem_addr_by_id(id); if (mon.total_size - mon.free_size > *page_max_mem) { *page_max_mem = mon.total_size - mon.free_size; LV_LOG_USER("page id %d, used: %d (%d %%), frag: %d %%, biggest free: %d\n", id, *page_max_mem, mon.used_pct, mon.frag_pct, (int)mon.free_biggest_size); } } static void anim_mem_max_printf(lv_event_t* e) { lv_event_code_t event_code = lv_event_get_code(e); if (event_code == LV_EVENT_SCREEN_LOADED) { page_mem_max_printf((uint32_t)lv_event_get_user_data(e)); } } #endif static void scr_mgr_stack_free(void) { lv_scr_mgr_stack_node_t* stack_node = NULL; /* 释放界面栈 */ while (NULL != mgr_stack_top) { stack_node = mgr_stack_top->prev; if(mgr_stack_top->handle->scr_destroy) mgr_stack_top->handle->scr_destroy(); lv_mem_free((void*)mgr_stack_top); mgr_stack_top = stack_node; } mgr_stack_root = NULL; } /** * @brief 入栈 * @param tag 要入栈的句柄 * @return 栈顶句柄 */ static lv_scr_mgr_stack_node_t* scr_mgr_stack_push(const lv_scr_mgr_handle_t* tag) { lv_scr_mgr_stack_node_t* stack_node = NULL; stack_node = lv_mem_alloc(sizeof(lv_scr_mgr_stack_node_t)); LV_ASSERT_MALLOC(stack_node); stack_node->handle = tag; stack_node->next = NULL; if (stack_node->handle->scr_first_create) { stack_node->handle->scr_first_create(); } if (tag->scr_create) { stack_node->scr = tag->scr_create(stack_node->handle->scr_id, mgr_list.param); } else { LV_LOG_ERROR("no create fun!"); } if (NULL == mgr_stack_top) { stack_node->prev = NULL; mgr_stack_root = stack_node; } else { stack_node->prev = mgr_stack_top; mgr_stack_top->next = stack_node; } mgr_stack_top = stack_node; return stack_node; } static int32_t scr_mgr_stack_pop(int32_t n) { lv_scr_mgr_stack_node_t* stack_node = NULL; int32_t i = n; if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev)) { return 0; } while (i) { if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev)) { break; } stack_node = mgr_stack_top->prev; if (mgr_stack_top->handle->scr_destroy) { mgr_stack_top->handle->scr_destroy(); } lv_mem_free((void*)mgr_stack_top); mgr_stack_top = stack_node; i--; } if (NULL != mgr_stack_top->handle->scr_create) { mgr_stack_top->scr = mgr_stack_top->handle->scr_create(mgr_stack_top->handle->scr_id, mgr_list.param); } else { LV_LOG_ERROR("no create fun!"); } if (i) { LV_LOG_WARN("stack pop %d, but stack is %d", n, n-i); } return n - i; } /** * @brief 切换界面 * @param cur_scr 当前界面 * @param stack_node 目标界面句柄 * @param anim 切换界面动画开关 * 关闭界面切换动画,切换界面时会先创建一个新的空界面,切换到空界面后, * 删除之前的界面,然后再创建切换到新界面,最后再删除中间界面。会节省内存。 * 关闭界面切换动画,切换界面时直接创建新界面,然后再用动画切换到新界面。 * * @return true */ bool scr_mgr_switch(lv_obj_t* cur_scr, lv_scr_mgr_stack_node_t* stack_node, bool anim) { lv_scr_load_anim_t load_anim = LV_SCR_MGR_LOAD_ANIM_DEFAULT; lv_obj_t* tmp_scr = NULL; if (anim) { if ((stack_node->handle->anim_type != LV_SCR_LOAD_ANIM_NONE) && (LV_SCR_LOAD_ANIM_OUT_BOTTOM >= stack_node->handle->anim_type)) { load_anim = stack_node->handle->anim_type; } #if LV_SCR_MGR_PRINTF_MEM mem_max_printf(stack_node->handle->scr_id); lv_obj_add_event_cb(stack_node->scr, anim_mem_max_printf, LV_EVENT_SCREEN_LOADED, (void*)stack_node->handle->scr_id); #endif lv_scr_load_anim(stack_node->scr, load_anim, LV_SCR_MGR_LOAD_ANIM_TIME, LV_SCR_MGR_LOAD_ANIM_DELAY, true); } else { if (NULL != cur_scr) { tmp_scr = lv_obj_create(NULL); lv_scr_load(tmp_scr); lv_obj_del(cur_scr); cur_scr = NULL; } lv_scr_load(stack_node->scr); #if LV_SCR_MGR_PRINTF_MEM mem_max_printf(stack_node->handle->scr_id); page_mem_max_printf(stack_node->handle->scr_id); #endif if (NULL != tmp_scr) { lv_obj_del(tmp_scr); } } return true; } /** * @brief 初始化界面管理器 * @param param 创建界面时的参数 * @return */ bool lv_scr_mgr_init(void* param) { mgr_list.param = param; #if LV_SCR_MGR_REG_ENABLE extern const lv_scr_mgr_handle_t* scr_mgr_scr_mgr_start; extern const lv_scr_mgr_handle_t* scr_mgr_scr_mgr_end; const lv_scr_mgr_handle_t** item = &scr_mgr_scr_mgr_start; item++; mgr_list.handles = item; mgr_list.scr_cnt = 0; for(;item < &scr_mgr_scr_mgr_end; item++) { mgr_list.scr_cnt++; } #else mgr_list.scr_cnt = lv_scr_mgr_get_cnt(); mgr_list.handles = lv_scr_mgr_get_handles(); #endif if (0 == mgr_list.scr_cnt) { LV_LOG_ERROR("no screen!"); return false; } #if LV_SCR_MGR_PRINTF_MEM mgr_list.max_mem = lv_mem_alloc(mgr_list.scr_cnt * sizeof(uint32_t*)); LV_ASSERT(mgr_list.max_mem); memset(mgr_list.max_mem, 0, mgr_list.scr_cnt * sizeof(uint32_t*)); #endif return true; } void lv_scr_mgr_deinit(void) { mgr_list.param = NULL; #if LV_SCR_MGR_PRINTF_MEM lv_mem_free(mgr_list.max_mem); #endif scr_mgr_stack_free(); } void lv_scr_mgr_param_set(void* param) { mgr_list.param = param; } void* lv_scr_mgr_param_get(void) { return mgr_list.param; } /** * @brief 设置根界面 * @param id 根界面序号 * @param anim 动画开关 * @return */ bool lv_scr_mgr_switch(uint32_t id, bool anim) { const lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id); const lv_scr_mgr_handle_t* cur_handle = NULL; lv_scr_mgr_stack_node_t* stack_node = NULL; lv_obj_t* cur_scr = NULL; if (NULL == tag_handle) { LV_LOG_ERROR("no screen, id %d", id); return false; } if (NULL != mgr_stack_top) { /* 栈内有界面 */ cur_handle = mgr_stack_top->handle; cur_scr = mgr_stack_top->scr; } else { cur_scr = lv_scr_act(); } scr_mgr_stack_free(); if ((NULL == cur_handle) || (tag_handle->scr_id == cur_handle->scr_id)) { /* 没有界面切换,不使用动画效果 */ anim = false; } stack_node = scr_mgr_stack_push(tag_handle); return scr_mgr_switch(cur_scr, stack_node, anim); } /** * @brief 入栈一个新的界面 * @param id * @param anim * @return */ bool lv_scr_mgr_push(uint32_t id, bool anim) { const lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id); lv_scr_mgr_stack_node_t* stack_node = NULL; lv_obj_t* cur_scr = NULL; if (NULL == tag_handle) { LV_LOG_ERROR("no screen, id %d", id); return false; } if ((NULL == mgr_stack_top) || (NULL == mgr_stack_root)) { LV_LOG_ERROR("no root screen, please use lv_scr_mgr_switch create root screen"); return false; } cur_scr = mgr_stack_top->scr; stack_node = scr_mgr_stack_push(tag_handle); return scr_mgr_switch(cur_scr, stack_node, anim); } /** * @brief 出栈n个界面 * @param n 如果栈内界面没有n个,则返回根界面 * @param anim * @return */ bool lv_scr_mgr_popn(uint32_t n, bool anim) { lv_obj_t* cur_scr = NULL; if ((mgr_stack_top == NULL) || (mgr_stack_top->prev == NULL)) { return false; } cur_scr = mgr_stack_top->scr; scr_mgr_stack_pop(n); return scr_mgr_switch(cur_scr, mgr_stack_top, anim); } /** * @brief 出栈一个界面 * @param anim * @return */ bool lv_scr_mgr_pop(bool anim) { return lv_scr_mgr_popn(1, anim); } /** * @brief 退回到根界面 * @param anim * @return */ bool lv_scr_mgr_pop_root(bool anim) { lv_scr_mgr_stack_node_t* stack_node = NULL; lv_scr_mgr_stack_node_t* stack_top = NULL; uint32_t cnt = 0; if (NULL == mgr_stack_root || NULL == mgr_stack_top) { return false; } stack_top = mgr_stack_top; while (stack_top != NULL) { cnt++; stack_node = stack_top->prev; stack_top = stack_node; } return lv_scr_mgr_popn(cnt-1, anim); } /** * @brief 获取当前界面id * @param * @return */ int32_t lv_scr_mgr_get_cur_id(void) { if (NULL != mgr_stack_top && NULL != mgr_stack_top->handle) { return mgr_stack_top->handle->scr_id; } else { return -1; } } /** * @brief 获取根界面id * @param * @return */ int32_t lv_scr_mgr_get_root_id(void) { if (NULL != mgr_stack_root && NULL != mgr_stack_root->handle) { return mgr_stack_root->handle->scr_id; } else { return -1; } } /************************ (C) COPYRIGHT ***********END OF FILE*****************/
/** *******************************CopyRight ************************************ * @file lv_scr_mgr.h * @author zyf * @date 2023-10-11 9:31:49 * @brief lvgl 页面管理器 * ****************************************************************************** */ #ifndef _LV_SCR_MGR_H_ #define _LV_SCR_MGR_H_ /* Includes ------------------------------------------------------------------*/ #include "stdint.h" #include "lvgl.h" #ifdef __cplusplus extern "C" { #endif /*!< 界面切换动画默认值 */ #define LV_SCR_MGR_LOAD_ANIM_DEFAULT LV_SCR_LOAD_ANIM_MOVE_LEFT #define LV_SCR_MGR_LOAD_ANIM_TIME 500 #define LV_SCR_MGR_LOAD_ANIM_DELAY 0 /*!< 内存泄漏检测 注意,页面管理器的push操作也会申请动态内存 * 如果使用动画,则需要将 lv_disp.c 中的 scr_anim_ready 改为如下 static void scr_anim_ready(lv_anim_t * a) { lv_disp_t * d = lv_obj_get_disp(a->var); lv_event_send(d->prev_scr, LV_EVENT_SCREEN_UNLOADED, NULL); if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr); d->prev_scr = NULL; d->draw_prev_over_act = false; d->scr_to_load = NULL; lv_event_send(d->act_scr, LV_EVENT_SCREEN_LOADED, NULL); lv_obj_remove_local_style_prop(a->var, LV_STYLE_OPA, 0); lv_obj_invalidate(d->act_scr); } */ #define LV_SCR_MGR_PRINTF_MEM 1 /* 使用分散加载的方式 将 lv_scr_mgr_handle_t 存放在特定段, * 用户创建 lv_scr_mgr_handle_t 后可以在后面直接 使用 LV_SCR_MGR_REG() 对界面句柄进行注册 * 而不用将 界面句柄 添加到 lv_scr_mgr_port.c 数组中 */ #define LV_SCR_MGR_REG_ENABLE 0 typedef struct { uint32_t scr_id; /*!< id */ lv_scr_load_anim_t anim_type; /*!< 切换动画类型 如果为空,则使用 LV_SCR_MGR_LOAD_ANIM_DEFAULT */ void (*scr_first_create)(void); /*!< lv_scr_mgr_switch lv_scr_mgr_push 函数会调用该创建函数 pop则不会调用 可以方便实现pop记住焦点 而push使用默认焦点 */ lv_obj_t* (*scr_create) (const uint32_t id, void* param); /*!< 创建界面,创建界面时不要使用 lv_scr_mgr_xxx 函数 */ void (*scr_destroy)(void); /*!< 删除界面的回调函数,一般用于删除如 lv_timer 等不会随界面自动删除的资源 */ }lv_scr_mgr_handle_t; typedef struct _lv_scr_mgr_stack_node_t { const lv_scr_mgr_handle_t* handle; lv_obj_t* scr; struct _lv_scr_mgr_stack_node_t* prev; struct _lv_scr_mgr_stack_node_t* next; }lv_scr_mgr_stack_node_t; #include "lv_scr_mgr_port.h" #if LV_SCR_MGR_REG_ENABLE #define ANONY_CONN(type, var) type var #define ANONY_DEF(type,prefix) ANONY_CONN(type, prefix) #define ANONY_TYPE(type,prefix) ANONY_DEF(type, prefix) #if defined(__CC_ARM) || defined(__GNUC__) /* ARM,GCC*/ #define SECTION(x) __attribute__((section(x))) #define USED __attribute__((used)) #elif defined (__ICCARM__) /*IAR */ #define SECTION(x) @ x #define USED __root #else #error "Current tool chain haven't supported yet!" #endif #define _LV_SCR_MGR_REG(handle, level) \ USED ANONY_TYPE(const lv_scr_mgr_handle_t*, scr_mgr_##handle)\ SECTION("scr_mgr."level) = &(handle) #define LV_SCR_MGR_REG(handle) _LV_SCR_MGR_REG(handle, "1") #else #define LV_SCR_MGR_REG(handle) #endif bool lv_scr_mgr_init(void* param); void lv_scr_mgr_deinit(void); void lv_scr_mgr_param_set(void* param); void* lv_scr_mgr_param_get(void); bool lv_scr_mgr_switch(uint32_t id, bool anim); bool lv_scr_mgr_push(uint32_t id, bool anim); bool lv_scr_mgr_popn(uint32_t n, bool anim); bool lv_scr_mgr_pop(bool anim); bool lv_scr_mgr_pop_root(bool anim); int32_t lv_scr_mgr_get_cur_id(void); int32_t lv_scr_mgr_get_root_id(void); #ifdef __cplusplus } #endif #endif /* _LV_SCR_MGR_H_ */ /************************ (C) COPYRIGHT *****END OF FILE*****************/
/** *******************************CopyRight ************************************ * @file lv_scr_mgr_port.c * @author zyf * @date 2023-10-11 13:51:24 * @brief lvgl 页面管理器 接口 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "lv_scr_mgr.h" #include "lv_scr_mgr_port.h" #if LV_SCR_MGR_REG_ENABLE /* 无需用户修改 */ const lv_scr_mgr_handle_t scr_mgr_start = {0}; _LV_SCR_MGR_REG(scr_mgr_start, "0"); const lv_scr_mgr_handle_t scr_mgr_end = {0}; _LV_SCR_MGR_REG(scr_mgr_end, "2"); #else /* 需要用户添加自己的界面句柄 */ extern const lv_scr_mgr_handle_t s_scr_mgr_handle_test1; extern const lv_scr_mgr_handle_t s_scr_mgr_handle_test2; extern const lv_scr_mgr_handle_t s_scr_mgr_handle_test3; static const lv_scr_mgr_handle_t* scr_mgr_handles[] = { & s_scr_mgr_handle_test1, & s_scr_mgr_handle_test2, & s_scr_mgr_handle_test3, }; uint32_t lv_scr_mgr_get_cnt(void) { return sizeof(scr_mgr_handles) / sizeof(scr_mgr_handles[0]); } const lv_scr_mgr_handle_t** lv_scr_mgr_get_handles(void) { return scr_mgr_handles; } #endif /************************ (C) COPYRIGHT ***********END OF FILE*****************/
/** *******************************CopyRight ************************************ * @file lv_scr_mgr_port.h * @author zyf * @date 2023-10-11 13:51:23 * @brief lvgl 页面管理器 接口 * ****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef _LV_SCR_MGR_PORT_H_ #define _LV_SCR_MGR_PORT_H_ /* Includes ------------------------------------------------------------------*/ #include "lvgl.h" #ifdef __cplusplus extern "C" { #endif typedef enum { eScreenUITest1 = 0, eScreenUITest2, eScreenUITest3 }lv_scr_mgr_id_e; #if !LV_SCR_MGR_REG_ENABLE uint32_t lv_scr_mgr_get_cnt(void); const lv_scr_mgr_handle_t** lv_scr_mgr_get_handles(void); #endif #ifdef __cplusplus } #endif #endif /* _LV_SCR_MGR_PORT_H_ */ /************************ (C) COPYRIGHT ***********END OF FILE*****************/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。