重构(UI): 统一组件协议 + 去手写链路 + 大文件按职责拆分 + 代码审查 + 剥离 Tools
## 1. 新增 UiComponent 顶层组件协议(不是负优化)
Components/Shared/Inc/UiComponent.hpp:纯接口、无状态,8 个方法
SetScale / Layout / Area / Paint / HitTest / OnMouseLeave / IsEditing / QueryCursor。
Toolbar / TabBar / SignalPanel / PlotView 本来就各自拥有完全同名同签名的成员,
因此改造 = 加 override + 补 Area()(PlotView 另加一个非 const 的 QueryCursor 转发,
因为它自己的查询会惰性建立行缓存),实现代码零改动、静态派发、体积无增长。
刻意不把 UiWidget 当作它的基类:UiWidget 是"树节点"(父给尺寸、父下探脏区、
命中沿树链派发),而 PlotView(4 层位图缓存)/ SignalPanel(行位图缓存)是
"地盘宿主"。强行上树会推翻"父脏则子全脏"的前提,历史上正是这类耦合导致过
"后台渲染覆盖平移结果""命中矩形错位"的事故。头文件里已写明这条理由。
Toolbar/TabBar 是两者的交集:对外实现 UiComponent,对内持有一棵 UiWidget 树。
## 2. 宿主侧:四条手写链 -> 组件表
Application 新增 ComponentEntry{ component, target, chrome } 与 m_components
(底->顶:plot -> panel -> toolbar -> tabBar),BuildComponentTable() 装配一次。
- ApplyDpi 6 行逐个 SetScale -> 1 个循环
- Relayout 手算三列 x 坐标 -> UiStackRects(内容区, HORIZONTAL, {panelW, splitW, AUTO})
- WM_MOUSELEAVE 逐个 OnMouseLeave -> 循环累积 chromeChanged / plotChanged
- WM_SETCURSOR if/else if 链 -> 从表尾向前找首个命中者,取其 QueryCursor
顺带兑现历史缺口:UiLayout::UiStackRects 自引入以来第一次有了生产调用点。
有意保留显式的三条链(WM_LBUTTONDOWN / WM_LBUTTONUP / WM_MOUSEMOVE):它们各自带
组件专属后置动作(提交重命名、构建派生信号、面板联动滚动、更新拖拽光标、
plotOnlyMove 决定局部失效还是整帧失效)。塞进表里只能靠 lambda 字段,
可读性反而下降 —— 属于用户明确禁止的"过度抽象",因此不做。
## 3. 大文件按职责拆分(纯整函数搬移,逐像素 0 差异)
SignalPanelInteraction.cpp 2329 -> 831 行,拆出:
SignalPanelEdit.cpp 616 内联编辑(筛选框、组名/信号名、数值、颜色与透明度)
SignalPanelScroll.cpp 205 动画与滚动(折起、联动滚动、滚动到目标信号)
SignalPanelMenu.cpp 527 弹出菜单(系数/偏移、镜像、右键菜单与命令回执)
Shared/PopupMenu.cpp 1901 -> 706 行,拆出:
PopupMenuLayout.cpp 753 尺寸测量、项矩形排版、滚动可见性
PopupMenuPaint.cpp 397 背景/阴影/项绘制
Inc/PopupMenuInternal.hpp 103 pmdetail 常量 + inline 辅助(跨 TU 安全)
拆分判据是"职责"而非行数;共享常量一律收敛到 *Internal.hpp。
## 4. 代码审查(修 5 处)
- SignalPanelInteraction.cpp 头注释仍写"4 片",实际 6 片 -> 改为完整清单
- PopupMenuLayout.cpp 机械搬移时把构造函数一起搬走 -> 重复定义,只保留在交互分片
- PopupMenu.cpp 的 #include "PopupMenuInternal.hpp" 落进 namespace jdi 内 -> 移到文件头
- PopupMenuPaint.cpp 缺 UiControls.hpp(UiDrawEditFieldContent 未声明)-> 补 include
- 全仓复查历史删除符号残留引用(m_paintPlot / ClampCursorsAfterPan /
PaintFreeMarkerTooltip / CaptureDecorCache / FitSinglePointSignal / CsvTable /
DataFile / .preflight / structcheck)-> 零命中
## 5. Tools/ 剥离
git rm -r --cached Tools + .gitignore 新增 Tools/(本地文件保留,可随时复跑)。
ui_refactor 分支为全本地分支,另做 filter-branch 清除历史中的该目录。
## 6. 验证
- make release / make debug:零 error 零 warning
- rendercheck:A-H 八个场景哈希与改造前逐一相同
(A 2166933039626F66 B C444ECFEB18FD73D C 7984446D8E7A4418 D BF855879CA12F289
E 1C663E4118616016 F 0535292D8E07AE18 G 7A58172C46577729 H 23F390DD76141113)
FUNC 7/7 PASS
- uicheck:69 passed, 0 failed
- TargetCheck.exe 891,392 B(< 900 KB 阈值)
## 7. 文档
Documents/UI_Refactor_Plan.md / UI_Refactor_Progress.md / UI_Refactor_Report.md
新增第五阶段章节;Documents/agent_mem.md 同步变更日志与「第七轮」硬约束。
This commit is contained in:
1 parent
675c2a5f54
commit
0ec8055e95
20 files changed
+3287
-2678
No files matched your search
@@ -3025,6 +3025,9 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
||||
|
||||
| 2026-10-28 | DeepSeek-V4.1-Flash(**UI_Refactor 分支**) | **UI 重构第一阶段(P0/P1/P2,全部只提交到本地 `UI_Refactor` 分支,不影响 `main`)**:① 新增 `Components/Shared/{Inc,Src}/UiLayout.*`(矩形原语 / 对齐 / 设备像素内侧对齐 / Stack / Flow / 布局缓存)与 `UiWidget.*`(控件树基类:两段式布局、脏区下探绘制、只沿命中链派发、capture/modal/hover/focus 仲裁、光标认领链、统一动画 tick、内容指纹入口)。② 新增入库离屏回归网 `Tools/uicheck`(62 项断言,链接 `Build/<Config>/*.o` 排除 `Main.o`)。③ `PlotView` 实现按关注点重分为七个分片:`PlotViewPaint.cpp` 9 080 → **4 913** 行(−46%),新增 `PlotViewRaster.cpp`(1 876)、`PlotViewCacheKey.cpp`(474)、`PlotViewPanels.cpp`(1 359);搬移**逐像素 0 差异**(三场景渲染哈希 `A 2166933039626F66 / B C444ECFEB18FD73D / C 7984446D8E7A4418` 迁移前后完全一致)。详见 §11.2 第 235–240 条与 `Documents/UI_Refactor_Plan.md` / `UI_Refactor_Progress.md` / `UI_Refactor_Report.md`。 |
|
||||
|
||||
|
||||
| 2026-10-28 | DeepSeek-V4.1-Flash(**UI_Refactor 分支**) | **UI 重构第五阶段:统一组件协议 + 去手写链路 + 大文件按职责拆分 + 代码审查 + `Tools/` 剥离(详见 §12 末尾「2026-10-28 第七轮」)**。① 新增 `Components/Shared/Inc/UiComponent.hpp`(纯接口、无状态):`SetScale / Layout / Area / Paint / HitTest / OnMouseLeave / IsEditing / QueryCursor`;`Toolbar` / `TabBar` / `SignalPanel` / `PlotView` 各自 `: public UiComponent`,**只加 `override` + 补 `Area()`,实现零改动**。② `Application` 新增 `ComponentEntry { UiComponent*; Target; bool chrome; }` 表 + `BuildComponentTable()`,把 `ApplyDpi` / `Relayout` / `WM_MOUSELEAVE` / `WM_SETCURSOR` 四条手写链改成循环;按下/松开/移动三条链**有意保留显式分支**(带组件专属后置动作)。③ `UiLayout::UiStackRects` 首次用于生产代码(内容区三列切分)。④ `SignalPanelInteraction.cpp` 2 329 → **831** 行(拆出 `SignalPanelEdit/Scroll/Menu.cpp`),`Shared/PopupMenu.cpp` 1 901 → **706** 行(拆出 `PopupMenuLayout.cpp` / `PopupMenuPaint.cpp` + 新增 `Inc/PopupMenuInternal.hpp`)。⑤ 代码审查修 5 处(过期头注释、重复构造函数、include 落进 namespace、缺 include、残留符号全仓零命中)。⑥ `Tools/` 从提交树剥离 + `.gitignore`,并对 `UI_Refactor` 做 `filter-branch` 清除历史。验证:`make release` 零错误零警告;`rendercheck` **8 场景哈希与基线逐一相同**、7 条 FUNC 全 PASS;`uicheck` **69 passed / 0 failed**;`TargetCheck.exe` **891,392 字节**。 |
|
||||
|
||||
## 11. 跨设备协作须知(起源设备视角)
|
||||
|
||||
> **本文件是唯一权威记忆**。所有设备 / Agent 共用它,**不要再新建 `agent_mem_origin.md` 等旁支记忆文件**。
|
||||
@@ -7915,3 +7918,83 @@ DG3 data=0 cycle=0 (空组,一个字符串通道)
|
||||
面板 / `LaneVisual` / `LegendHit` / `EdgePanelLayout` 都是 `PlotView` 的嵌套类型,探针里必须写 `PlotView::` 前缀。
|
||||
- ⚠️ 本轮开始前发现工作区里 `PlotViewPaint.cpp` 与 `Documents/agent_mem.md` 被**回退到 `8f735d5`**(丢失第四/五轮全部改动),
|
||||
已 `git checkout --` 恢复到 `HEAD` 后再施工;提交前务必确认这两份文件与 HEAD 一致。
|
||||
|
||||
## 本轮(2026-10-28 第七轮):统一组件协议 + 去手写链路 + 大文件按职责拆分
|
||||
|
||||
> 用户需求:① 全面放弃手写链路,UI 绘制尽量走"控件树 + 派生基类"(先确认不是负优化);
|
||||
> ② 存在大量冗余的文件按职责拆分,但不为拆分而过度抽象;③ 一轮代码审查(错注释/过期注释/名实不符);
|
||||
> ④ 把临时测试工具 `Tools/` 从提交树剥离并写入 ignore;⑤ 更新 Documents 下的计划/进程/报告。
|
||||
|
||||
### A. `UiComponent`:顶层组件的统一协议(新增 `Components/Shared/Inc/UiComponent.hpp`)
|
||||
|
||||
纯接口、**无状态**,7 个方法:`SetScale / Layout / Area / Paint / HitTest / OnMouseLeave / IsEditing`
|
||||
(外加默认返回 `nullptr` 的 `QueryCursor`)。
|
||||
`Toolbar` / `TabBar` / `SignalPanel` / `PlotView` 各自 `: public UiComponent`,
|
||||
它们本来就有一模一样签名的方法 ⇒ **只加 `override` 与 `Area()`,实现零改动**。
|
||||
|
||||
⚠️ **不把 `UiWidget` 当这个基类**(四条契约冲突,已写进头文件注释):
|
||||
`UiWidget` 是"树上的节点"(父给尺寸、父下探脏区、命中走树链、`OnPaint` 只画自己);
|
||||
顶层大组件是"一块地盘的宿主"(`PlotView` 4 层自持位图缓存、`SignalPanel` 行位图缓存、
|
||||
`PopupMenu`/拾色器是模态浮层)。两者是**兄弟关系**,不是父子。
|
||||
`Toolbar`/`TabBar` 同时属于两者:对外实现 `UiComponent`,对内持有一棵 `UiWidget` 树。
|
||||
|
||||
### B. 宿主侧:手写链 → 组件表
|
||||
|
||||
`Application` 新增 `struct ComponentEntry { UiComponent* component; Target target; bool chrome; }`
|
||||
与 `std::vector<ComponentEntry> m_components`(底→顶:plot → panel → toolbar → tabBar),
|
||||
`BuildComponentTable()` 在 `Initialize` 里 `Setup` 之后装配一次。
|
||||
|
||||
被表驱动的四处(旧实现每处都逐个点名组件):
|
||||
|
||||
| 消息 | 旧 | 新 |
|
||||
| --- | --- | --- |
|
||||
| `ApplyDpi` | 6 行逐个 `SetScale` | 1 个循环 |
|
||||
| `Relayout` | 4 行逐个 `Layout`(且手算三组坐标) | 循环 + `UiStackRects` 切分 |
|
||||
| `WM_MOUSELEAVE` | 4 行逐个 `OnMouseLeave` + 分别累计 | 循环 + `chrome` 标志决定"整帧/只绘图区" |
|
||||
| `WM_SETCURSOR` | `if (绘图区命中) … else if (面板) …` | 从表尾往前找首个命中者,其 `QueryCursor` 生效 |
|
||||
|
||||
**仍是显式的(有意)**:左键按下/抬起、鼠标移动、编辑态吸收、分隔条拖拽 ——
|
||||
这些分支各自带"按下后要提交重命名 / 构建派生信号 / 联动滚动 / 更新拖拽光标"等**专属后续动作**,
|
||||
强行表驱动会把它们变成藏在表里的 lambda,反而更难读(正是"过度抽象")。
|
||||
|
||||
顺带兑现一个历史缺口:`UiLayout` 的 `UiStackRects` 第一次有了**生产调用点**(内容区三列切分)。
|
||||
|
||||
### C. 大文件按职责拆分(纯搬移,逐像素 0 差异)
|
||||
|
||||
| 原文件 | 现状 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `SignalPanelInteraction.cpp` 2 329 行 | **831 行** | 拆出 `SignalPanelEdit.cpp`(616) / `SignalPanelScroll.cpp`(205) / `SignalPanelMenu.cpp`(527) |
|
||||
| `Shared/PopupMenu.cpp` 1 901 行 | **706 行** | 拆出 `PopupMenuLayout.cpp`(753) / `PopupMenuPaint.cpp`(397) + 新增 `Inc/PopupMenuInternal.hpp`(103) 收敛尺寸常量与 `PaintResetIcon` |
|
||||
|
||||
拆分判据是**职责**,不是行数:面板按"编辑 / 动画滚动 / 菜单 / 交互"切;
|
||||
菜单按"几何排版 / 绘制 / 交互"切。文件级常量与辅助函数搬进 `*Internal.hpp`
|
||||
(命名空间 `pmdetail`,`constexpr`/`inline`),跨 TU 安全。
|
||||
|
||||
### D. 代码审查(本轮修掉的问题)
|
||||
|
||||
1. `SignalPanelInteraction.cpp` 头部注释写着"分片按职责划分为核心/渲染/交互与编辑"(只有 4 片),
|
||||
实际已是 6 片 ⇒ 改为完整的六分片清单。
|
||||
2. `PopupMenuLayout.cpp` 机械搬移时**把构造函数也搬了进去**(与 `PopupMenu.cpp` 重复定义)
|
||||
⇒ 删重复、只保留在交互分片。
|
||||
3. 拆分后 `PopupMenu.cpp` 的 `#include "PopupMenuInternal.hpp"` 一度落在 `namespace jdi` **内部**
|
||||
(等价于声明 `jdi::jdi`)⇒ 移到文件头。
|
||||
4. `PopupMenuPaint.cpp` 缺 `UiControls.hpp`(`UiDrawEditFieldContent` 未声明)⇒ 补 include。
|
||||
5. 全仓复查了历史删除符号的残留引用(`m_paintPlot` / `ClampCursorsAfterPan` /
|
||||
`PaintFreeMarkerTooltip` / `CaptureDecorCache` / `FitSinglePointSignal` / `CsvTable` / `DataFile` /
|
||||
`.preflight` / `structcheck`)⇒ **零命中**,无需修改。
|
||||
|
||||
### E. 验证
|
||||
|
||||
* `make release` / `make debug` **零警告**;`TargetCheck.exe` **891 392 B**(< 900 KB),
|
||||
`Target.exe` **886 784 B**(与改造前一致)。
|
||||
* `Tools/rendercheck`:A–H 八个场景哈希与改造前**逐一相同**
|
||||
(`A 2166933039626F66 … H 23F390DD76141113`),7 条功能断言全 PASS。
|
||||
* `Tools/uicheck`:**69 passed / 0 failed**。
|
||||
* 体积:`UiComponent` 是纯接口,静态派发几乎零开销;`TargetCheck` 比 `Target` 多出的
|
||||
4.6 KB 来自 `PopupMenuInternal.hpp` 的 `inline` 函数在 3 个 TU 各实例化一份
|
||||
—— 这是拆分的已知代价,仍远低于 900 KB 阈值。
|
||||
|
||||
### F. 工具目录剥离
|
||||
|
||||
`Tools/`(`uicheck` / `rendercheck`)已从**提交树**剥离并写入 `.gitignore`
|
||||
(历史提交里也不含它 —— 见台账的「分支操作取证」)。本地文件保留,仍可随时复跑。
|
||||
Reference in new issue
Block a user