/** * 日期: 2025-04-02 * 作者: coffee * 描述: ui页面管理, 独立模块, 用于管理页面切换和跳转 */ #ifndef __H_UI_PAGE_MANAGE_H__ #define __H_UI_PAGE_MANAGE_H__ #include #ifndef __COUNT_ARGS_IMPL #define __COUNT_ARGS_IMPL(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N #endif #ifndef __COUNT_ARGS #define __COUNT_ARGS(...) __COUNT_ARGS_IMPL(dummy, ##__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #endif // 注册页面函数辅助宏 #define UIPAGE_FUNC(func) uint8_t func##PageCall(uint16_t cmd, void *data, uint16_t len) #define UIPAGE_DATA data #define UIPAGE_LEN len #define UIPAGE_CMD cmd // 对应事件的data转换具体类型宏 #define UI_CALL_INDEX_TYPE(value) ((enum eUIPage *)value) // hide -> free -> update Page -> init -> show // 或者非返回时如下, 此时的hide和index事件都可存储该页面索引: // hide -> index -> free -> update Page -> init -> show enum eCallCmd { kCallInitPage, ///< 构建页面, 对应页面自己内部创建数据(非释放页面不调用, 但如未构建则会触发) kCallFreePage, ///< 释放页面, 对应页面自己内部释放数据(非释放页面不调用) kCallShowPage, ///< 显示页面 kCallHidePage, ///< 退出页面, 此事件如果是返回触发的可以存储索引数据 kCallSwitchPage, ///< 切换页面, 对应页面返回false时则不切换, 所有切换都会触发这个事件 kCallIndexSave, ///< 存储当前索引事件, 通知此事件说明当前不是返回事件(cmd, enum eUIPage *nextPage, 1); }; // 每个页面占用一个枚举, 根据枚举切换页面, kUIPageMax最大页面值, 要求格式统一 kUIPage + 页面名 enum eUIPage { kUIPageMax, ///< ui最大个数, 不超过254个页面, 如超过则需要修改字节栈类型 }; ///< cmd命令, data数据, len数据长度 typedef uint8_t (*pageCallType_t)(uint16_t cmd, void *data, uint16_t len); typedef void (*initPageType_t)(pageCallType_t *call); // 初始化页面管理, 当为NULL时内部初始化, 否则回调初始化, 请需要先设置好主页, 初始化会默认显示主页 void HUIPageInit(initPageType_t initPage); // 设置主页, 切换到主页清空返回栈, 如果返回栈为空时, 当前页面不是主页, 则切换到主页 void HUIPageSetHome(enum eUIPage page); // 切换页面, 当前页面入栈, 相同页面不操作, 需要检查栈, 栈存在就回栈清空之后的, 不存在就压栈 // 因为有些页面可能不用HUIPageBack来返回, 所以需要兼容这种情况 void HUIPageSwitch(enum eUIPage page); // 返回上一个页面 void HUIPageBack(); // 清空返回栈 void HUIPageClear(); /** * @brief * 添加关联页面到返回栈, 用于一些按键跳转到指定页面, 或者一些不想逐个进入, 而是直接跳转, 然后返回时逐个返回的功能使用 * 如正常是 主页->菜单->该页面, 但快捷跳转是主页->该页面, 需要将菜单页面添加到返回栈 * 则需要调用 清空返回栈, 然后添加 主页->菜单, 最后再切换到该页面(内部会判断首个页面是否存在返回栈, 自动清空首个页面前的返回栈) * HUIPageClear(); HUIPageAddStack(主页, 菜单, 该页面); // 栈2个, 显示该页面 * 注: 调用这个时, 当前页面将不会入栈, 最大参数长度9个 * 如: 当前页面是菜单, 设置 主页->菜单, 则菜单页面不会入栈 * 因此, 此方法用于绝对顺序跳转 */ void _HUIPageAddStack(int len, ...); #define HUIPageAddStack(...) _HUIPageAddStack(__COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__) // 当前自身页面不释放内存, 用于某些暂不想释放页面, 等返回后再考虑释放 void HUIPageSetCurrNotFree(); // 恢复当前页面默认释放内存 void HUIPageResetCurrFree(); // 获取当前页面是否不释放 uint8_t HUIPageGetCurrNotFree(); // 设置指定页面不释放内存 void HUIPageSetNotFree(enum eUIPage page); // 恢复指定页面默认释放内存 void HUIPageResetFree(enum eUIPage page); // 获取指定页面是否不释放, 是返回1, 否则返回0 uint8_t HUIPageGetNotFree(enum eUIPage page); // 设置用户数据, 在 kCallShowPage 和 kCallHidePage 都可调用, 但每次切换这些事件后都会重置数据为0 void HUIPageSetUserData(long userData); // 获取用户数据 long HUIPageGetUserData(); // 保存当前页面索引, 仅在 kCallHidePage 和 kCallIndexSave 有效, 成功返回1, 否则返回0 uint8_t HUIPageSaveIndex(uint8_t value); // 获取当前页面索引, 仅在 HUIPageIsBack() 返回1时有效, 否则返回0 uint8_t HUIPageGetIndex(); // 获取当前页面 enum eUIPage HUIPageGetCurrPage(); // 获取上一个页面 enum eUIPage HUIPageGetPrevPage(); // 获取返回栈使用长度 uint8_t HUIPageGetStackLen(); // 获取索引栈使用长度 uint8_t HUIPageGetIndexStackLen(); // 检查当前是否是返回 uint8_t HUIPageIsBack(); // 检查该页面是否在返回栈, 是返回1, 否则返回0 uint8_t HUIPageFindStack(enum eUIPage page); #endif //__H_UI_PAGE_MANAGE_H__