未来将会有诸多应用,这些应用将通过菜单进行有序组织和管理。因此,我们需要率先打造好菜单。
LCD 驱动通常是直接写屏的,虽然速度较快,但用于界面制作则不太适宜。所以,最好能拥有一套 UI 框架。如前所述,我们的目标是学习,故而不采用如 LVGL 之类的框架,一切都需亲力亲为。
构建一个简易的 UI 框架:

每个页面,我们称之为场景(scean),其中包含众多控件。所有页面存放在链表中,每次仅执行最后一个页面的操作。若删除页面,则会退回到前一个页面。
每个页面可以拥有多个控件。这些控件放置在一个链表中。每次仅执行最后一个控件的操作。当前掌机没有触摸功能,故暂不考虑多个控件同时接收事件。若仅有一个控件,也可不使用链表。
之前已设计好,大循环放置在主 main 函数内。每次通过 tick 方法将运行间隔传递给下面的场景(scean),再传递给下面的用户控件(usercontrol)。
好了,开始我们的实操:
菜单分为多个级别,每级都有自己的页面,同时每个应用也有自己的页面。我们将每个页面用场景(SCEAN)来表示。所有实例化的场景都存放在场景列表(sceanList)中进行管理,以便于页面的前进和后退。
一:写个scean基类,或者说是接口也行。
个人比较习惯JAVA的面向对象技术,所以编码风格带有JAVA的色彩。
IScean.h
#ifdef __cplusplus
enum SceanResult{
SceanResult_EXIT = 1,
SceanResult_Done = 2
};
class IScean {
public:
IScean();
virtual ~IScean();
// 纯虚函数
virtual SceanResult tick(u32 ticks) = 0;
virtual int scean_init(cJSON* param) {return 0;};
virtual int scean_resume(void){return 0;};
virtual int scean_pause(void){return 0;};
protected:
map_t iconMap = NULL;
unsigned char* getImageResource(char* fn);
};
#endif
scean中有几个重要的方法:初始化,暂停,恢复,执行(tick)
原则上没有使用系统中断、钩子之类的东西。而是在main函数中进行循环,处理系统级任务,每每次循环的时间消耗通过tick函数传递给当前scean。
main.cpp
void UserMain(void)
{
。。。
while(1){
handleMainScreanTask();
IScean* cur= ((IScean*)sceanList->prev->data);
_tmp_Run_Ticks = tls_os_get_time();
keyAdepterProc(_tmp_Run_Ticks - _last_Run_Ticks);
res = cur->tick(_tmp_Run_Ticks - _last_Run_Ticks);
_last_Run_Ticks = _tmp_Run_Ticks;
switch (res) {
case SceanResult_EXIT:
delete cur;
ListPopBack(sceanList);
((IScean*)sceanList->prev->data)->scean_resume();
break;
case SceanResult_Done:
break;
}
。。。
}
}
scean实现中,加入了scean图标的读取。
IScean.cpp
#include "IScean.h"
#include "../driver/psram.h"
int iterate(any_t item, any_t data){
psram_heap_free((unsigned char *)data);
return MAP_OK;
}
IScean::IScean(){
iconMap = hashmap_new();
}
IScean::~IScean(){
any_t val;
hashmap_iterate(iconMap, iterate, val);
hashmap_free(iconMap);
}
unsigned char* I

最低0.47元/天 解锁文章
742

被折叠的 条评论
为什么被折叠?



