增加了 APPinfo 页面的基础显示功能
This commit is contained in:
@@ -37,6 +37,10 @@ add_executable(DTU-HMI
|
||||
src/Drv/pages/menu/model.c
|
||||
src/Drv/pages/menu/presenter.c
|
||||
src/Drv/pages/menu/view.c
|
||||
src/Drv/pages/AppInfo/page.c
|
||||
src/Drv/pages/AppInfo/model.c
|
||||
src/Drv/pages/AppInfo/presenter.c
|
||||
src/Drv/pages/AppInfo/view.c
|
||||
src/Drv/lcd/lcd.c
|
||||
src/Drv/lcd/lcd_draw.c
|
||||
src/Drv/lcd/lcd_text.c
|
||||
|
||||
59
README.md
59
README.md
@@ -12,6 +12,31 @@
|
||||
- 基于 CTest 的单元测试体系,已覆盖菜单、页面管理、按键、LCD、TCP 回环等模块
|
||||
|
||||
---
|
||||
```txt
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 应用层 (main.c) │
|
||||
│ 系统初始化 / 主循环调度 / 生命周期管理 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 多页面管理层 │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ Page Manager (栈式调度) │ Global Model (跨页面共享) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ MVP 业务层 │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Menu Page │ │ AppInfoPage │ │ YC Page │ │
|
||||
│ │ Model/ │ │ Model/ │ │ Model/ │ │
|
||||
│ │ Presenter/ │ │ Presenter/ │ │ Presenter/ │ │
|
||||
│ │ View │ │ View │ │ View │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 驱动抽象层 │
|
||||
│ LCD 驱动 │ 按键驱动 │ 布局计算 │ 渲染端口 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 底层基础设施 │
|
||||
│ TCP/Socket 封装 │ 线程工具 │ UTF-8 处理 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
@@ -70,38 +95,38 @@ ctest --test-dir build -C Debug --output-on-failure
|
||||
DTU-HMI/
|
||||
├── CMakeLists.txt
|
||||
├── README.md
|
||||
├── include/
|
||||
│ └── types.h
|
||||
├── include/ # 公共头文件
|
||||
│ └── types.h # 类型定义
|
||||
├── src/
|
||||
│ ├── main.c
|
||||
│ ├── main.c # ⭐ 应用入口,主循环调度
|
||||
│ ├── common/
|
||||
│ │ └── utf8.c/h
|
||||
│ ├── remoteDisplay.c/h
|
||||
│ ├── thread_utils.c/h
|
||||
│ ├── TCP/
|
||||
│ │ └── tcp.c/h
|
||||
│ └── Drv/
|
||||
│ ├── key.c/h
|
||||
│ └── Drv/ # 📦 驱动层
|
||||
│ ├── key.c/h # 按键输入抽象
|
||||
│ ├── menu/app/
|
||||
│ │ └── menu.c/h
|
||||
│ ├── lcd/
|
||||
│ │ ├── ascii.c/h
|
||||
│ ├── lcd/ # LCD 显示驱动
|
||||
│ │ ├── ascii.c/h # ASCII 字库
|
||||
│ │ ├── lcd.c/h
|
||||
│ │ ├── lcd_draw.c/h
|
||||
│ │ └── lcd_text.c/h
|
||||
│ └── pages/
|
||||
│ ├── page.h
|
||||
│ ├── page_manager.c/h
|
||||
│ ├── global/
|
||||
│ │ ├── global_state.c/h
|
||||
│ │ └── renderer_lcd.c/h
|
||||
│ └── menu/
|
||||
│ └── pages/ # ⭐ 新版多页面系统根目录
|
||||
│ ├── page.h # 标准页面抽象定义
|
||||
│ ├── page_manager.c/h # 页面栈调度器
|
||||
│ ├── global/ # 🌍 全局状态管理
|
||||
│ │ ├── global_state.c/h # 跨页面共享数据
|
||||
│ │ └── renderer_lcd.c/h # LCD 渲染 HAL 接口
|
||||
│ └── menu/ # 📋 Menu 页面的 MVP 实现
|
||||
│ ├── def.h
|
||||
│ ├── model.c/h
|
||||
│ ├── presenter.c/h
|
||||
│ ├── view.c/h
|
||||
│ └── page.c/h
|
||||
└── tests/
|
||||
│ ├── view.c/h # 菜单渲染绘制
|
||||
│ └── page.c/h # 页面生命周期注册
|
||||
└── tests/ # 🧪 测试目录
|
||||
├── CMakeLists.txt
|
||||
├── test_p0_remote_display.c
|
||||
├── test_p0_utf8_hz12_get.c
|
||||
|
||||
1221
docs/系统架构设计文档.md
1221
docs/系统架构设计文档.md
File diff suppressed because it is too large
Load Diff
@@ -1,506 +0,0 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.6.6 Chrome/144.0.7559.236 Electron/40.8.4 Safari/537.36" version="29.6.6" pages="8">
|
||||
<diagram name="显示指定层级菜单项流程" id="etDREPkzm4HehLh3Wzss">
|
||||
<mxGraphModel dx="752" dy="817" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="Dq_V7AeBsTtqcCJDGkD4-1" parent="1" style="swimlane;childLayout=stackLayout;horizontal=1;fillColor=none;horizontalStack=1;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=0;strokeColor=none;stackBorder=10;stackSpacing=-12;resizable=1;align=center;points=[];whiteSpace=wrap;html=1;" value="显示指定层级菜单项" vertex="1">
|
||||
<mxGeometry height="100" width="610" x="100" y="560" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Dq_V7AeBsTtqcCJDGkD4-2" parent="Dq_V7AeBsTtqcCJDGkD4-1" style="shape=step;perimeter=stepPerimeter;fixedSize=1;points=[];whiteSpace=wrap;html=1;" value="绘制该层级边框" vertex="1">
|
||||
<mxGeometry height="57" width="160" x="10" y="33" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Dq_V7AeBsTtqcCJDGkD4-3" parent="Dq_V7AeBsTtqcCJDGkD4-1" style="shape=step;perimeter=stepPerimeter;fixedSize=1;points=[];whiteSpace=wrap;html=1;" value="获取该层级选中菜单项" vertex="1">
|
||||
<mxGeometry height="57" width="182" x="158" y="33" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Dq_V7AeBsTtqcCJDGkD4-4" parent="Dq_V7AeBsTtqcCJDGkD4-1" style="shape=step;perimeter=stepPerimeter;fixedSize=1;points=[];whiteSpace=wrap;html=1;" value="绘制该层级下菜单项" vertex="1">
|
||||
<mxGeometry height="57" width="162" x="328" y="33" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Dq_V7AeBsTtqcCJDGkD4-5" parent="Dq_V7AeBsTtqcCJDGkD4-1" style="shape=step;perimeter=stepPerimeter;fixedSize=1;points=[];whiteSpace=wrap;html=1;" value="反显选中项" vertex="1">
|
||||
<mxGeometry height="57" width="122" x="478" y="33" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="39Z0d1SsfJPrEY7NQ2dw" name="MVP 事件处理流程">
|
||||
<mxGraphModel dx="1090" dy="1185" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-1" edge="1" parent="1" source="CHJpIxpMOG3BUcIp9TBN-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="CHJpIxpMOG3BUcIp9TBN-3" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-2" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<span style="text-wrap-mode: nowrap;">外部事件</span>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="354" y="490" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-3" parent="1" style="whiteSpace=wrap;html=1;rounded=0;" value="Presenter 协同层" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="354" y="570" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-4" parent="1" style="whiteSpace=wrap;html=1;rounded=0;" value="View 视图层" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="284" y="680" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-5" parent="1" style="whiteSpace=wrap;html=1;rounded=0;" value="Model 模型层&nbsp;" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="424" y="680" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-6" edge="1" parent="1" source="CHJpIxpMOG3BUcIp9TBN-5" style="endArrow=classic;html=1;rounded=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;edgeStyle=orthogonalEdgeStyle;jumpStyle=arc;startArrow=classic;startFill=1;" target="CHJpIxpMOG3BUcIp9TBN-3" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="594" y="630" as="sourcePoint" />
|
||||
<mxPoint x="644" y="580" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="CHJpIxpMOG3BUcIp9TBN-7" edge="1" parent="1" source="CHJpIxpMOG3BUcIp9TBN-3" style="endArrow=classic;html=1;rounded=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;edgeStyle=orthogonalEdgeStyle;" target="CHJpIxpMOG3BUcIp9TBN-4" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="374" y="670" as="sourcePoint" />
|
||||
<mxPoint x="484" y="660" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="X0IBgYVqs8-xy_G4TQXO" name="MVP 架构示意图">
|
||||
<mxGraphModel dx="1090" dy="1185" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-14" connectable="0" parent="1" style="group" value="" vertex="1">
|
||||
<mxGeometry height="300" width="600" x="100" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-1" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<font style="font-size: 21px;"><b>MVP 架构示意图</b></font>" vertex="1">
|
||||
<mxGeometry height="50" width="600" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-2" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="180" y="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-3" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="185" x="207.5" y="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-4" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="185" x="415" y="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-5" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<font style="font-size: 16px;"><b>View (视图层)</b></font>" vertex="1">
|
||||
<mxGeometry height="40" width="160" x="10" y="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-6" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<b style="font-size: 16px;">Presenter (协调层)</b>" vertex="1">
|
||||
<mxGeometry height="40" width="160" x="220" y="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-7" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<b style="font-size: 16px;">Model (数据层)</b>" vertex="1">
|
||||
<mxGeometry height="40" width="160" x="430" y="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-8" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<span style="font-size: 16px;"><b>负责显示内容</b></span>" vertex="1">
|
||||
<mxGeometry height="40" width="160" x="10" y="250" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-9" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<font style="font-size: 16px;"><b>负责流程协调</b></font>" vertex="1">
|
||||
<mxGeometry height="40" width="160" x="220" y="250" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-10" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="rounded=1;whiteSpace=wrap;html=1;" value="<font style="font-size: 16px;"><b>负责数据和规则</b></font>" vertex="1">
|
||||
<mxGeometry height="40" width="160" x="430" y="250" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-11" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="<b><font style="font-size: 14px;">LCD 显示</font></b><div><b><font style="font-size: 14px;">LED 指示</font></b></div><div><b><font style="font-size: 14px;">按键输入</font></b></div>" vertex="1">
|
||||
<mxGeometry height="60" width="80" x="20" y="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-12" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="<b><font style="font-size: 14px;">接收外部事件</font></b><div><b><font style="font-size: 14px;">调用 Model 处理</font></b></div><div><span style="font-size: 14px;"><b>更新 View 状态</b></span></div>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="230" y="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wkRVSMCZ4WoaQlwrK3vp-13" parent="wkRVSMCZ4WoaQlwrK3vp-14" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="<span style="font-size: 14px;"><b>菜单逻辑计算</b></span><br><div><b><font style="font-size: 14px;">参数边界检查</font></b></div><div><span style="font-size: 14px;"><b>传感器数据获取</b></span></div><div><span style="font-size: 14px;"><b>数据存储读写</b></span></div>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="440" y="150" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="HxDEZlLnL0qG7Ur4KydZ" name="页面管理器架构设计">
|
||||
<mxGraphModel dx="1363" dy="1481" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="LuWILqjna9OgU5SQR-9t-1" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<font style="font-size: 29px;">页面管理器(<span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">Page Manager</span>)</font><div><span style="font-size: 29px;"><br></span></div><div><span style="font-size: 29px;"><br></span><div><font style="font-size: 29px;"><br></font></div><div><font style="font-size: 29px;"><br></font></div></div>" vertex="1">
|
||||
<mxGeometry height="240" width="500" x="130" y="290" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="LuWILqjna9OgU5SQR-9t-2" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<div><div><font style="font-size: 29px;">页面栈 (Page Stack)</font></div></div><div><font style="font-size: 29px;"><br></font></div><div><font style="font-size: 29px;"><br></font></div>" vertex="1">
|
||||
<mxGeometry height="130" width="500" x="130" y="400" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="LuWILqjna9OgU5SQR-9t-3" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<span style="font-size: 23px;">栈顶页面</span>" vertex="1">
|
||||
<mxGeometry height="60" width="240" x="140" y="460" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="LuWILqjna9OgU5SQR-9t-4" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<span style="font-size: 23px;">后台页面1</span>" vertex="1">
|
||||
<mxGeometry height="60" width="240" x="380" y="460" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="R1sptnBL6Yvgqzv1JQT0" name="菜单页面架构设计">
|
||||
<mxGraphModel dx="1090" dy="1185" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="_v9aWsQiSdQDmT4Fcf7S-1" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<font style="font-size: 29px;">菜单页面</font><div><font style="font-size: 29px;"><br></font></div><div><font style="font-size: 29px;"><br></font></div>" vertex="1">
|
||||
<mxGeometry height="130" width="500" x="164" y="480" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_v9aWsQiSdQDmT4Fcf7S-2" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<font style="font-size: 23px;">page</font>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="174" y="540" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_v9aWsQiSdQDmT4Fcf7S-3" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<span style="font-size: 23px;">model</span>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="294" y="540" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_v9aWsQiSdQDmT4Fcf7S-4" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<span style="font-size: 23px;">view</span>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="414" y="540" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_v9aWsQiSdQDmT4Fcf7S-5" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="<span style="font-size: 23px;">presenter</span>" vertex="1">
|
||||
<mxGeometry height="60" width="120" x="534" y="540" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="ae4TW034q6_u2rk01mG-" name="菜单树构建逻辑">
|
||||
<mxGraphModel dx="1224" dy="1192" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-321" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="主菜单(class=0)" vertex="1">
|
||||
<mxGeometry height="54" width="171" x="36" y="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-322" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="参数设置(class=1)" vertex="1">
|
||||
<mxGeometry height="54" width="187" x="260" y="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-323" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="信息查看(class=1)" vertex="1">
|
||||
<mxGeometry height="54" width="187" x="250" y="276" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-324" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="关于系统(class=1)" vertex="1">
|
||||
<mxGeometry height="54" width="187" x="250" y="430" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-325" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="定值设置(class=2)" vertex="1">
|
||||
<mxGeometry height="54" width="187" x="520" y="107" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-326" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="开关设置(class=2)" vertex="1">
|
||||
<mxGeometry height="54" width="187" x="520" y="207" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-327" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="运行信息(class=2)" vertex="1">
|
||||
<mxGeometry height="54" width="187" x="520" y="294" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-328" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-321" style="startArrow=none;endArrow=block;entryX=0.64;entryY=0;rounded=0;edgeStyle=orthogonalEdgeStyle;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" target="uTcgnOhw-1hiChn4308x-322" value="lower">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="380" y="47" />
|
||||
</Array>
|
||||
<mxPoint x="240" y="40" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-329" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-322" style="startArrow=none;endArrow=block;exitX=0.667;exitY=1.037;entryX=0.72;entryY=0;rounded=0;exitDx=0;exitDy=0;exitPerimeter=0;" target="uTcgnOhw-1hiChn4308x-323" value="behind">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-330" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-323" style="startArrow=none;endArrow=block;exitX=0.75;exitY=1;entryX=0.75;entryY=0;rounded=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;" target="uTcgnOhw-1hiChn4308x-324" value="behind">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-331" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-324" style="startArrow=none;endArrow=block;exitX=0.75;exitY=1;entryX=-0.001;entryY=0.171;rounded=0;edgeStyle=orthogonalEdgeStyle;exitDx=0;exitDy=0;entryDx=0;entryDy=0;entryPerimeter=0;" target="uTcgnOhw-1hiChn4308x-322" value="behind 回环">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="390" y="520" />
|
||||
<mxPoint x="110" y="520" />
|
||||
<mxPoint x="110" y="149" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-332" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-322" style="startArrow=none;endArrow=block;exitX=0;exitY=0.75;entryX=0.25;entryY=1;rounded=0;edgeStyle=orthogonalEdgeStyle;entryDx=0;entryDy=0;exitDx=0;exitDy=0;" target="uTcgnOhw-1hiChn4308x-324" value="before 回环">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="180" y="180" />
|
||||
<mxPoint x="180" y="500" />
|
||||
<mxPoint x="297" y="500" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-333" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-323" style="startArrow=none;endArrow=block;exitX=0.269;exitY=0.012;entryX=0.33;entryY=1;rounded=0;exitDx=0;exitDy=0;exitPerimeter=0;" value="before">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="321.79" y="276" as="sourcePoint" />
|
||||
<mxPoint x="300.00000000000006" y="194" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-334" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-324" style="startArrow=none;endArrow=block;exitX=0.4;exitY=0;entryX=0.399;entryY=0.986;rounded=0;entryDx=0;entryDy=0;entryPerimeter=0;" target="uTcgnOhw-1hiChn4308x-323" value="before">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-335" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-322" style="startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;entryDx=0;entryDy=0;exitDx=0;exitDy=0;edgeStyle=orthogonalEdgeStyle;" target="uTcgnOhw-1hiChn4308x-325" value="lower">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-336" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-325" style="startArrow=none;endArrow=block;exitX=0.912;exitY=0.975;entryX=0.91;entryY=0;rounded=0;edgeStyle=orthogonalEdgeStyle;exitDx=0;exitDy=0;exitPerimeter=0;" target="uTcgnOhw-1hiChn4308x-326" value="behind">
|
||||
<mxGeometry relative="1" x="0.1907" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-337" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-326" style="startArrow=none;endArrow=block;exitX=0.332;exitY=-0.003;entryX=0.33;entryY=1;rounded=0;exitDx=0;exitDy=0;exitPerimeter=0;" target="uTcgnOhw-1hiChn4308x-325" value="behind 回环">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-338" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-325" style="startArrow=none;endArrow=block;exitX=0.669;exitY=0.986;rounded=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.673;entryY=-0.017;entryDx=0;entryDy=0;entryPerimeter=0;" target="uTcgnOhw-1hiChn4308x-326" value="before 回环">
|
||||
<mxGeometry relative="1" x="0.1635" y="-6" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
<mxPoint x="647" y="167" as="sourcePoint" />
|
||||
<mxPoint x="645" y="187" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-339" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-326" style="startArrow=none;endArrow=block;exitX=0.133;exitY=-0.013;entryX=0.13;entryY=1;rounded=0;exitDx=0;exitDy=0;exitPerimeter=0;" target="uTcgnOhw-1hiChn4308x-325" value="before">
|
||||
<mxGeometry relative="1" x="0.0153" y="9" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-340" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-323" style="startArrow=none;endArrow=block;exitX=0.999;exitY=0.807;entryX=0;entryY=0.5;rounded=0;edgeStyle=orthogonalEdgeStyle;entryDx=0;entryDy=0;exitDx=0;exitDy=0;exitPerimeter=0;" target="uTcgnOhw-1hiChn4308x-327" value="lower">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-341" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-322" style="startArrow=none;endArrow=block;exitX=0.21;exitY=0;entryX=0.5;entryY=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" target="uTcgnOhw-1hiChn4308x-321" value="higher">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-342" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-323" style="startArrow=none;endArrow=block;exitX=0;exitY=0.5;entryX=0.26;entryY=1;rounded=0;edgeStyle=orthogonalEdgeStyle;exitDx=0;exitDy=0;" target="uTcgnOhw-1hiChn4308x-321" value="higher">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="80" y="303" />
|
||||
<mxPoint x="80" y="276" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-343" edge="1" parent="1" style="startArrow=none;endArrow=block;entryX=0;entryY=0.83;rounded=0;edgeStyle=orthogonalEdgeStyle;" value="higher">
|
||||
<mxGeometry relative="1" x="0.4125" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
<Array as="points">
|
||||
<mxPoint x="250" y="460" />
|
||||
<mxPoint x="20" y="460" />
|
||||
<mxPoint x="20" y="40" />
|
||||
</Array>
|
||||
<mxPoint x="250" y="460" as="sourcePoint" />
|
||||
<mxPoint x="36" y="40.019999999999996" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-344" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-325" style="startArrow=none;endArrow=block;exitX=0.5;exitY=0;entryX=0.905;entryY=0.019;rounded=0;edgeStyle=orthogonalEdgeStyle;entryDx=0;entryDy=0;entryPerimeter=0;exitDx=0;exitDy=0;" target="uTcgnOhw-1hiChn4308x-322" value="higher">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="614" y="80" />
|
||||
<mxPoint x="429" y="80" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-345" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-326" style="startArrow=none;endArrow=block;exitX=0;exitY=0.5;rounded=0;edgeStyle=orthogonalEdgeStyle;exitDx=0;exitDy=0;" value="higher">
|
||||
<mxGeometry relative="1" x="-0.3947" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
<Array as="points">
|
||||
<mxPoint x="420" y="234" />
|
||||
</Array>
|
||||
<mxPoint x="420" y="194" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-346" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-327" style="startArrow=none;endArrow=block;exitX=0.43;exitY=0;entryX=1.005;entryY=0.163;rounded=0;edgeStyle=orthogonalEdgeStyle;entryDx=0;entryDy=0;entryPerimeter=0;" target="uTcgnOhw-1hiChn4308x-323" value="higher">
|
||||
<mxGeometry relative="1" x="0.4124" y="-3" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
<Array as="points">
|
||||
<mxPoint x="600" y="285" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-347" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-327" style="endArrow=classic;html=1;rounded=0;exitX=0.677;exitY=0.972;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.709;entryY=0.015;entryDx=0;entryDy=0;entryPerimeter=0;curved=1;" target="uTcgnOhw-1hiChn4308x-327" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="710" y="380" />
|
||||
<mxPoint x="730" y="330" />
|
||||
<mxPoint x="730" y="300" />
|
||||
<mxPoint x="720" y="260" />
|
||||
</Array>
|
||||
<mxPoint x="657" y="460" as="sourcePoint" />
|
||||
<mxPoint x="707" y="410" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-348" connectable="0" parent="uTcgnOhw-1hiChn4308x-347" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="before" vertex="1">
|
||||
<mxGeometry relative="1" x="-0.0353" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-351" edge="1" parent="1" source="uTcgnOhw-1hiChn4308x-327" style="curved=1;endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" target="uTcgnOhw-1hiChn4308x-327" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="750" y="230" />
|
||||
<mxPoint x="750" y="400" />
|
||||
<mxPoint x="590" y="390" />
|
||||
</Array>
|
||||
<mxPoint x="570" y="484" as="sourcePoint" />
|
||||
<mxPoint x="620" y="434" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uTcgnOhw-1hiChn4308x-352" connectable="0" parent="uTcgnOhw-1hiChn4308x-351" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="behind" vertex="1">
|
||||
<mxGeometry relative="1" x="0.0226" y="-5" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="5RVJ2jwpCgCB7Hji9JxO" name="菜单树判断逻辑">
|
||||
<mxGraphModel dx="2720" dy="2649" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-1" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="byCurClass < byNextClass" vertex="1">
|
||||
<mxGeometry height="54" width="241" x="250" y="380" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-2" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="进入子菜单" vertex="1">
|
||||
<mxGeometry height="54" width="140" x="510" y="380" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-3" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="current.lower = next" vertex="1">
|
||||
<mxGeometry height="54" width="190" x="670" y="380" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-4" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="next.higher = current" vertex="1">
|
||||
<mxGeometry height="54" width="209" x="891" y="380" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-5" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="byCurClass == byNextClass" vertex="1">
|
||||
<mxGeometry height="54" width="240" x="250" y="484" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-6" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="同层兄弟" vertex="1">
|
||||
<mxGeometry height="54" width="140" x="511" y="484" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-7" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="current.behind = next" vertex="1">
|
||||
<mxGeometry height="54" width="190" x="670" y="484" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-8" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="next.before = current" vertex="1">
|
||||
<mxGeometry height="54" width="210" x="890" y="484" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-9" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="next.higher = current.higher" vertex="1">
|
||||
<mxGeometry height="78" width="260" x="1140" y="472" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-10" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="byCurClass > byNextClass" vertex="1">
|
||||
<mxGeometry height="54" width="241" x="250" y="591" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-11" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="从深层回退" vertex="1">
|
||||
<mxGeometry height="54" width="140" x="510" y="591" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-12" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="next.before = ptLast[nextClass]" vertex="1">
|
||||
<mxGeometry height="54" width="190" x="670" y="591" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-27" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="HZ-q9eH6YA3dt1o5nvaf-26" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-13" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="ptLast[nextClass].behind=next" vertex="1">
|
||||
<mxGeometry height="54" width="190" x="1140" y="591" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-14" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-1" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-2" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-15" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-2" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-3" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-16" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-3" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-4" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-17" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-5" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-6" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-18" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-6" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-7" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-19" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-7" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-8" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-20" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-8" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-9" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-21" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-10" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-11" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-22" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-11" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;" target="HZ-q9eH6YA3dt1o5nvaf-12" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-23" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-12" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;rounded=0;exitDx=0;exitDy=0;" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
<mxPoint x="890" y="618" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-25" edge="1" parent="1" source="HZ-q9eH6YA3dt1o5nvaf-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="HZ-q9eH6YA3dt1o5nvaf-13" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-24" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="next.behind=ptLast[nextClass].higher" vertex="1">
|
||||
<mxGeometry height="54" width="209" x="891" y="591" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="HZ-q9eH6YA3dt1o5nvaf-26" parent="1" style="whiteSpace=wrap;html=1;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);strokeWidth=2;" value="形成回环" vertex="1">
|
||||
<mxGeometry height="55" width="69" x="1351" y="591" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="zG06bic9s9vmrHAmIL5z" name="模型层初始化顺序">
|
||||
<mxGraphModel dx="628" dy="611" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-21" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="4pC_cjyCFYns3d6entyY-3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-1" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);rounded=1;" value="开始" vertex="1">
|
||||
<mxGeometry height="24" width="210" x="320" y="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-3" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="计算菜单个数 maxItem " vertex="1">
|
||||
<mxGeometry height="30" width="210" x="320" y="171" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-5" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="统计 0 级菜单数量 by0LevelNum " vertex="1">
|
||||
<mxGeometry height="30" width="210" x="320" y="225" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-6" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="构建菜单树链路" vertex="1">
|
||||
<mxGeometry height="30" width="210" x="320" y="279" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-7" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="补充带子菜单项的右侧箭头》" vertex="1">
|
||||
<mxGeometry height="40" width="210" x="320" y="328" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-8" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="计算各节点 wPos 与 wNum" vertex="1">
|
||||
<mxGeometry height="30" width="210" x="320" y="387" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-9" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="计算整棵菜单树的显示位置" vertex="1">
|
||||
<mxGeometry height="30" width="210" x="320" y="441" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-10" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);rounded=1;" value="函数结束" vertex="1">
|
||||
<mxGeometry height="20" width="210" x="320" y="500" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-13" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-3" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;entryDx=0;entryDy=0;" target="4pC_cjyCFYns3d6entyY-5" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
<mxPoint x="426" y="470" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-15" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-5" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="4pC_cjyCFYns3d6entyY-6" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-16" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-6" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="4pC_cjyCFYns3d6entyY-7" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-17" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-7" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="4pC_cjyCFYns3d6entyY-8" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-18" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-8" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="4pC_cjyCFYns3d6entyY-9" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="4pC_cjyCFYns3d6entyY-19" edge="1" parent="1" source="4pC_cjyCFYns3d6entyY-9" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="4pC_cjyCFYns3d6entyY-10" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
@@ -1,4 +1,4 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.6.6 Chrome/144.0.7559.236 Electron/40.8.4 Safari/537.36" version="29.6.6" pages="8">
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.6.6 Chrome/144.0.7559.236 Electron/40.8.4 Safari/537.36" version="29.6.6" pages="10">
|
||||
<diagram name="显示指定层级菜单项流程" id="etDREPkzm4HehLh3Wzss">
|
||||
<mxGraphModel dx="752" dy="817" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
@@ -437,7 +437,7 @@
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="zG06bic9s9vmrHAmIL5z" name="第 8 页">
|
||||
<diagram id="zG06bic9s9vmrHAmIL5z" name="模型层初始化顺序">
|
||||
<mxGraphModel dx="628" dy="611" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
@@ -503,4 +503,330 @@
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="GAiekOzPbh1v7V_syctI" name="按键处理逻辑">
|
||||
<mxGraphModel dx="1440" dy="2571" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-84" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="开始" vertex="1">
|
||||
<mxGeometry height="54" width="92" x="1003" y="-180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-85" parent="1" style="rhombus;strokeWidth=2;whiteSpace=wrap;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="按下哪个键?" vertex="1">
|
||||
<mxGeometry height="140" width="140" x="979" y="-76" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-86" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="KEY_U" vertex="1">
|
||||
<mxGeometry height="54" width="106" x="840" y="-80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-87" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="KEY_D" vertex="1">
|
||||
<mxGeometry height="54" width="105" x="840" y="-10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-88" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="KEY_L" vertex="1">
|
||||
<mxGeometry height="54" width="103" x="840" y="64" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-89" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="KEY_R / KEY_ENT" vertex="1">
|
||||
<mxGeometry height="54" width="186" x="1080" y="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-90" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="KEY_ESC" vertex="1">
|
||||
<mxGeometry height="54" width="121" x="1153" y="-26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-91" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="其他按键" vertex="1">
|
||||
<mxGeometry height="48" width="124" x="1150" y="-110" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-92" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="焦点移动到上一项" vertex="1">
|
||||
<mxGeometry height="54" width="126" x="690" y="-80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-93" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="焦点移动到下一项" vertex="1">
|
||||
<mxGeometry height="54" width="126" x="690" y="-10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-94" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="先退回上一级" vertex="1">
|
||||
<mxGeometry height="54" width="126" x="690" y="64" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-95" parent="1" style="rhombus;strokeWidth=2;whiteSpace=wrap;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="是否退回到 0 级菜单?" vertex="1">
|
||||
<mxGeometry height="100" width="190" x="650" y="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-96" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="重新定位到某个 0 级入口的子菜单" vertex="1">
|
||||
<mxGeometry height="54" width="210" x="700" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-97" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="停留在上一级菜单项" vertex="1">
|
||||
<mxGeometry height="56" width="204" x="856" y="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-98" parent="1" style="rhombus;strokeWidth=2;whiteSpace=wrap;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="当前项有子菜单?" vertex="1">
|
||||
<mxGeometry height="100" width="172" x="1087" y="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-99" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="进入子菜单" vertex="1">
|
||||
<mxGeometry height="54" width="140" x="930" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-100" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="若有回调则执行回调" vertex="1">
|
||||
<mxGeometry height="54" width="130" x="1080" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-101" parent="1" style="rhombus;strokeWidth=2;whiteSpace=wrap;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="当前是否在 1 级菜单?" vertex="1">
|
||||
<mxGeometry height="130" width="206" x="1290" y="28" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-102" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="快速回到初始菜单状态" vertex="1">
|
||||
<mxGeometry height="54" width="141" x="1220" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-103" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="退回上一级" vertex="1">
|
||||
<mxGeometry height="54" width="80" x="1370" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-104" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="不处理" vertex="1">
|
||||
<mxGeometry height="50" width="108" x="1310" y="-112" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-106" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-84" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-85" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-107" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-85" style="startArrow=none;endArrow=block;exitX=0;exitY=0.5;rounded=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitDx=0;exitDy=0;" target="stTsyAOdvTomNQkrpvn1-86" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="820" y="-30" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-108" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-85" style="startArrow=none;endArrow=block;exitX=0;exitY=0.57;entryX=1;entryY=0.5;rounded=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-87" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-109" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-85" style="startArrow=none;endArrow=block;exitX=0;exitY=0.71;entryX=1;entryY=0.5;rounded=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-88" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-110" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-85" style="startArrow=none;endArrow=block;exitX=1;exitY=0.69;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-89" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-111" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-85" style="startArrow=none;endArrow=block;exitX=1;exitY=0.56;entryX=0;entryY=0.5;rounded=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-90" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-112" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-85" style="startArrow=none;endArrow=block;exitX=1;exitY=0.54;entryX=0;entryY=0.5;rounded=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-91" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-113" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-86" style="curved=1;startArrow=none;endArrow=block;exitX=0;exitY=0.5;entryX=1;entryY=0.5;rounded=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-92" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-114" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-87" style="curved=1;startArrow=none;endArrow=block;exitX=0;exitY=0.5;entryX=1;entryY=0.5;rounded=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-93" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-115" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-88" style="curved=1;startArrow=none;endArrow=block;exitX=0;exitY=0.5;entryX=1;entryY=0.5;rounded=0;entryDx=0;entryDy=0;exitDx=0;exitDy=0;" target="stTsyAOdvTomNQkrpvn1-94" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-116" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-94" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-95" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-117" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-95" style="startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;exitDx=0;exitDy=0;" target="stTsyAOdvTomNQkrpvn1-96" value="是">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-118" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-95" style="startArrow=none;endArrow=block;exitX=0.743;exitY=0.238;entryX=0;entryY=0.5;rounded=0;entryDx=0;entryDy=0;exitDx=0;exitDy=0;exitPerimeter=0;" target="stTsyAOdvTomNQkrpvn1-97" value="否">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-119" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-89" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-98" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-120" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-98" style="startArrow=none;endArrow=block;exitX=0.1;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-99" value="是">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-121" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-98" style="startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;exitDx=0;exitDy=0;" target="stTsyAOdvTomNQkrpvn1-100" value="否">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-122" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-90" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.301;entryY=0.223;rounded=0;entryDx=0;entryDy=0;entryPerimeter=0;" target="stTsyAOdvTomNQkrpvn1-101" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-123" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-101" style="startArrow=none;endArrow=block;exitX=0.09;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-102" value="是">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-124" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-101" style="startArrow=none;endArrow=block;exitX=0.91;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="stTsyAOdvTomNQkrpvn1-103" value="否">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="stTsyAOdvTomNQkrpvn1-125" edge="1" parent="1" source="stTsyAOdvTomNQkrpvn1-91" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;" target="stTsyAOdvTomNQkrpvn1-104" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="dIhOnUq7jFqkhXTXlf7A" name="系统架构">
|
||||
<mxGraphModel dx="237" dy="1037" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-1" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=15;" value="🏗️ 底层基础设施 (Infrastructure)






" vertex="1">
|
||||
<mxGeometry height="150" width="640" x="900" y="849" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-2" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#d5e8d4;strokeColor=#82b366;" value="🔧 驱动抽象层 (Driver Abstraction)







" vertex="1">
|
||||
<mxGeometry height="152" width="640" x="900" y="686" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-3" parent="1" style="whiteSpace=wrap;strokeWidth=2;" value="⚙️ MVP 业务层 (MVP Business Layer)

























" vertex="1">
|
||||
<mxGeometry height="392" width="640" x="900" y="282" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-4" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#f8cecc;strokeColor=#b85450;" value="⚙️ YC Page





















" vertex="1">
|
||||
<mxGeometry height="347" width="170" x="1351" y="307" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-5" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#fff2cc;strokeColor=#d6b656;" value="ℹ️ AppInfo Page





















" vertex="1">
|
||||
<mxGeometry height="347" width="190" x="1140" y="307" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-6" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#ffe6cc;strokeColor=#d79b00;" value="📋 Menu Page





















" vertex="1">
|
||||
<mxGeometry height="347" width="200" x="916" y="307" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-7" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" value="🔄 多页面管理层 (Page Management)




" vertex="1">
|
||||
<mxGeometry height="110" width="640" x="900" y="160" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-8" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=18;" value="📱 应用层 (Application Layer)


" vertex="1">
|
||||
<mxGeometry height="102" width="640" x="900" y="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-9" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" value="main.c
系统初始化 / 主循环调度
/ 生命周期管理" vertex="1">
|
||||
<mxGeometry height="62" width="420" x="1037" y="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-10" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="📦 Page Manager
栈式调度
事件分发器" vertex="1">
|
||||
<mxGeometry height="63" width="185" x="983" y="197" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-11" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="🌍 Global Model
跨页面共享数据
持久化配置
观察者通知" vertex="1">
|
||||
<mxGeometry height="62" width="180" x="1305" y="197" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-12" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="Model
菜单数据与状态" vertex="1">
|
||||
<mxGeometry height="78" width="170" x="933" y="341" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-13" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="Presenter
事件处理/导航逻辑" vertex="1">
|
||||
<mxGeometry height="78" width="170" x="933" y="454" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-14" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="View
菜单渲染绘制" vertex="1">
|
||||
<mxGeometry height="78" width="170" x="933" y="564" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-15" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="Model
应用信息数据" vertex="1">
|
||||
<mxGeometry height="78" width="156" x="1161" y="341" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-16" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="Presenter
信息展示逻辑" vertex="1">
|
||||
<mxGeometry height="78" width="156" x="1156" y="454" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-17" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="View
信息页面渲染" vertex="1">
|
||||
<mxGeometry height="78" width="156" x="1156" y="564" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-18" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="Model
YC 配置数据" vertex="1">
|
||||
<mxGeometry height="78" width="148" x="1363" y="341" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-19" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="Presenter
YC 控制逻辑" vertex="1">
|
||||
<mxGeometry height="78" width="148" x="1363" y="454" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-20" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=light-dark(#eeeeee,#1f2020);strokeColor=light-dark(#999999,#cccccc);fontColor=light-dark(#333333,#cccccc);" value="View
YC 页面渲染" vertex="1">
|
||||
<mxGeometry height="78" width="148" x="1363" y="564" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-21" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;flipH=1;legacyAnchorPoints=0;" value="🖥️ LCD 驱动
显存操作
图形/文字绘制" vertex="1">
|
||||
<mxGeometry height="100" width="160" x="1153" y="726" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-22" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#fa6800;strokeColor=#C73500;fontColor=#000000;flipH=1;legacyAnchorPoints=0;" value="⌨️ 按键驱动
输入抽象
本地/远程注入" vertex="1">
|
||||
<mxGeometry height="100" width="160" x="956" y="726" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-24" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#e3c800;strokeColor=#B09500;fontColor=#000000;flipH=1;legacyAnchorPoints=0;" value="🎨 渲染端口
底层绘制接口" vertex="1">
|
||||
<mxGeometry height="100" width="160" x="1346" y="726" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-25" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#6d8764;strokeColor=#3A5431;fontColor=#ffffff;" value="🌐 TCP/Socket
网络通信封装
跨平台适配" vertex="1">
|
||||
<mxGeometry height="102" width="150" x="959" y="879" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-26" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#647687;strokeColor=#314354;fontColor=#ffffff;" value="⚡ 线程工具
线程管理
同步机制" vertex="1">
|
||||
<mxGeometry height="102" width="151" x="1141" y="879" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-27" parent="1" style="whiteSpace=wrap;strokeWidth=2;fillColor=#a0522d;strokeColor=#6D1F00;fontColor=#ffffff;" value="🔤 UTF-8 处理
编码转换
字符解析" vertex="1">
|
||||
<mxGeometry height="102" width="155" x="1351.5" y="879" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-28" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-9" style="startArrow=none;endArrow=block;exitX=0.09;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-10" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-29" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-9" style="startArrow=none;endArrow=block;exitX=0.85;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-11" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-30" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-12" style="startArrow=block;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;exitDx=0;exitDy=0;" target="SKzmmjIQc6qRBKoh8kct-13" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-31" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-13" style="curved=1;startArrow=block;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-14" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-32" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-15" style="startArrow=block;endArrow=block;exitX=0.46;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-16" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-33" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-16" style="curved=1;startArrow=block;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-17" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-34" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-18" style="startArrow=block;endArrow=block;entryX=0.5;entryY=0;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" target="SKzmmjIQc6qRBKoh8kct-19" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-35" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-19" style="curved=1;startArrow=block;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-20" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-36" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-22" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-25" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-37" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-25" style="curved=1;startArrow=none;endArrow=block;exitX=1;exitY=0.5;entryX=0;entryY=0.5;rounded=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-26" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-38" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-21" style="curved=1;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;" target="SKzmmjIQc6qRBKoh8kct-27" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-39" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-11" style="dashed=1;dashPattern=2 3;startArrow=none;endArrow=block;entryX=0.5;entryY=0;rounded=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" target="SKzmmjIQc6qRBKoh8kct-12" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1403" y="280" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-40" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-11" style="dashed=1;dashPattern=2 3;startArrow=none;endArrow=block;exitX=0.49;exitY=1;entryX=0.5;entryY=0;rounded=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-15" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-41" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-11" style="dashed=1;dashPattern=2 3;startArrow=none;endArrow=block;exitX=0.5;exitY=1;entryX=0.5;entryY=0;rounded=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-18" value="">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-42" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-10" style="curved=1;startArrow=none;endArrow=block;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" target="SKzmmjIQc6qRBKoh8kct-6" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-43" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-10" style="curved=1;startArrow=none;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-5" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-44" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-10" style="curved=1;startArrow=none;endArrow=block;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" target="SKzmmjIQc6qRBKoh8kct-4" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-45" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-14" style="curved=1;startArrow=none;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-21" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-46" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-6" style="curved=1;startArrow=none;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" target="SKzmmjIQc6qRBKoh8kct-22" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-48" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-17" style="curved=1;startArrow=none;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-21" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="SKzmmjIQc6qRBKoh8kct-49" edge="1" parent="1" source="SKzmmjIQc6qRBKoh8kct-20" style="curved=1;startArrow=none;endArrow=block;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="SKzmmjIQc6qRBKoh8kct-21" value="">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
|
||||
@@ -30,5 +30,12 @@ typedef int (*FUNCPTR) ( );
|
||||
#define ASSERT(expr) ((void)0) // 发布模式禁用断言
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG(format, ...) \
|
||||
printf(format, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(format, ...) ((void)0) // 发布模式禁用断言
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,10 +52,13 @@ static int8_t Lcd_ColorCheck(uint32_t color)
|
||||
* - LCD_ERR_OUT_OF_RANGE: 坐标越界或顺序非法
|
||||
* - LCD_ERR_INVALID_COLOR: 颜色非法
|
||||
* ------------------------------------------------------------------------- */
|
||||
int8_t Lcd_FillRect(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y, uint32_t color)
|
||||
int8_t Lcd_FillRect(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y, uint8_t color)
|
||||
{
|
||||
ASSERT((right_x >= LCD_SIZE_X) || (bottom_y >= LCD_SIZE_Y));
|
||||
if (Lcd_ColorCheck(color) != LCD_OK) return LCD_ERR_INVALID_COLOR;
|
||||
ASSERT((right_x >= LCD_SIZE_X) || (bottom_y >= LCD_SIZE_Y));
|
||||
if ((right_x < left_x) || (bottom_y < top_y)) return LCD_ERR_OUT_OF_RANGE;
|
||||
ASSERT((right_x >= LCD_SIZE_X) || (bottom_y >= LCD_SIZE_Y));
|
||||
if ((right_x >= LCD_SIZE_X) || (bottom_y >= LCD_SIZE_Y)) return LCD_ERR_OUT_OF_RANGE;
|
||||
|
||||
for (uint16_t y = top_y; y <= bottom_y; y++) {
|
||||
@@ -109,9 +112,13 @@ int8_t Lcd_LineH(uint16_t wXStart, uint16_t wXEnd, uint16_t wYStart, uint16_t wW
|
||||
M_GuiSwap(wXEnd, wXStart);
|
||||
}
|
||||
wYEnd32 = (uint32_t)wYStart + (uint32_t)wWidth;
|
||||
ASSERT((wXStart >= LCD_SIZE_X) || (wXEnd > LCD_SIZE_X));
|
||||
if (wXStart >= LCD_SIZE_X) return LCD_ERR_OUT_OF_RANGE;
|
||||
ASSERT((wXEnd > LCD_SIZE_X) || (wYStart >= LCD_SIZE_Y));
|
||||
if (wXEnd > LCD_SIZE_X) return LCD_ERR_OUT_OF_RANGE; /* 半开区间,end 可等于边界 */
|
||||
ASSERT((wYStart >= LCD_SIZE_Y) || (wYEnd32 > LCD_SIZE_Y));
|
||||
if (wYStart >= LCD_SIZE_Y) return LCD_ERR_OUT_OF_RANGE;
|
||||
ASSERT((wYEnd32 > LCD_SIZE_Y) || (wXStart >= LCD_SIZE_X));
|
||||
if (wYEnd32 > LCD_SIZE_Y) return LCD_ERR_OUT_OF_RANGE; /* 半开区间,end 可等于边界 */
|
||||
wYEnd = (uint16_t)wYEnd32;
|
||||
|
||||
@@ -157,9 +164,13 @@ int8_t Lcd_LineV(uint16_t wYStart, uint16_t wYEnd, uint16_t wXStart, uint16_t wW
|
||||
M_GuiSwap(wYEnd, wYStart);
|
||||
}
|
||||
wXEnd32 = (uint32_t)wXStart + (uint32_t)wWidth;
|
||||
ASSERT((wYStart >= LCD_SIZE_Y) || (wXStart >= LCD_SIZE_X));
|
||||
if (wYStart >= LCD_SIZE_Y) return LCD_ERR_OUT_OF_RANGE;
|
||||
ASSERT((wYEnd > LCD_SIZE_Y) || (wXStart >= LCD_SIZE_X));
|
||||
if (wYEnd > LCD_SIZE_Y) return LCD_ERR_OUT_OF_RANGE; /* 半开区间,end 可等于边界 */
|
||||
ASSERT((wXStart >= LCD_SIZE_X) || (wXEnd32 > LCD_SIZE_X));
|
||||
if (wXStart >= LCD_SIZE_X) return LCD_ERR_OUT_OF_RANGE;
|
||||
ASSERT((wXEnd32 > LCD_SIZE_X) || (wYStart >= LCD_SIZE_Y));
|
||||
if (wXEnd32 > LCD_SIZE_X) return LCD_ERR_OUT_OF_RANGE; /* 半开区间,end 可等于边界 */
|
||||
wXEnd = (uint16_t)wXEnd32;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
|
||||
|
||||
int8_t Lcd_FillRect(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y, uint32_t color);
|
||||
int8_t Lcd_FillRect(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y, uint8_t color);
|
||||
int8_t Lcd_Invert(uint16_t wXstart, uint16_t wYstart, uint16_t wXend, uint16_t wYend);
|
||||
int8_t Lcd_LineH(uint16_t wXStart, uint16_t wXEnd, uint16_t wYStart, uint16_t wWidth, uint8_t color);
|
||||
int8_t Lcd_LineV(uint16_t wYStart, uint16_t wYEnd, uint16_t wXStart, uint16_t wWidth, uint8_t color);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "ascii.h"
|
||||
#include "lcd_draw.h"
|
||||
|
||||
static textConfig text_cfg = {
|
||||
textConfig text_cfg = {
|
||||
.wGBFontWidth = 13,
|
||||
.wGBFontHeight = 12,
|
||||
.wASCIIFontWidth = 7,
|
||||
|
||||
@@ -13,6 +13,9 @@ typedef struct {
|
||||
uint16_t rowSpace;
|
||||
} textConfig;
|
||||
|
||||
|
||||
extern textConfig text_cfg;
|
||||
|
||||
int8_t Lcd_ShowStr(uint16_t x, uint16_t y, uint8_t *pcString);
|
||||
int8_t Lcd_ShowTest(uint16_t x, uint16_t y, uint8_t *pcString);
|
||||
|
||||
|
||||
@@ -1,12 +1,35 @@
|
||||
#include "menu.h"
|
||||
|
||||
#include "../../pages/menu/page.h"
|
||||
#include "../../pages/page_manager.h"
|
||||
|
||||
void MenuProc_See_AppInfo(void)
|
||||
{
|
||||
MenuPage_TriggerCurrentAction();
|
||||
(void)PageManager_Navigate(PAGE_ID_APP_INFO);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPage_TriggerCurrentAction
|
||||
* 功能:
|
||||
* 触发当前菜单项动作的占位接口(当前版本仅输出调试日志)。
|
||||
*
|
||||
* 参数:
|
||||
* 无
|
||||
*
|
||||
* 边界处理:
|
||||
* - 当前实现不依赖外部输入,不涉及参数校验。
|
||||
*
|
||||
* 说明:
|
||||
* - 现阶段用于保留动作触发扩展点,后续可接入真实业务动作执行链路。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
void MenuPage_TriggerCurrentAction(void)
|
||||
{
|
||||
printf("MenuPage_TriggerCurrentAction\n");
|
||||
}
|
||||
|
||||
|
||||
void MenuProc_See_YC(void)
|
||||
{
|
||||
MenuPage_TriggerCurrentAction();
|
||||
|
||||
9
src/Drv/pages/AppInfo/def.h
Normal file
9
src/Drv/pages/AppInfo/def.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef APPINFO_def_H
|
||||
#define APPINFO_def_H
|
||||
|
||||
#define CN_HEIGHT 12
|
||||
#define CN_ROWSPACE 2
|
||||
#define APPINFO_WITDTH 7
|
||||
|
||||
|
||||
#endif
|
||||
15
src/Drv/pages/AppInfo/model.c
Normal file
15
src/Drv/pages/AppInfo/model.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "Drv/pages/AppInfo/model.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void AppInfoModel_Init(appinfo_model_t *model)
|
||||
{
|
||||
if (model == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(model, 0, sizeof(*model));
|
||||
/* 默认顶栏标题,与菜单「装置信息」条目一致 */
|
||||
(void)memcpy(model->topName, "装置信息", sizeof("装置信息"));
|
||||
}
|
||||
15
src/Drv/pages/AppInfo/model.h
Normal file
15
src/Drv/pages/AppInfo/model.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef APPINFO_MODEL_H
|
||||
#define APPINFO_MODEL_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct appinfo_model_t appinfo_model_t;
|
||||
|
||||
struct appinfo_model_t
|
||||
{
|
||||
uint8_t topName[32];
|
||||
};
|
||||
|
||||
void AppInfoModel_Init(appinfo_model_t *model);
|
||||
|
||||
#endif
|
||||
218
src/Drv/pages/AppInfo/page.c
Normal file
218
src/Drv/pages/AppInfo/page.c
Normal file
@@ -0,0 +1,218 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Drv/pages/AppInfo/page.h"
|
||||
#include "Drv/pages/AppInfo/model.h"
|
||||
#include "Drv/pages/AppInfo/presenter.h"
|
||||
#include "Drv/pages/AppInfo/view.h"
|
||||
#include "Drv/pages/global/renderer_lcd.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 模块内静态对象说明:
|
||||
* s_model - AppInfo页 Model 实例(AppInfo数据与运行时结构)
|
||||
* s_view - AppInfo页 View 实例(布局与渲染能力)
|
||||
* s_presenter - AppInfo页 Presenter 实例(输入处理与状态驱动)
|
||||
* s_page - 页面管理器可注册的 page_t 描述对象
|
||||
*
|
||||
* 说明:
|
||||
* - 以上对象均为文件内静态单例,生命周期覆盖进程运行期。
|
||||
* - 通过 AppInfoPage_GetInstance() 暴露 s_page 给 PageManager 注册。
|
||||
* ------------------------------------------------------------------------- */
|
||||
static appinfo_model_t s_model;
|
||||
static appinfo_view_t s_view;
|
||||
static appinfo_presenter_t s_presenter;
|
||||
static page_t s_page;
|
||||
static const PageRenderPort *s_port = NULL;
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: AppInfoPage_OnExit
|
||||
* 功能:
|
||||
* 页面退出回调占位点;当前版本无额外退出动作。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 使用 (void)page 防止未使用参数告警。
|
||||
*
|
||||
* 说明:
|
||||
* - 预留给后续扩展(如停止定时任务、冻结动画、保存瞬时 UI 状态等)。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void Page_OnExit(page_t *page)
|
||||
{
|
||||
s_port->clear_screen();
|
||||
(void)page;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: AppInfoPage_OnDestroy
|
||||
* 功能:
|
||||
* 页面销毁回调:清空菜单页内部三层对象(Model/View/Presenter)状态。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 使用 memset 全量清零静态对象,避免残留状态影响后续重建。
|
||||
*
|
||||
* 说明:
|
||||
* - 与 is_cached 策略配合:当页面被标记为非缓存并弹栈销毁时,该函数用于复位。
|
||||
* - page_t 元信息不在此函数复位,由页面生命周期创建阶段重新赋值。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void Page_OnDestroy(page_t *page)
|
||||
{
|
||||
(void)page;
|
||||
memset(&s_model, 0, sizeof(s_model));
|
||||
memset(&s_view, 0, sizeof(s_view));
|
||||
memset(&s_presenter, 0, sizeof(s_presenter));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: AppInfoPage_OnEvent
|
||||
* 功能:
|
||||
* 页面事件回调:校验输入事件后,将按键转交 Presenter 处理。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
* event - 输入事件指针
|
||||
*
|
||||
* 边界处理:
|
||||
* - event 为 NULL 时返回 EVENT_UNHANDLED。
|
||||
* - 仅处理 PAGE_EVENT_KEY 事件类型,其它类型返回 EVENT_UNHANDLED。
|
||||
* - keyVal 为 0 视为无效按键,返回 EVENT_UNHANDLED。
|
||||
*
|
||||
* 说明:
|
||||
* - 事件有效时调用 Presenter 对外输入接口执行业务流转。
|
||||
* - 返回 EVENT_HANDLED,表示该事件已被菜单页消费,不再交给上层页面逻辑。
|
||||
*
|
||||
* 返回值:
|
||||
* - EVENT_HANDLED : 事件已处理
|
||||
* - EVENT_UNHANDLED : 事件无效或不属于本页处理范围
|
||||
* ------------------------------------------------------------------------- */
|
||||
static event_result_t Page_OnEvent(page_t *page, input_event_t *event)
|
||||
{
|
||||
(void)page;
|
||||
if ((event == NULL) || (event->type != PAGE_EVENT_KEY) || (event->keyVal == 0))
|
||||
{
|
||||
return EVENT_UNHANDLED;
|
||||
}
|
||||
|
||||
s_presenter.handle_input(&s_presenter, event->keyVal);
|
||||
return EVENT_HANDLED;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: AppInfoPage_OnLoop
|
||||
* 功能:
|
||||
* 页面循环回调:周期性驱动 Presenter 执行刷新逻辑。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 使用 (void)page 防止未使用参数告警。
|
||||
*
|
||||
* 说明:
|
||||
* - 实际刷新策略(全量/增量)由 Presenter 内部状态控制。
|
||||
* - 该函数通常由 PageManager_Loop() 在主循环节拍中调用。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void Page_OnLoop(page_t *page)
|
||||
{
|
||||
(void)page;
|
||||
s_presenter.refresh(&s_presenter);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: AppInfoPage_OnCreate
|
||||
* 功能:
|
||||
* 页面创建回调:按 Model -> View -> Presenter 顺序完成菜单页运行时装配,
|
||||
* 并初始化 page_t 描述对象字段。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(由 PageManager 传入)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 先清零 s_menuPage,再统一重建其元信息与回调绑定,避免脏状态遗留。
|
||||
* - 假定 page 非空且来自 PageManager 生命周期调用链。
|
||||
*
|
||||
* 说明:
|
||||
* - 初始化顺序固定:
|
||||
* 1) MenuModel_Init(&s_model)
|
||||
* 2) MenuView_Init(&s_view)
|
||||
* 3) MenuPresenter_Init(&s_presenter, &s_model, &s_view)
|
||||
* - 将 model/presenter/view 回填到 page 与 s_menuPage,便于调试与统一访问。
|
||||
* - s_menuPage 作为静态页面实例,对外由 MenuPage_GetInstance() 返回。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void Page_OnCreate(page_t *page)
|
||||
{
|
||||
/* 1) model init */
|
||||
AppInfoModel_Init(&s_model);
|
||||
|
||||
/* 2) view init */
|
||||
AppInfoView_Init(&s_view);
|
||||
|
||||
/* 3) presenter setup + runtime build */
|
||||
AppInfoPresenter_Init(&s_presenter, &s_model, &s_view);
|
||||
|
||||
|
||||
page->model = &s_model;
|
||||
page->presenter = &s_presenter;
|
||||
page->view = &s_view;
|
||||
|
||||
s_page.presenter = &s_presenter;
|
||||
s_page.view = &s_view;
|
||||
s_page.model = &s_model;
|
||||
s_port = PageRenderer_Lcd();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: AppInfoPage_OnEnter
|
||||
* 功能:
|
||||
* 页面进入回调:将菜单渲染标记为“首帧全量刷新”,并立即触发一次刷新。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数不依赖 page 内容,统一转为 (void)page 消除未使用告警。
|
||||
*
|
||||
* 说明:
|
||||
* - 通过 refresh(..., 1) 告知 Presenter 下一次刷新走首帧路径。
|
||||
* - 进入页面后立即刷新,确保界面可见状态与内部状态同步。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void Page_OnEnter(page_t *page)
|
||||
{
|
||||
(void)page;
|
||||
/* 首帧全量刷新 */
|
||||
LOG("AppInfoPage_OnEnter\n");
|
||||
s_presenter.refresh(&s_presenter);
|
||||
}
|
||||
|
||||
page_t *AppInfoPage_GetInstance(void)
|
||||
{
|
||||
/* 确保在注册到 PageManager 前,页面生命周期回调已就绪 */
|
||||
memset(&s_page, 0, sizeof(s_page));
|
||||
s_page.page_id = PAGE_ID_APP_INFO;
|
||||
s_page.is_cached = 1;
|
||||
s_page.on_create = Page_OnCreate;
|
||||
s_page.on_enter = Page_OnEnter;
|
||||
s_page.on_exit = Page_OnExit;
|
||||
s_page.on_destroy = Page_OnDestroy;
|
||||
s_page.on_event = Page_OnEvent;
|
||||
s_page.on_loop = Page_OnLoop;
|
||||
return &s_page;
|
||||
}
|
||||
9
src/Drv/pages/AppInfo/page.h
Normal file
9
src/Drv/pages/AppInfo/page.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef APPINFO_PAGE_H
|
||||
#define APPINFO_PAGE_H
|
||||
|
||||
#include "Drv/pages/page.h"
|
||||
|
||||
page_t *AppInfoPage_GetInstance(void);
|
||||
void AppInfoPage_TriggerCurrentAction(void);
|
||||
|
||||
#endif
|
||||
90
src/Drv/pages/AppInfo/presenter.c
Normal file
90
src/Drv/pages/AppInfo/presenter.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "Drv/pages/AppInfo/presenter.h"
|
||||
#include "Drv/pages/page_manager.h"
|
||||
#include "Drv/key.h"
|
||||
#include <string.h>
|
||||
|
||||
static void AppInfoPresenter_HandleInput(appinfo_presenter_t *presenter, uint8_t keyVal)
|
||||
{
|
||||
switch (keyVal)
|
||||
{
|
||||
case KEY_ESC:
|
||||
(void)PageManager_Pop();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名:MenuPresenter_Refresh
|
||||
* 功能:
|
||||
* Presenter 层的对外刷新接口,根据是否为首帧渲染选择不同的刷新策略。
|
||||
* 本函数作为 menu_presenter_t::refresh 回调被调用,负责协调 View 层完成界面更新。
|
||||
*
|
||||
* 参数:
|
||||
* presenter - 菜单 Presenter 实例指针,内部持有 menuCtrl 上下文和 view 接口引用
|
||||
* isFirstFrame - 是否为首帧标志:
|
||||
* 1 - 首帧渲染:需要完整初始化并刷新整个菜单界面
|
||||
* 0 - 非首帧渲染:根据当前状态差异进行增量或局部刷新
|
||||
*
|
||||
* 刷新策略:
|
||||
* 首帧模式 (isFirstFrame == 1):
|
||||
* - 调用 View 层的 full_refresh() 接口,完整重绘整个菜单界面。
|
||||
* - 此时 menuCtrl 中的导航路径、选中项等状态已完成初始化,可安全进行全量渲染。
|
||||
* - MODE_NONE 表示不进行特殊模式过滤(如调试模式、特定层级过滤等)。
|
||||
*
|
||||
* 非首帧模式 (isFirstFrame == 0):
|
||||
* - 调用 MenuPresenter_RenderByState() 进行智能状态对比刷新:
|
||||
* 1) 比较 pt0Level 与 ptRoute[0],判断顶层上下文是否切换
|
||||
* 2) 比较 ptCurBak 与 ptCurrent,判断选中项是否变化
|
||||
* 3) 根据层级关系和父节点关联选择最优渲染策略:
|
||||
* - 同层同父:局部反显更新(旧选中恢复 + 新选中高亮)
|
||||
* - 新层级 >= 旧层级:补绘受影响层级
|
||||
* - 回退到更高层:整页刷新保证一致性
|
||||
* - 此策略可避免不必要的重绘,提升界面响应性能。
|
||||
*
|
||||
* 调用关系:
|
||||
* - 被 MenuPresenter_HandleInput() 在导航状态变化后调用(isFirstFrame = 0)
|
||||
* - 被外部初始化完成后首次调用(isFirstFrame = 1)
|
||||
* - 通过 presenter->refresh 函数指针绑定,符合 Presenter 的接口抽象。
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数假设 presenter 指针有效,不做空指针校验(由调用方保证)。
|
||||
* - view 接口的 full_refresh() 和内部渲染逻辑负责具体的绘制安全校验。
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void AppInfoPresenter_Refresh(appinfo_presenter_t *presenter)
|
||||
{
|
||||
presenter->view->show_top_name(presenter->model->topName);
|
||||
}
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPresenter_Init
|
||||
* 功能:
|
||||
* 初始化菜单 Presenter 实例,完成依赖绑定、对外接口挂接以及初始导航状态装配。
|
||||
*
|
||||
* 参数:
|
||||
* presenter - 待初始化的 Presenter 实例
|
||||
* model - 菜单 Model 实例,提供菜单树与运行时数据
|
||||
* view - 菜单 View 实例,提供刷新与绘制能力
|
||||
*
|
||||
* 边界处理:
|
||||
* - 若 `presenter`、`model` 或 `view` 任一为空,则直接返回。
|
||||
*
|
||||
* 说明:
|
||||
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
void AppInfoPresenter_Init(appinfo_presenter_t *presenter, appinfo_model_t *model, appinfo_view_t *view)
|
||||
{
|
||||
ASSERT((presenter == NULL) || (model == NULL) || (view == NULL));
|
||||
if ((presenter == NULL) || (model == NULL) || (view == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(presenter, 0, sizeof(*presenter));
|
||||
presenter->model = model;
|
||||
presenter->view = view;
|
||||
presenter->handle_input = AppInfoPresenter_HandleInput;
|
||||
presenter->refresh = AppInfoPresenter_Refresh;
|
||||
}
|
||||
18
src/Drv/pages/AppInfo/presenter.h
Normal file
18
src/Drv/pages/AppInfo/presenter.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef APPINFO_PRESENTER_H
|
||||
#define APPINFO_PRESENTER_H
|
||||
|
||||
#include "Drv/pages/AppInfo/model.h"
|
||||
#include "Drv/pages/AppInfo/view.h"
|
||||
|
||||
typedef struct appinfo_presenter_t appinfo_presenter_t;
|
||||
|
||||
struct appinfo_presenter_t
|
||||
{
|
||||
appinfo_model_t *model;
|
||||
appinfo_view_t *view;
|
||||
void (*handle_input)(appinfo_presenter_t *presenter, uint8_t keyVal);
|
||||
void (*refresh)(appinfo_presenter_t *presenter);
|
||||
};
|
||||
|
||||
void AppInfoPresenter_Init(appinfo_presenter_t *presenter, appinfo_model_t *model, appinfo_view_t *view);
|
||||
#endif
|
||||
97
src/Drv/pages/AppInfo/view.c
Normal file
97
src/Drv/pages/AppInfo/view.c
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
#include "Drv/pages/AppInfo/view.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* MSVC 对含多字节/中文格式串的静态分析可能误报 C4474/C4996。
|
||||
* 本文件内的格式化输出均为受控 buffer,并用于显示文本渲染。 */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4474)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
static const PageRenderPort *s_port = NULL;
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuView_DrawMeitou
|
||||
* 功能:
|
||||
* 绘制菜单标题装饰线(“眉头”样式):中间横线 + 左右两端斜线。
|
||||
*
|
||||
* 参数:
|
||||
* view - 菜单视图对象,提供底层渲染端口
|
||||
* yStart - 装饰线基准 Y 坐标(横线所在行)
|
||||
* width - 线宽参数(传递给 line_h/line)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数不做空指针判定,调用方需保证 view 与 s_port 有效。
|
||||
* - 坐标范围合法性由上层布局计算保证。
|
||||
*
|
||||
* 说明:
|
||||
* - 颜色统一使用字体前景色(get_color_font),确保装饰与文字风格一致。
|
||||
* - 绘制顺序:
|
||||
* 1) 中间横线(x:16~144)
|
||||
* 2) 左斜线(8, yStart-8 -> 16, yStart)
|
||||
* 3) 右斜线(144, yStart -> 152, yStart-8)
|
||||
* - 该函数用于视觉分隔与层次强调,不改变菜单状态数据。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void AppInfoView_DrawMeitou(uint16_t yStart, uint16_t width)
|
||||
{
|
||||
uint8_t fontColor = s_port->get_color_font();
|
||||
s_port->line_h(16, 144, yStart, width, fontColor);
|
||||
s_port->line(8, yStart - 8, 16, yStart, width, fontColor);
|
||||
s_port->line(144, yStart, 152, yStart - 8, width, fontColor);
|
||||
}
|
||||
|
||||
void AppInfoView_ShowInfoPage(uint16_t wPageNum, uint16_t wPageMax )
|
||||
{
|
||||
/* show_str 期望的是 '\0' 结尾的 UTF-8 字符串 */
|
||||
char pbyTips[64];
|
||||
uint16_t y = s_port->get_size_y() - 16;
|
||||
|
||||
/* 格式化字符串(用于 LCD 文本显示) */
|
||||
#if defined(_MSC_VER)
|
||||
(void)sprintf_s(pbyTips, sizeof(pbyTips), "第%4u 页 , 共%4u 页",
|
||||
(unsigned)wPageNum, (unsigned)wPageMax);
|
||||
#else
|
||||
(void)snprintf(pbyTips, sizeof(pbyTips), "第%4u 页 , 共%4u 页",
|
||||
(unsigned)wPageNum, (unsigned)wPageMax);
|
||||
#endif
|
||||
|
||||
s_port->show_str(6, y, (uint8_t *)pbyTips);
|
||||
}
|
||||
|
||||
void AppInfoView_ShowTerminalInfo(void)
|
||||
{
|
||||
uint8_t *context[] = {
|
||||
"终端类型 : F30",
|
||||
"终端型号 : F30",
|
||||
"软件版本 : SV0.010",
|
||||
"硬件版本 : HW0.010",
|
||||
"软件校验 : 4454",
|
||||
"程序日期 : 2024.08.27"
|
||||
};
|
||||
s_port->show_str(32, 26, "馈线自动化终端");
|
||||
for(uint8_t index = 0; index < 6; index++ )
|
||||
{
|
||||
s_port->show_str(6, 26 + (index + 1) * (s_port->get_ascii_height() + s_port->get_row_space()), context[index]);
|
||||
}
|
||||
}
|
||||
|
||||
void AppInfoView_ShowTopName(uint8_t *name)
|
||||
{
|
||||
uint16_t wLen = s_port->get_utf8_len(name) * s_port->get_ascii_width();
|
||||
|
||||
s_port->fill_rect(0, 0, s_port->get_size_x() - 1, s_port->get_size_y() - 1, s_port->get_color_back());
|
||||
/* 显示顶部名称,居中显示 */
|
||||
s_port->show_str((s_port->get_size_x() - wLen) / 2, 3, name);
|
||||
|
||||
AppInfoView_DrawMeitou(18, 2);
|
||||
AppInfoView_ShowInfoPage(10, 1);
|
||||
AppInfoView_ShowTerminalInfo();
|
||||
}
|
||||
void AppInfoView_Init(appinfo_view_t *view)
|
||||
{
|
||||
s_port = PageRenderer_Lcd();
|
||||
view->show_top_name = AppInfoView_ShowTopName;
|
||||
}
|
||||
17
src/Drv/pages/AppInfo/view.h
Normal file
17
src/Drv/pages/AppInfo/view.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef APPINFO_VIEW_H
|
||||
#define APPINFO_VIEW_H
|
||||
|
||||
#include "types.h"
|
||||
#include "Drv/pages/AppInfo/def.h"
|
||||
#include "Drv/pages/global/renderer_lcd.h"
|
||||
|
||||
typedef struct appinfo_view_t appinfo_view_t;
|
||||
|
||||
struct appinfo_view_t
|
||||
{
|
||||
void (*show_top_name)(uint8_t *name);
|
||||
};
|
||||
|
||||
void AppInfoView_Init(appinfo_view_t *view);
|
||||
|
||||
#endif
|
||||
@@ -4,31 +4,87 @@
|
||||
#include "lcd_draw.h"
|
||||
#include "lcd_text.h"
|
||||
|
||||
static unsigned short PageRenderer_LcdSizeX(void)
|
||||
static uint16_t PageRenderer_LcdSizeX(void)
|
||||
{
|
||||
return LCD_SIZE_X;
|
||||
}
|
||||
|
||||
static unsigned short PageRenderer_LcdSizeY(void)
|
||||
static uint16_t PageRenderer_LcdSizeY(void)
|
||||
{
|
||||
return LCD_SIZE_Y;
|
||||
}
|
||||
|
||||
static unsigned char PageRenderer_LcdColorFont(void)
|
||||
static uint8_t PageRenderer_LcdColorFont(void)
|
||||
{
|
||||
return LCD_FONT;
|
||||
}
|
||||
|
||||
static unsigned char PageRenderer_LcdColorBack(void)
|
||||
static uint8_t PageRenderer_LcdColorBack(void)
|
||||
{
|
||||
return LCD_BACK;
|
||||
}
|
||||
static uint16_t PageRenderer_LcdGetASCIIWidth(void)
|
||||
{
|
||||
return text_cfg.wASCIIFontWidth;
|
||||
}
|
||||
static uint16_t PageRenderer_LcdGetASCIIHeight(void)
|
||||
{
|
||||
return text_cfg.wASCIIFontHeight;
|
||||
}
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: PageRenderer_LcdGetUtf8Len
|
||||
* 功能:
|
||||
* 计算 UTF-8 字符串在当前菜单显示规则下的“显示宽度”。
|
||||
*
|
||||
* 参数:
|
||||
* str - 待计算的 UTF-8 字符串
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数不做空指针校验,调用方需保证 `str` 非空且为 `\0` 结尾。
|
||||
* - 依赖 `utf8_next()` 逐字符解析 UTF-8 编码;若输入非法,结果由底层解析行为决定。
|
||||
*
|
||||
* 说明:
|
||||
* - 当前显示规则约定:
|
||||
* 1) ASCII/单字节字符宽度记为 1
|
||||
* 2) 多字节 UTF-8 字符(如中文)宽度记为 2
|
||||
* - 本函数返回的是“显示占位宽度”,不是原始字节长度。
|
||||
* - 该结果会被菜单布局函数用于计算菜单框宽度与字符串显示长度。
|
||||
*
|
||||
* 返回值:
|
||||
* - UTF-8 字符串的显示宽度
|
||||
* ------------------------------------------------------------------------- */
|
||||
static uint16_t PageRenderer_LcdGetUtf8Len(uint8_t *str)
|
||||
{
|
||||
uint16_t strLen = 0;
|
||||
uint32_t unicode;
|
||||
uint8_t index = 0;
|
||||
uint8_t n = 0;
|
||||
|
||||
while (str[index] != '\0')
|
||||
{
|
||||
n = utf8_next(str + index, &unicode);
|
||||
strLen += (n > 1) ? 2 : 1;
|
||||
index += n;
|
||||
}
|
||||
return strLen;
|
||||
}
|
||||
static uint16_t PageRenderer_LcdGetRowSpace(void)
|
||||
{
|
||||
return text_cfg.rowSpace;
|
||||
}
|
||||
static void PageRenderer_ClearScreen(void)
|
||||
{
|
||||
Lcd_FillRect(0, 0, LCD_SIZE_X - 1, LCD_SIZE_Y - 1, LCD_BACK);
|
||||
}
|
||||
static const PageRenderPort g_lcd_port = {
|
||||
.get_size_x = PageRenderer_LcdSizeX,
|
||||
.get_size_y = PageRenderer_LcdSizeY,
|
||||
.get_ascii_width = PageRenderer_LcdGetASCIIWidth,
|
||||
.get_ascii_height = PageRenderer_LcdGetASCIIHeight,
|
||||
.get_color_font = PageRenderer_LcdColorFont,
|
||||
.get_color_back = PageRenderer_LcdColorBack,
|
||||
.get_utf8_len = PageRenderer_LcdGetUtf8Len,
|
||||
.get_row_space = PageRenderer_LcdGetRowSpace,
|
||||
.fill_rect = Lcd_FillRect,
|
||||
.line_h = Lcd_LineH,
|
||||
.line_v = Lcd_LineV,
|
||||
@@ -36,6 +92,7 @@ static const PageRenderPort g_lcd_port = {
|
||||
.set_pixel = Lcd_SetPixel,
|
||||
.invert = Lcd_Invert,
|
||||
.show_str = Lcd_ShowStr,
|
||||
.clear_screen = PageRenderer_ClearScreen,
|
||||
};
|
||||
|
||||
const PageRenderPort *PageRenderer_Lcd(void)
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
#ifndef PAGE_RENDERER_LCD_H
|
||||
#define PAGE_RENDERER_LCD_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short (*get_size_x)(void);
|
||||
unsigned short (*get_size_y)(void);
|
||||
unsigned char (*get_color_font)(void);
|
||||
unsigned char (*get_color_back)(void);
|
||||
signed char (*fill_rect)(unsigned short left_x, unsigned short top_y, unsigned short right_x, unsigned short bottom_y, unsigned int color);
|
||||
signed char (*line_h)(unsigned short x_start, unsigned short x_end, unsigned short y, unsigned short width, unsigned char color);
|
||||
signed char (*line_v)(unsigned short y_start, unsigned short y_end, unsigned short x, unsigned short width, unsigned char color);
|
||||
signed char (*line)(unsigned short x_start, unsigned short y_start, unsigned short x_end, unsigned short y_end, unsigned short width, unsigned char color);
|
||||
signed char (*set_pixel)(unsigned short x, unsigned short y, unsigned char color);
|
||||
signed char (*invert)(unsigned short left_x, unsigned short top_y, unsigned short right_x, unsigned short bottom_y);
|
||||
signed char (*show_str)(unsigned short x, unsigned short y, unsigned char *text);
|
||||
uint16_t (*get_size_x)(void);
|
||||
uint16_t (*get_size_y)(void);
|
||||
uint8_t (*get_color_font)(void);
|
||||
uint8_t (*get_color_back)(void);
|
||||
uint16_t (*get_ascii_width)(void);
|
||||
uint16_t (*get_ascii_height)(void);
|
||||
uint16_t (*get_utf8_len)(uint8_t *str);
|
||||
uint16_t (*get_row_space)(void);
|
||||
int8_t (*fill_rect)(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y, uint8_t color);
|
||||
int8_t (*line_h)(uint16_t x_start, uint16_t x_end, uint16_t y, uint16_t width, uint8_t color);
|
||||
int8_t (*line_v)(uint16_t y_start, uint16_t y_end, uint16_t x, uint16_t width, uint8_t color);
|
||||
int8_t (*line)(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t width, uint8_t color);
|
||||
int8_t (*set_pixel)(uint16_t x, uint16_t y, uint8_t color);
|
||||
int8_t (*invert)(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y);
|
||||
int8_t (*show_str)(uint16_t x, uint16_t y, uint8_t *text);
|
||||
int8_t (*clear_screen)(void);
|
||||
} PageRenderPort;
|
||||
|
||||
const PageRenderPort *PageRenderer_Lcd(void);
|
||||
|
||||
@@ -23,32 +23,6 @@ static menu_view_t s_view;
|
||||
static menu_presenter_t s_presenter;
|
||||
static page_t s_menuPage;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPage_OnEnter
|
||||
* 功能:
|
||||
* 页面进入回调:将菜单渲染标记为“首帧全量刷新”,并立即触发一次刷新。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数不依赖 page 内容,统一转为 (void)page 消除未使用告警。
|
||||
*
|
||||
* 说明:
|
||||
* - 通过 dspCtrl.bFirst = 1 告知 Presenter 下一次刷新走首帧路径。
|
||||
* - 进入页面后立即刷新,确保界面可见状态与内部状态同步。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void MenuPage_OnEnter(page_t *page)
|
||||
{
|
||||
(void)page;
|
||||
s_presenter.dspCtrl.bFirst = 1;
|
||||
MenuPresenter_Refresh(&s_presenter);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPage_OnExit
|
||||
* 功能:
|
||||
@@ -112,7 +86,7 @@ static void MenuPage_OnDestroy(page_t *page)
|
||||
* - keyVal 为 0 视为无效按键,返回 EVENT_UNHANDLED。
|
||||
*
|
||||
* 说明:
|
||||
* - 事件有效时调用 MenuPresenter_HandleInput() 执行业务输入流转。
|
||||
* - 事件有效时调用 Presenter 对外输入接口执行业务流转。
|
||||
* - 返回 EVENT_HANDLED,表示该事件已被菜单页消费,不再交给上层页面逻辑。
|
||||
*
|
||||
* 返回值:
|
||||
@@ -127,7 +101,7 @@ static event_result_t MenuPage_OnEvent(page_t *page, input_event_t *event)
|
||||
return EVENT_UNHANDLED;
|
||||
}
|
||||
|
||||
MenuPresenter_HandleInput(&s_presenter, event->keyVal);
|
||||
s_presenter.handle_input(&s_presenter, event->keyVal);
|
||||
return EVENT_HANDLED;
|
||||
}
|
||||
|
||||
@@ -152,7 +126,7 @@ static event_result_t MenuPage_OnEvent(page_t *page, input_event_t *event)
|
||||
static void MenuPage_OnLoop(page_t *page)
|
||||
{
|
||||
(void)page;
|
||||
MenuPresenter_Refresh(&s_presenter);
|
||||
s_presenter.refresh(&s_presenter, 0);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
@@ -200,6 +174,31 @@ static void MenuPage_OnCreate(page_t *page)
|
||||
s_menuPage.model = &s_model;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPage_OnEnter
|
||||
* 功能:
|
||||
* 页面进入回调:将菜单渲染标记为“首帧全量刷新”,并立即触发一次刷新。
|
||||
*
|
||||
* 参数:
|
||||
* page - 当前页面对象指针(本实现未直接使用)
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数不依赖 page 内容,统一转为 (void)page 消除未使用告警。
|
||||
*
|
||||
* 说明:
|
||||
* - 通过 refresh(..., 1) 告知 Presenter 下一次刷新走首帧路径。
|
||||
* - 进入页面后立即刷新,确保界面可见状态与内部状态同步。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void MenuPage_OnEnter(page_t *page)
|
||||
{
|
||||
(void)page;
|
||||
/* 首帧全量刷新 */
|
||||
s_presenter.refresh(&s_presenter, 1);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPage_GetInstance
|
||||
* 功能:
|
||||
@@ -231,25 +230,3 @@ page_t *MenuPage_GetInstance(void)
|
||||
s_menuPage.on_loop = MenuPage_OnLoop;
|
||||
return &s_menuPage;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPage_TriggerCurrentAction
|
||||
* 功能:
|
||||
* 触发当前菜单项动作的占位接口(当前版本仅输出调试日志)。
|
||||
*
|
||||
* 参数:
|
||||
* 无
|
||||
*
|
||||
* 边界处理:
|
||||
* - 当前实现不依赖外部输入,不涉及参数校验。
|
||||
*
|
||||
* 说明:
|
||||
* - 现阶段用于保留动作触发扩展点,后续可接入真实业务动作执行链路。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
void MenuPage_TriggerCurrentAction(void)
|
||||
{
|
||||
printf("MenuPage_TriggerCurrentAction\n");
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#ifndef MENU_PAGE_H
|
||||
#define MENU_PAGE_H
|
||||
|
||||
#include "view.h"
|
||||
#include "../page.h"
|
||||
|
||||
page_t *MenuPage_GetInstance(void);
|
||||
void MenuPage_TriggerCurrentAction(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,149 +5,256 @@
|
||||
|
||||
#include "../../key.h"
|
||||
|
||||
typedef struct
|
||||
/* -------------------------------------------------------------------------
|
||||
* 枚举名:MenuNavResult
|
||||
* 功能:
|
||||
* 菜单导航操作后的刷新结果状态指示器。用于 `MenuNavigator_ProcessKey()`
|
||||
* 函数返回值,标识按键操作是否导致菜单界面需要重新绘制。
|
||||
*
|
||||
* 成员说明:
|
||||
* MENU_NAV_NO_REFRESH (0) - 无刷新:
|
||||
* 表示当前按键操作未引起菜单焦点或层级状态的变化,
|
||||
* 或变化不足以触发界面重绘(例如 F1/F2 功能键、无效按键等)。
|
||||
* 调用方收到此值后不应执行额外的刷新操作。
|
||||
*
|
||||
* MENU_NAV_REFRESH (1) - 需刷新:
|
||||
* 表示当前按键操作导致菜单选中项或层级发生变化,
|
||||
* 需要重建导航路径并触发界面刷新以反映新的状态。
|
||||
*
|
||||
* 使用场景:
|
||||
* - `MenuNavigator_ProcessKey()` 根据按键类型和当前菜单状态计算是否需要刷新
|
||||
* - `MenuPresenter_HandleInput()` 根据返回值决定是否调用路由重建和刷新接口
|
||||
* - 返回值为 MENU_NAV_REFRESH 时,会触发:
|
||||
* 1) MenuNavigator_RebuildRoute() 重建当前导航路径 ptRoute[]
|
||||
* 2) Presenter->refresh() 执行界面增量或整页刷新
|
||||
*
|
||||
* 设计意图:
|
||||
* - 通过返回值区分"需刷新"和"无需刷新"两种状态,避免不必要的界面重绘
|
||||
* - 将导航计算与渲染决策分离,符合关注点分离原则
|
||||
* ------------------------------------------------------------------------- */
|
||||
typedef enum
|
||||
{
|
||||
tagPMenuItem ptHead;
|
||||
tagPMenuItem ptCurrent;
|
||||
tagPMenuItem ptRoute[4];
|
||||
tagPMenuItem ptCurBak;
|
||||
tagPMenuItem pt0Level;
|
||||
} MenuNavState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t needRefresh;
|
||||
uint8_t skipRenderThisRound;
|
||||
MENU_NAV_NO_REFRESH = 0, ///< 无需刷新:按键未引起菜单焦点/层级变化(如 F1/F2、无效按键)
|
||||
MENU_NAV_REFRESH = 1 ///< 需要刷新:按键导致选中项或层级改变,需重建路径并触发界面更新
|
||||
} MenuNavResult;
|
||||
|
||||
static MenuNavResult MenuNavigator_ProcessKey(MenuNavState *navState, uint8_t keyVal)
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名:MenuNavigator_ProcessKey
|
||||
* 功能:
|
||||
* 处理菜单导航按键,根据当前选中项和输入按键更新导航状态,并返回是否需要刷新界面。
|
||||
* 本函数是菜单导航的核心逻辑,负责解析各类按键(方向键、确认键、返回键等)并执行
|
||||
* 相应的菜单层级跳转和选中项变更操作。
|
||||
*
|
||||
* 参数:
|
||||
* menuCtrl - 菜单运行时控制上下文指针,包含当前选中项、路径数组、各级菜单节点引用等状态
|
||||
* keyVal - 输入按键值(来自 KEY_F1, KEY_F2, KEY_U, KEY_D, KEY_L, KEY_R, KEY_ENT, KEY_ESC 等)
|
||||
*
|
||||
* 返回值:
|
||||
* MenuNavResult - 导航结果枚举:
|
||||
* MENU_NAV_NO_REFRESH (0) - 无需刷新:按键未引起状态变化(如 F1/F2、未知按键)
|
||||
* MENU_NAV_REFRESH (1) - 需要刷新:选中项或层级发生变化,需触发界面更新
|
||||
*
|
||||
* 按键处理逻辑:
|
||||
* KEY_F1 / KEY_F2:
|
||||
* 功能键,当前不执行任何导航操作,仅占用一个 case 分支。
|
||||
*
|
||||
* KEY_U (Up - 上移):
|
||||
* 将选中项移动到前一项(ptCurrent->links.before),标记需要刷新界面。
|
||||
*
|
||||
* KEY_D (Down - 下移):
|
||||
* 将选中项移动到后一项(ptCurrent->links.behind),标记需要刷新界面。
|
||||
*
|
||||
* KEY_L (Left - 左移/返回上级):
|
||||
* 向左移动或返回上一级菜单:
|
||||
* 1) 根据当前层级从 ptRoute 数组获取对应层级的节点
|
||||
* 2) 若为 0 级菜单(byClass == 0):
|
||||
* - wPos == 1 时:向前跳过两个节点后下探到子级
|
||||
* - wPos != 1 时:向前一个节点后下探到子级
|
||||
* 3) 标记需要刷新界面。
|
||||
*
|
||||
* KEY_R / KEY_ENT (Right/Enter - 右移/确认):
|
||||
* 向右移动或进入子菜单:
|
||||
* a) 若当前项有子菜单(links.lower != NULL):
|
||||
* 下探到子菜单节点,标记需要刷新。
|
||||
* b) 否则若当前项绑定了窗口回调函数(pfnWinProc != NULL):
|
||||
* 直接执行该回调函数(如打开弹窗、启动新界面等)。
|
||||
*
|
||||
* KEY_ESC (Escape - 返回/退出):
|
||||
* 返回或退出菜单:
|
||||
* a) 若当前在 1 级菜单(byClass == 1):
|
||||
* 重置导航状态到初始根节点,快速返回顶层。
|
||||
* b) 否则:
|
||||
* 向上回退一级(ptRoute[byClass - 1]),标记需要刷新。
|
||||
*
|
||||
* default (未知按键):
|
||||
* 直接返回 MENU_NAV_NO_REFRESH,不执行任何操作。
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数假设 menuCtrl 指针有效,不做空指针校验(由调用方保证)。
|
||||
* - 在访问 ptCurrent->links.before/behind/lower/higher 等指针前,依赖菜单树结构的正确性。
|
||||
* - 对于子菜单为空或回调函数为 NULL 的情况有相应判断保护。
|
||||
*
|
||||
* 实现说明:
|
||||
* - 使用局部变量 ptCurrent、ptHead、ptRoute 缓存 menuCtrl 中的状态引用,避免多次解引用。
|
||||
* - needRefresh 标志用于累积本次按键操作是否需要刷新界面(默认 0,遇到有效导航操作后置为 1)。
|
||||
* - 函数末尾统一设置 menuCtrl->ptCurrent = ptCurrent 更新选中项,并根据 needRefresh 返回结果。
|
||||
* ------------------------------------------------------------------------- */
|
||||
static MenuNavResult MenuNavigator_ProcessKey(tagMenuCtrl *menuCtrl, uint8_t keyVal)
|
||||
{
|
||||
MenuNavResult result;
|
||||
tagPMenuItem ptCurrent;
|
||||
tagPMenuItem ptHead;
|
||||
tagPMenuItem *ptRoute;
|
||||
|
||||
result.needRefresh = 0;
|
||||
result.skipRenderThisRound = 0;
|
||||
|
||||
ptCurrent = navState->ptCurrent;
|
||||
ptHead = navState->ptHead;
|
||||
ptRoute = navState->ptRoute;
|
||||
uint8_t needRefresh = 0; /* < 刷新标志:1 表示需要刷新界面,0 表示无需刷新 */
|
||||
tagPMenuItem ptCurrent; /* < 当前选中菜单项指针(局部副本) */
|
||||
tagPMenuItem ptHead; /* < 菜单树根节点指针(局部副本) */
|
||||
tagPMenuItem *ptRoute; /* < 导航路径数组指针(局部副本,用于快速访问各级菜单节点) */
|
||||
|
||||
/* 缓存 menuCtrl 中的状态引用,避免多次解引用 */
|
||||
ptCurrent = menuCtrl->ptCurrent;
|
||||
ptHead = menuCtrl->ptHead;
|
||||
ptRoute = menuCtrl->ptRoute;
|
||||
switch (keyVal)
|
||||
{
|
||||
case KEY_F1:
|
||||
case KEY_F2:
|
||||
/* 功能键:当前不执行任何导航操作 */
|
||||
break;
|
||||
|
||||
case KEY_U:
|
||||
/* Up - 向上移动选中项到前一项 */
|
||||
ptCurrent = ptCurrent->links.before;
|
||||
result.needRefresh = 1;
|
||||
needRefresh = 1;
|
||||
break;
|
||||
|
||||
case KEY_D:
|
||||
/* Down - 向下移动选中项到后一项 */
|
||||
ptCurrent = ptCurrent->links.behind;
|
||||
result.needRefresh = 1;
|
||||
needRefresh = 1;
|
||||
break;
|
||||
|
||||
case KEY_L:
|
||||
/* Left 返回上一级菜单 */
|
||||
/* 由于 ptCurrent 不能为 0 级菜单,byClass - 1 必定大于 0 */
|
||||
ptCurrent = ptRoute[ptCurrent->menuDef.byClass - 1];
|
||||
/* 若当前项为 0 级菜单,则直接下探到子级 */
|
||||
if (ptCurrent->menuDef.byClass == 0)
|
||||
{
|
||||
if (ptCurrent->rect.wPos == 1)
|
||||
/*当前的逻辑是,每次都回到第一个0级菜单,然后下探到子级*/
|
||||
/* 0 级菜单的特殊处理:根据 wPos 决定向前跳过的节点数 */
|
||||
if (ptCurrent->rect.wPos == 0)
|
||||
{
|
||||
/* 只有两个 0级菜单,跳两次又回到自己 */
|
||||
ptCurrent = ptCurrent->links.before->links.before;
|
||||
}
|
||||
else
|
||||
else /* 若 wPos != 1,则向前跳过一个节点 */
|
||||
{
|
||||
ptCurrent = ptCurrent->links.before;
|
||||
}
|
||||
ptCurrent = ptCurrent->links.lower;
|
||||
}
|
||||
result.needRefresh = 1;
|
||||
needRefresh = 1;
|
||||
break;
|
||||
|
||||
case KEY_R:
|
||||
case KEY_ENT:
|
||||
/* Right/Enter - 向右移动或进入子菜单 */
|
||||
if (ptCurrent->links.lower != NULL)
|
||||
{
|
||||
/* 有子菜单:下探到子级节点 */
|
||||
ptCurrent = ptCurrent->links.lower;
|
||||
result.needRefresh = 1;
|
||||
needRefresh = 1;
|
||||
}
|
||||
else if (ptCurrent->menuDef.pfnWinProc != NULL)
|
||||
{
|
||||
/* 无子菜单但有回调函数:执行窗口回调(如打开弹窗) */
|
||||
ptCurrent->menuDef.pfnWinProc();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_ESC:
|
||||
/* Escape - 返回或退出菜单 */
|
||||
if (ptCurrent->menuDef.byClass == 1)
|
||||
{
|
||||
navState->pt0Level = ptHead;
|
||||
navState->ptRoute[0] = ptHead;
|
||||
navState->ptCurrent = ptHead->links.lower;
|
||||
navState->ptCurBak = navState->ptCurrent;
|
||||
navState->ptRoute[1] = navState->ptCurrent;
|
||||
result.skipRenderThisRound = 1;
|
||||
return result;
|
||||
/* 在 1 级菜单:快速重置到根节点状态 */
|
||||
/* 强制整页刷新:避免 invert 反显状态残留叠加 */
|
||||
menuCtrl->pt0Level = NULL;
|
||||
menuCtrl->ptRoute[0] = ptHead;
|
||||
menuCtrl->ptCurrent = ptHead->links.lower;
|
||||
menuCtrl->ptCurBak = menuCtrl->ptCurrent;
|
||||
menuCtrl->ptRoute[1] = menuCtrl->ptCurrent;
|
||||
return MENU_NAV_REFRESH;
|
||||
}
|
||||
/* 在其他层级:向上回退一级 */
|
||||
ptCurrent = ptRoute[ptCurrent->menuDef.byClass - 1];
|
||||
result.needRefresh = 1;
|
||||
needRefresh = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
/* 未知按键:不执行任何操作,返回无需刷新 */
|
||||
return MENU_NAV_NO_REFRESH;
|
||||
}
|
||||
|
||||
navState->ptCurrent = ptCurrent;
|
||||
return result;
|
||||
/* 更新选中项状态 */
|
||||
menuCtrl->ptCurrent = ptCurrent;
|
||||
/* 根据刷新标志返回结果 */
|
||||
return needRefresh ? MENU_NAV_REFRESH : MENU_NAV_NO_REFRESH;
|
||||
}
|
||||
|
||||
static void MenuNavigator_RebuildRoute(MenuNavState *navState, uint32_t maxItem)
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuNavigator_RebuildRoute
|
||||
* 功能:
|
||||
* 根据当前选中菜单项,向上回溯父链并重建当前菜单路径 `ptRoute[]`。
|
||||
*
|
||||
* 参数:
|
||||
* menuCtrl - 菜单运行时控制上下文,内部保存当前选中项与路径数组
|
||||
* maxItem - 最大回溯次数上限,用于防止异常链路导致死循环
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数不做空指针校验,默认由调用链保证 `menuCtrl` 有效。
|
||||
* - 若 `ptCurBak == ptCurrent`,说明当前选中项未发生变化,直接返回。
|
||||
* - 使用 `maxItem` 作为保护上限,避免异常菜单链表造成无限回溯。
|
||||
*
|
||||
* 说明:
|
||||
* - 重建流程如下:
|
||||
* 1) 从当前选中项 `ptCurrent` 出发
|
||||
* 2) 若当前节点没有父节点,说明到达 0 级菜单链,沿 `before` 回退到根上下文
|
||||
* 3) 若存在父节点,则沿 `higher` 向上回溯,并把对应层级节点写入 `ptRoute[level]`
|
||||
* 4) 当回溯到 `byClass == 0` 的节点时结束
|
||||
* 5) 最后把当前选中节点重新写回 `ptRoute[当前层级]`
|
||||
* - 该函数的作用是让 `ptRoute[]` 始终准确反映“从顶层到当前焦点”的完整路径,
|
||||
* 供后续 View 刷新和层级定位使用。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void MenuNavigator_RebuildRoute(tagMenuCtrl *menuCtrl, uint32_t maxItem)
|
||||
{
|
||||
tagPMenuItem ptIndex;
|
||||
|
||||
if (navState->ptCurBak == navState->ptCurrent)
|
||||
/* 若当前选中项未发生变化,则直接返回 */
|
||||
if (menuCtrl->ptCurBak == menuCtrl->ptCurrent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ptIndex = navState->ptCurrent;
|
||||
ptIndex = menuCtrl->ptCurrent;
|
||||
for (uint32_t index = 0; index < maxItem; index++)
|
||||
{
|
||||
/* 若当前节点没有父节点,则沿 `before` 回退到根上下文 */
|
||||
if (ptIndex->links.higher == NULL)
|
||||
{
|
||||
ptIndex = ptIndex->links.before;
|
||||
}
|
||||
else
|
||||
else /* 若存在父节点,则沿 `higher` 向上回溯,并把对应层级节点写入 `ptRoute[level]` */
|
||||
{
|
||||
ptIndex = ptIndex->links.higher;
|
||||
navState->ptRoute[ptIndex->menuDef.byClass] = ptIndex;
|
||||
menuCtrl->ptRoute[ptIndex->menuDef.byClass] = ptIndex;
|
||||
}
|
||||
/* 当回溯到 `byClass == 0` 的节点时结束 */
|
||||
if (ptIndex->menuDef.byClass == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
navState->ptRoute[navState->ptCurrent->menuDef.byClass] = navState->ptCurrent;
|
||||
}
|
||||
|
||||
static void MenuPresenter_FillNavState(const tagMenuCtrl *ctrl, MenuNavState *nav)
|
||||
{
|
||||
nav->ptHead = ctrl->ptHead;
|
||||
nav->ptCurrent = ctrl->ptCurrent;
|
||||
nav->ptRoute[0] = ctrl->ptRoute[0];
|
||||
nav->ptRoute[1] = ctrl->ptRoute[1];
|
||||
nav->ptRoute[2] = ctrl->ptRoute[2];
|
||||
nav->ptRoute[3] = ctrl->ptRoute[3];
|
||||
nav->ptCurBak = ctrl->ptCurBak;
|
||||
nav->pt0Level = ctrl->pt0Level;
|
||||
}
|
||||
|
||||
static void MenuPresenter_ApplyNavState(tagMenuCtrl *ctrl, const MenuNavState *nav)
|
||||
{
|
||||
ctrl->ptHead = nav->ptHead;
|
||||
ctrl->ptCurrent = nav->ptCurrent;
|
||||
ctrl->ptRoute[0] = nav->ptRoute[0];
|
||||
ctrl->ptRoute[1] = nav->ptRoute[1];
|
||||
ctrl->ptRoute[2] = nav->ptRoute[2];
|
||||
ctrl->ptRoute[3] = nav->ptRoute[3];
|
||||
ctrl->ptCurBak = nav->ptCurBak;
|
||||
ctrl->pt0Level = nav->pt0Level;
|
||||
/* 最后把当前选中节点重新写回 `ptRoute[当前层级]` */
|
||||
menuCtrl->ptRoute[menuCtrl->ptCurrent->menuDef.byClass] = menuCtrl->ptCurrent;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
@@ -177,7 +284,7 @@ static void MenuPresenter_ApplyNavState(tagMenuCtrl *ctrl, const MenuNavState *n
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void MenuPresenter_RenderByState(MenuPresenter *presenter)
|
||||
static void MenuPresenter_RenderByState(menu_presenter_t *presenter)
|
||||
{
|
||||
tagMenuCtrl *menuCtrl = &presenter->menuCtrl;
|
||||
MenuView *view = presenter->view;
|
||||
@@ -208,15 +315,150 @@ static void MenuPresenter_RenderByState(MenuPresenter *presenter)
|
||||
}
|
||||
}
|
||||
|
||||
void MenuPresenter_Init(MenuPresenter *presenter, menu_model_t *model, menu_view_t *view)
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名:MenuPresenter_Refresh
|
||||
* 功能:
|
||||
* Presenter 层的对外刷新接口,根据是否为首帧渲染选择不同的刷新策略。
|
||||
* 本函数作为 menu_presenter_t::refresh 回调被调用,负责协调 View 层完成界面更新。
|
||||
*
|
||||
* 参数:
|
||||
* presenter - 菜单 Presenter 实例指针,内部持有 menuCtrl 上下文和 view 接口引用
|
||||
* isFirstFrame - 是否为首帧标志:
|
||||
* 1 - 首帧渲染:需要完整初始化并刷新整个菜单界面
|
||||
* 0 - 非首帧渲染:根据当前状态差异进行增量或局部刷新
|
||||
*
|
||||
* 刷新策略:
|
||||
* 首帧模式 (isFirstFrame == 1):
|
||||
* - 调用 View 层的 full_refresh() 接口,完整重绘整个菜单界面。
|
||||
* - 此时 menuCtrl 中的导航路径、选中项等状态已完成初始化,可安全进行全量渲染。
|
||||
* - MODE_NONE 表示不进行特殊模式过滤(如调试模式、特定层级过滤等)。
|
||||
*
|
||||
* 非首帧模式 (isFirstFrame == 0):
|
||||
* - 调用 MenuPresenter_RenderByState() 进行智能状态对比刷新:
|
||||
* 1) 比较 pt0Level 与 ptRoute[0],判断顶层上下文是否切换
|
||||
* 2) 比较 ptCurBak 与 ptCurrent,判断选中项是否变化
|
||||
* 3) 根据层级关系和父节点关联选择最优渲染策略:
|
||||
* - 同层同父:局部反显更新(旧选中恢复 + 新选中高亮)
|
||||
* - 新层级 >= 旧层级:补绘受影响层级
|
||||
* - 回退到更高层:整页刷新保证一致性
|
||||
* - 此策略可避免不必要的重绘,提升界面响应性能。
|
||||
*
|
||||
* 调用关系:
|
||||
* - 被 MenuPresenter_HandleInput() 在导航状态变化后调用(isFirstFrame = 0)
|
||||
* - 被外部初始化完成后首次调用(isFirstFrame = 1)
|
||||
* - 通过 presenter->refresh 函数指针绑定,符合 Presenter 的接口抽象。
|
||||
*
|
||||
* 边界处理:
|
||||
* - 本函数假设 presenter 指针有效,不做空指针校验(由调用方保证)。
|
||||
* - view 接口的 full_refresh() 和内部渲染逻辑负责具体的绘制安全校验。
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void MenuPresenter_Refresh(menu_presenter_t *presenter, uint8_t isFirstFrame)
|
||||
{
|
||||
presenter->dspCtrl.bFirst = 0;
|
||||
if (isFirstFrame)
|
||||
{
|
||||
/* 首帧模式:完整重绘整个菜单界面 */
|
||||
presenter->view->full_refresh(presenter->view, &presenter->menuCtrl, MODE_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 非首帧模式:根据状态差异进行智能增量刷新 */
|
||||
MenuPresenter_RenderByState(presenter);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPresenter_HandleInput
|
||||
* 功能:
|
||||
* 处理菜单页输入按键,驱动导航状态更新,并在需要时触发路由重建与界面刷新。
|
||||
*
|
||||
* 参数:
|
||||
* presenter - 菜单 Presenter 实例,内部持有导航控制状态与 Model/View 依赖
|
||||
* keyVal - 当前输入按键值
|
||||
*
|
||||
* 边界处理:
|
||||
* - 若 `presenter == NULL`,则直接返回。
|
||||
* - 若 `keyVal == KEY_NONE`,则直接返回。
|
||||
* - 若按键不引起状态变化,`MenuNavigator_ProcessKey()` 会返回
|
||||
* `MENU_NAV_NO_REFRESH`,本函数直接结束,不触发额外刷新。
|
||||
*
|
||||
* 说明:
|
||||
* - 处理流程如下:
|
||||
* 1) 调用 `MenuNavigator_ProcessKey()`,根据按键更新 `menuCtrl` 中的当前选中项
|
||||
* 与必要的路径状态
|
||||
* 2) 若返回值为 `MENU_NAV_REFRESH`,说明本次输入导致菜单焦点或层级发生变化
|
||||
* 3) 调用 `MenuNavigator_RebuildRoute()` 重建当前路径 `ptRoute[]`
|
||||
* 4) 调用 Presenter 对外刷新接口 `refresh(..., 0)`,执行增量或整页刷新判定
|
||||
* - 本函数本身不直接绘制界面,而是负责把“输入 -> 导航状态变化 -> 刷新请求”
|
||||
* 串联起来。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
static void MenuPresenter_HandleInput(menu_presenter_t *presenter, uint8_t keyVal)
|
||||
{
|
||||
MenuNavResult navResult;
|
||||
|
||||
ASSERT(presenter == NULL);
|
||||
if (presenter == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyVal == KEY_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
navResult = MenuNavigator_ProcessKey(&presenter->menuCtrl, keyVal);
|
||||
|
||||
if (navResult == MENU_NAV_REFRESH)
|
||||
{
|
||||
MenuNavigator_RebuildRoute(&presenter->menuCtrl, presenter->model->maxItem);
|
||||
presenter->refresh(presenter, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: MenuPresenter_Init
|
||||
* 功能:
|
||||
* 初始化菜单 Presenter 实例,完成依赖绑定、对外接口挂接以及初始导航状态装配。
|
||||
*
|
||||
* 参数:
|
||||
* presenter - 待初始化的 Presenter 实例
|
||||
* model - 菜单 Model 实例,提供菜单树与运行时数据
|
||||
* view - 菜单 View 实例,提供刷新与绘制能力
|
||||
*
|
||||
* 边界处理:
|
||||
* - 若 `presenter`、`model` 或 `view` 任一为空,则直接返回。
|
||||
*
|
||||
* 说明:
|
||||
* - 初始化步骤如下:
|
||||
* 1) 清零 `menuCtrl`,避免历史状态残留
|
||||
* 2) 绑定 `model` / `view` 依赖
|
||||
* 3) 绑定 Presenter 对外接口 `handle_input` / `refresh`
|
||||
* 4) 将 `ptHead` 指向菜单树根节点
|
||||
* 5) 将 `ptCurrent` 初始化为根节点的首个子菜单
|
||||
* 6) 初始化 `ptCurBak` 与 `ptRoute[0..3]`,建立首帧导航路径
|
||||
* - 该函数只负责 Presenter 状态装配,不触发实际刷新。
|
||||
*
|
||||
* 返回值:
|
||||
* - 无
|
||||
* ------------------------------------------------------------------------- */
|
||||
void MenuPresenter_Init(menu_presenter_t *presenter, menu_model_t *model, menu_view_t *view)
|
||||
{
|
||||
ASSERT((presenter == NULL) || (model == NULL) || (view == NULL));
|
||||
if ((presenter == NULL) || (model == NULL) || (view == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&presenter->menuCtrl, 0, sizeof(presenter->menuCtrl));
|
||||
presenter->model = model;
|
||||
presenter->view = view;
|
||||
presenter->handle_input = MenuPresenter_HandleInput;
|
||||
presenter->refresh = MenuPresenter_Refresh;
|
||||
|
||||
|
||||
presenter->dspCtrl.bFirst = 1;
|
||||
presenter->menuCtrl.ptHead = &presenter->model->menuItems[0];
|
||||
presenter->menuCtrl.pt0Level = &presenter->model->menuItems[0];
|
||||
presenter->menuCtrl.ptCurrent = presenter->menuCtrl.ptHead->links.lower;
|
||||
@@ -227,46 +469,3 @@ void MenuPresenter_Init(MenuPresenter *presenter, menu_model_t *model, menu_view
|
||||
presenter->menuCtrl.ptRoute[2] = presenter->menuCtrl.ptCurrent;
|
||||
presenter->menuCtrl.ptRoute[3] = presenter->menuCtrl.ptCurrent;
|
||||
}
|
||||
|
||||
void MenuPresenter_Refresh(MenuPresenter *presenter)
|
||||
{
|
||||
if (presenter->dspCtrl.bFirst)
|
||||
{
|
||||
presenter->dspCtrl.bFirst = 0;
|
||||
presenter->view->full_refresh(presenter->view, &presenter->menuCtrl, MODE_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
MenuPresenter_RenderByState(presenter);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuPresenter_HandleInput(MenuPresenter *presenter, uint8_t keyVal)
|
||||
{
|
||||
MenuNavState navState;
|
||||
MenuNavResult navResult;
|
||||
|
||||
if (presenter->dspCtrl.bFirst)
|
||||
{
|
||||
MenuPresenter_Refresh(presenter);
|
||||
return;
|
||||
}
|
||||
|
||||
MenuPresenter_FillNavState(&presenter->menuCtrl, &navState);
|
||||
navResult = MenuNavigator_ProcessKey(&navState, keyVal);
|
||||
MenuPresenter_ApplyNavState(&presenter->menuCtrl, &navState);
|
||||
|
||||
if (navResult.skipRenderThisRound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (navResult.needRefresh)
|
||||
{
|
||||
MenuNavState rebuildState;
|
||||
MenuPresenter_FillNavState(&presenter->menuCtrl, &rebuildState);
|
||||
MenuNavigator_RebuildRoute(&rebuildState, presenter->model->maxItem);
|
||||
MenuPresenter_ApplyNavState(&presenter->menuCtrl, &rebuildState);
|
||||
MenuPresenter_Refresh(presenter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,27 +7,37 @@
|
||||
|
||||
typedef struct menu_presenter_t menu_presenter_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bFirst;
|
||||
} tagDspCtrl;
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 结构体名: menu_presenter_t
|
||||
* 功能:
|
||||
* 菜单页面 Presenter 层对象,负责衔接输入事件、菜单导航状态与 View 刷新行为。
|
||||
*
|
||||
* 字段说明:
|
||||
* menuCtrl - 菜单运行时控制上下文,保存当前选中项、路径与刷新相关状态
|
||||
* model - 菜单 Model 实例,提供菜单树与运行时数据访问
|
||||
* view - 菜单 View 实例,提供界面刷新与绘制能力
|
||||
* handle_input - Presenter 对外输入接口,负责处理按键并驱动导航状态变化
|
||||
* refresh - Presenter 对外刷新接口,负责按当前状态触发界面刷新
|
||||
*
|
||||
* 说明:
|
||||
* - Presenter 位于 Model 与 View 之间:
|
||||
* 1) 从页面层接收输入事件
|
||||
* 2) 更新 `menuCtrl` 中的导航状态
|
||||
* 3) 根据状态变化调用 View 接口完成局部或整页刷新
|
||||
* - 函数指针在 `MenuPresenter_Init()` 中完成绑定。
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
struct menu_presenter_t
|
||||
{
|
||||
tagDspCtrl dspCtrl;
|
||||
tagMenuCtrl menuCtrl;
|
||||
menu_model_t *model;
|
||||
menu_view_t *view;
|
||||
void (*handle_input)(struct menu_presenter_t *self, uint8_t keyVal);
|
||||
void (*refresh)(struct menu_presenter_t *self, uint8_t isFirstFrame);
|
||||
};
|
||||
|
||||
typedef menu_presenter_t MenuPresenter;
|
||||
|
||||
void MenuPresenter_Init(MenuPresenter *presenter,
|
||||
void MenuPresenter_Init(menu_presenter_t *presenter,
|
||||
menu_model_t *model,
|
||||
menu_view_t *view);
|
||||
|
||||
void MenuPresenter_HandleInput(MenuPresenter *presenter, uint8_t keyVal);
|
||||
void MenuPresenter_Refresh(MenuPresenter *presenter);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -265,7 +265,7 @@ static void MenuView_FullRefresh(MenuView *view, const tagMenuCtrl *menuCtrl, Me
|
||||
uint8_t backColor = s_port->get_color_back();
|
||||
uint16_t lcdSizeX = s_port->get_size_x();
|
||||
|
||||
s_port->fill_rect(0, MENU_YMIN, lcdSizeX - 1, MENU_YMAX, backColor);
|
||||
s_port->fill_rect(0, MENU_YMIN, (uint16_t)(lcdSizeX - 1), MENU_YMAX, backColor);
|
||||
|
||||
MenuView_ShowTopLevel(view, mode);
|
||||
for (uint8_t index = 0; index < menuCtrl->ptCurrent->menuDef.byClass; index++)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 取值说明:
|
||||
* PAGE_ID_NONE - 无效页面 ID / 未初始化占位值
|
||||
* PAGE_ID_MENU - 菜单页 ID(当前主运行页)
|
||||
* PAGE_ID_APP_INFO - 预留页面 ID(当前版本可注册与否由上层决定)
|
||||
* PAGE_ID_APP_INFO - 装置信息页 ID(在 main 中与菜单页一并注册)
|
||||
* PAGE_ID_MAX - 上界哨兵,不可作为有效页面 ID 使用
|
||||
*
|
||||
* 使用约束:
|
||||
@@ -21,7 +21,7 @@ typedef enum
|
||||
{
|
||||
PAGE_ID_NONE = 0,
|
||||
PAGE_ID_MENU = 1,
|
||||
PAGE_ID_APP_INFO = 2, /* 预留ID:当前版本未注册运行 */
|
||||
PAGE_ID_APP_INFO = 2, /* 装置信息页:AppInfoPage_GetInstance */
|
||||
PAGE_ID_MAX
|
||||
} page_id_t;
|
||||
|
||||
|
||||
@@ -232,12 +232,13 @@ page_manager_result_t PageManager_Push(page_t *newPage)
|
||||
/* 重复导航到当前页面:按幂等处理 */
|
||||
return PAGE_MANAGER_OK;
|
||||
}
|
||||
ASSERT((currentTop != NULL) && (currentTop->on_exit != NULL));
|
||||
/* 调用旧页的 on_exit 回调 */
|
||||
if ((currentTop != NULL) && (currentTop->on_exit != NULL))
|
||||
{
|
||||
currentTop->on_exit(currentTop);
|
||||
}
|
||||
|
||||
/* 将新页压入栈 */
|
||||
s_pageManager.stack_top++;
|
||||
s_pageManager.page_stack[s_pageManager.stack_top] = newPage;
|
||||
|
||||
@@ -294,7 +295,6 @@ page_manager_result_t PageManager_Pop(void)
|
||||
}
|
||||
|
||||
currentPage = s_pageManager.page_stack[s_pageManager.stack_top];
|
||||
ASSERT((currentPage != NULL) && (currentPage->on_exit != NULL));
|
||||
if ((currentPage != NULL) && (currentPage->on_exit != NULL))
|
||||
{
|
||||
currentPage->on_exit(currentPage);
|
||||
@@ -314,14 +314,12 @@ page_manager_result_t PageManager_Pop(void)
|
||||
s_pageManager.stack_top--;
|
||||
|
||||
newTop = s_pageManager.page_stack[s_pageManager.stack_top];
|
||||
ASSERT((newTop != NULL) && (newTop->on_enter != NULL));
|
||||
if ((newTop != NULL) && (newTop->on_enter != NULL))
|
||||
{
|
||||
newTop->on_enter(newTop);
|
||||
}
|
||||
return PAGE_MANAGER_OK;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: PageManager_Navigate
|
||||
* 功能:
|
||||
@@ -358,6 +356,88 @@ page_manager_result_t PageManager_Navigate(page_id_t pageId)
|
||||
return PageManager_Push(target);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: PageManager_Replace
|
||||
* 功能:
|
||||
* 页面替换接口:用目标页面替换当前栈顶页面,不增加栈深。
|
||||
*
|
||||
* 参数:
|
||||
* pageId - 目标页面标识
|
||||
*
|
||||
* 边界处理:
|
||||
* - 若目标页未注册,返回 PAGE_MANAGER_ERR_NOT_FOUND。
|
||||
* - 若当前无活动页(空栈),退化为 Push 目标页。
|
||||
* - 若目标页与当前栈顶同一 page_id,按幂等处理返回 PAGE_MANAGER_OK。
|
||||
*
|
||||
* 说明:
|
||||
* - 生命周期顺序:
|
||||
* 1) 当前页 on_exit
|
||||
* 2) 若当前页非缓存且实现 on_destroy,则销毁并清 is_created
|
||||
* 3) 栈顶指针替换为目标页
|
||||
* 4) 目标页必要时 on_create(首次)+ on_enter
|
||||
*
|
||||
* 返回值:
|
||||
* - PAGE_MANAGER_OK : 替换成功
|
||||
* - PAGE_MANAGER_ERR_NOT_FOUND : 未找到目标页面
|
||||
* - PAGE_MANAGER_ERR_STACK_FULL : 空栈退化 Push 且栈满(透传)
|
||||
* ------------------------------------------------------------------------- */
|
||||
page_manager_result_t PageManager_Replace(page_id_t pageId)
|
||||
{
|
||||
page_t *target;
|
||||
page_t *currentTop;
|
||||
|
||||
target = PageManager_Find(pageId);
|
||||
ASSERT(target == NULL);
|
||||
if (target == NULL)
|
||||
{
|
||||
return PAGE_MANAGER_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
currentTop = PageManager_GetTop();
|
||||
if (currentTop == NULL)
|
||||
{
|
||||
/* 空栈场景:替换退化为压栈导航 */
|
||||
return PageManager_Push(target);
|
||||
}
|
||||
|
||||
if (currentTop->page_id == target->page_id)
|
||||
{
|
||||
return PAGE_MANAGER_OK;
|
||||
}
|
||||
|
||||
if (currentTop->on_exit != NULL)
|
||||
{
|
||||
currentTop->on_exit(currentTop);
|
||||
}
|
||||
|
||||
if (!currentTop->is_cached)
|
||||
{
|
||||
if (currentTop->on_destroy != NULL)
|
||||
{
|
||||
currentTop->on_destroy(currentTop);
|
||||
}
|
||||
currentTop->is_created = 0;
|
||||
}
|
||||
|
||||
s_pageManager.page_stack[s_pageManager.stack_top] = target;
|
||||
|
||||
if (!target->is_created)
|
||||
{
|
||||
if (target->on_create != NULL)
|
||||
{
|
||||
target->on_create(target);
|
||||
}
|
||||
target->is_created = 1;
|
||||
}
|
||||
|
||||
if (target->on_enter != NULL)
|
||||
{
|
||||
target->on_enter(target);
|
||||
}
|
||||
|
||||
return PAGE_MANAGER_OK;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* 函数名: PageManager_DispatchEvent
|
||||
* 功能:
|
||||
|
||||
@@ -66,6 +66,7 @@ typedef enum
|
||||
void PageManager_Init(void);
|
||||
page_manager_result_t PageManager_Register(page_t *page);
|
||||
page_manager_result_t PageManager_Navigate(page_id_t pageId);
|
||||
page_manager_result_t PageManager_Replace(page_id_t pageId);
|
||||
page_manager_result_t PageManager_DispatchEvent(input_event_t *event);
|
||||
|
||||
page_t *PageManager_GetTop(void);
|
||||
|
||||
@@ -31,6 +31,7 @@ static int getch(void)
|
||||
#endif
|
||||
|
||||
#include "Drv/pages/page_manager.h"
|
||||
#include "Drv/pages/AppInfo/page.h"
|
||||
#include "Drv/pages/menu/page.h"
|
||||
#include "TCP/tcp.h"
|
||||
#include "remoteDisplay.h"
|
||||
@@ -69,6 +70,7 @@ int main(void)
|
||||
PageManager_Init();
|
||||
Lcd_Init(); /* 初始化屏幕显存:由入口统一完成 */
|
||||
(void)PageManager_Register(MenuPage_GetInstance());
|
||||
(void)PageManager_Register(AppInfoPage_GetInstance());
|
||||
(void)PageManager_Navigate(PAGE_ID_MENU);
|
||||
Key_Init(); /* 初始化按键 */
|
||||
printf("PC 端 HMI 菜单模拟启动(TCP 服务在单独线程,端口 7003)。\n");
|
||||
|
||||
@@ -96,6 +96,7 @@ add_dtu_test(
|
||||
test_p1_menu
|
||||
test_p1_menu.c
|
||||
"${CMAKE_SOURCE_DIR}/src/Drv/menu/app/menu.c"
|
||||
"${CMAKE_SOURCE_DIR}/src/Drv/pages/page_manager.c"
|
||||
"${CMAKE_SOURCE_DIR}/src/Drv/pages/menu/model.c"
|
||||
"${CMAKE_SOURCE_DIR}/src/Drv/pages/menu/view.c"
|
||||
"${CMAKE_SOURCE_DIR}/src/Drv/pages/menu/presenter.c"
|
||||
|
||||
Reference in New Issue
Block a user