Files
Just-DataInspector/Documents/UI_Refactor_Progress.md
T
DeepSeek V4.1 Flash 3529c7b44f UI 重构 P0+P1:新增布局/控件基础层与离屏回归网(对产品像素零影响)
新增 Components/Shared 下的 UI 基础层:
- UiLayout:矩形原语 / 对齐 / 设备像素内侧对齐 / Stack / Flow / 布局缓存(deque 保证引用稳定、
  定向失效、按最久未命中淘汰)。
- UiWidget:控件树基类。两段式布局(Measure 自下而上带缓存、Arrange 自上而下)、
  脏区下探绘制(dirty 为空=全画;与子树矩形无交集=整棵跳过;有效裁剪=祖先裁剪切∩自身∩脏区)、
  只沿命中链派发的冒泡模型(绝不分发给同层兄弟)、capture/modal/hover/focus 仲裁、
  光标认领链、统一动画 tick、内容指纹入口。

新增 Tools/uicheck 离屏回归网(62 项断言,全程不创建窗口、不注入输入):
- 布局数学:对齐/STRETCH/超尺寸夹取、Stack 固定与自动均分且绝不产生负尺寸、Flow 换行与 overflow。
- 缓存:引用稳定、定向失效、容量淘汰。
- 绘制:全画 / 子树跳过 / 裁剪收窄 / 不可见跳过 / 失效冒泡。
- 派发:重叠子节点只投最上层、hit-transparent 穿透、消费不上抛、capture 越过边界仍投递、
  仅持有者可释放、modal 屏蔽其余子树、祖先兜底、光标由最上层认领、键盘沿焦点链。
- 动画:时间戳统一下发、活跃状态汇总。

过程中修正自身两处缺陷:补齐 AdvanceAnimationSelf/AnimationActiveSelf 声明;
把"遍历同层兄弟"改为"只沿命中链派发 + 祖先兜底"(否则一次点击可能被视觉上位于下方的控件也处理)。

验证:make release TARGET_FILE_NAME=TargetCheck 零警告(873,984 B,低于 900KB 阈值);
Tools/uicheck 62 passed / 0 failed。

本提交不改动任何现有组件,Toolbar/TabBar/SignalPanel/PlotView 仍走旧路径,产品像素零变化。
文档:Documents/UI_Refactor_Plan.md(蓝图)、Documents/UI_Refactor_Progress.md(台账)。
2026-10-28 12:15:41 +08:00

87 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UI 重构进度(UI_Refactor 分支)
> 本文件是**跨会话/跨 Agent 的交接台账**。每次提交前更新;每一行都要能对应到一个可复跑的验证结果。
> 计划见 `Documents/UI_Refactor_Plan.md`;硬约束见 `Documents/agent_mem.md` §11.2。
## 分支状态
| 分支 | 基线 | 用途 |
| --- | --- | --- |
| `main` | `df715a0` | 可发布,**不受本次重构影响** |
| `dev` | `4e51b41`(删除过时报告 `refactor_report_2026-10-16.md`) | 日常开发基线 |
| `UI_Refactor` | 从 `dev` 切出 | 本次 UI 重构(全部提交只留在本地) |
## 阶段看板
| 阶段 | 内容 | 状态 |
| --- | --- | --- |
| **P0** | 离屏回归网 `Tools/uicheck`(入库) | ✅ 完成(62 项断言全绿) |
| **P1** | `UiLayout` + `UiWidget` 基础层 | ✅ 完成(编译零警告,`uicheck` 覆盖) |
| **P2** | `PlotViewPaint.cpp` 零行为分片 | ⏳ 待做 |
| **P3** | 迁移 chrome(Toolbar / TabBar / 菜单 / 拾色器 / 列表行) | ⏳ 待做 |
| **P4** | 迁移 5 个浮动面板 | ⏳ 待做 |
| **P5** | 波形管线包成叶子 surface + 共享 DIB | ⏳ 待做 |
---
## 提交记录
### 1. `P0 + P1`:UI 基础层与离屏回归网
**新增文件**
| 文件 | 行数 | 职责 |
| --- | --- | --- |
| `Components/Shared/Inc/UiLayout.hpp` | ~250 | 布局原语 + `UiLayoutCache` |
| `Components/Shared/Src/UiLayout.cpp` | ~300 | 矩形原语 / 对齐 / Stack / Flow / 缓存 |
| `Components/Shared/Inc/UiWidget.hpp` | ~330 | 控件基类接口与设计说明 |
| `Components/Shared/Src/UiWidget.cpp` | ~560 | 树 / Measure·Arrange / Paint(脏区+裁剪)/ 派发 / 仲裁 / 动画 |
| `Tools/uicheck/main.cpp` | ~570 | 离屏回归网(62 项断言) |
| `Tools/uicheck/build.ps1` | ~70 | 链接 `Build/<Config>/*.o`(排除 `Main.o`) |
**已实现并验证的行为**
- 布局:`UiAlignInRect`(含 `STRETCH`、超尺寸夹取、偏移后置)、`UiRectSnapInward`(设备像素内侧对齐)、
`UiStackRects`(固定 / `kUiSizeAuto` 均分 / **绝不产生负尺寸**)、`UiFlowRects`(换行 + `overflow` 下标)。
- 缓存:`UiLayoutCache` 用 `std::deque` 保证**引用稳定**;容量淘汰按"最久未命中";`Invalidate` 为**定向**失效。
- 布局 pass:`Measure` 命中缓存不重复调用 `OnMeasure`;`InvalidateMeasure` **只**沿祖先链失效(兄弟不重算)。
- 绘制:`dirty` 为空 = 全画;与子树矩形无交集 ⇒ **整棵子树跳过**;有效裁剪 = 祖先裁剪切 ∩ 自身矩形 ∩ 脏区;
不可见节点跳过。
- 派发:**只沿命中链**(最深的命中节点 → 祖先冒泡),**绝不分发给同层兄弟**;`capture` 期间事件直投捕获者;
`modal` 只向模态子树派发;`hit-transparent` 让事件穿透;`QUERY_CURSOR` 由最上层认领者返回;
键盘/字符沿**焦点链**派发(无焦点交给根,保证宿主级快捷键可用)。
- 动画:`AdvanceAnimation` 逐节点下发同一时间戳并汇总"是否仍有动画"。
- 悬停:进入 / 离开各只触发一次,跨子节点迁移时正确配对。
**过程中修掉的两个自身缺陷**
1. `UiWidget` 缺 `AdvanceAnimationSelf` / `AnimationActiveSelf` 两个 protected 虚函数(`.cpp` 已引用、头文件漏声明)。
2. 最初的派发实现是"遍历同层兄弟、未消费就继续" ⇒ **一个点击可能同时被视觉上位于下方的控件处理**;
已改为"只沿命中链派发 + 祖先兜底"。回归网里对应的断言从"绝对次数"改为**增量断言**
(绝对次数会被前面用例计数污染,本轮踩过一次)。
**验证**
```
make release TARGET_FILE_NAME=TargetCheck # 零警告
powershell -File Tools/uicheck/build.ps1 # 链接 Build/Release/*.o(排除 Main.o)
Tools/uicheck/uicheck.exe # 62 passed, 0 failed
```
**未做(有意)**
- 未改动任何现有组件(Toolbar / TabBar / SignalPanel / PlotView 仍走旧路径),因此**本提交对产品像素零影响**。
- 未把 `UiWidget` 接入 `Application`,避免在 P2 之前引入行为差异。
---
## 下一步(接手者请从这里开始)
1. **P2:`PlotViewPaint.cpp` 零行为分片**(9 080 行)
- 目标分片:`Paint`(只画)/ `Raster`(缓存与预算)/ `CacheKey`(指纹)/ `Geometry`(面板与命中几何)。
- 做法:**机械搬移函数定义**,不改一行逻辑;`PlotViewInternal.hpp` 里的 `pvdetail` 全是 `inline`,跨分片安全。
- 判据:`make release` 零警告 + `Target.exe` 体积变化 < 1KB + 场景哈希/像素快照与迁移前一致。
- ⚠️ 搬移后务必确认没有残留的 `static` 文件级变量(只在 `PlotViewPaint.cpp` 内可见的辅助函数要一并搬走)。
2. **P3:Toolbar 优先**(最小、最容易验证的组件),迁移后跑 `uicheck` + 新旧像素对比。
3. 每个阶段单独提交,提交信息写清"改了什么 / 为什么 / 怎么验证"。