PlotViewPaint.cpp 9,080 行里混住四类内容(真绘制 / 光栅化缓存 / 内容指纹 / 布局与命中几何), 按"函数名前缀"分片是上一轮膨胀的根因。本提交按关注点机械搬移函数定义,不改一行逻辑: - 新增 PlotViewRaster.cpp(1,876 行):光晕离屏层、静态场景缓存、装饰层(AlphaBlend)、 每网格宽基底图层/并行重建/滚动补条/预热预算。 - 新增 PlotViewCacheKey.cpp(474 行):SceneCacheKey、SceneContentHash/Geometry/Decor、 样式与派生快照、只改外观的网格定位、样式补丁帧。 - PlotViewPaint.cpp 只留绘制:9,080 -> 6,252 行(-31%)。 - 顶层注释从「四个分片」改为「六个分片(按关注点)」,并保留 「PlotView::Paint/PaintLane 只允许定义在 PlotViewPaint.cpp」。 pvdetail 全部 inline,故跨分片安全;无需改任何 include,Makefile 按 basename 自动收集。 验证: - make release TARGET_FILE_NAME=TargetCheck 零警告;Target.exe 873,984 -> 875,008 B(+1KB 对齐差异)。 - 逐像素 A/B(仓库外一次性渲染哈希探针,三场景:全览 / 深放大+自由标记+均值滤波+弱峰调整+时间光标 / 再平移一帧):分片前后哈希完全相同 A 2166933039626F66、B C444ECFEB18FD73D、C 7984446D8E7A4418。 - Tools/uicheck 62 passed / 0 failed。 坑:用旧文件回退做 A/B 时必须先删除 Build/<Config>/PlotViewRaster.o 与 PlotViewCacheKey.o, 否则链接会因重复符号失败。
7.1 KiB
7.1 KiB
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 零行为分片 |
✅ 完成(逐像素 0 差异,见 §2) |
| 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逐节点下发同一时间戳并汇总"是否仍有动画"。 - 悬停:进入 / 离开各只触发一次,跨子节点迁移时正确配对。
过程中修掉的两个自身缺陷
UiWidget缺AdvanceAnimationSelf/AnimationActiveSelf两个 protected 虚函数(.cpp已引用、头文件漏声明)。- 最初的派发实现是"遍历同层兄弟、未消费就继续" ⇒ 一个点击可能同时被视觉上位于下方的控件处理; 已改为"只沿命中链派发 + 祖先兜底"。回归网里对应的断言从"绝对次数"改为增量断言 (绝对次数会被前面用例计数污染,本轮踩过一次)。
验证
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 之前引入行为差异。
2. P2:PlotViewPaint.cpp 按关注点分片(零行为变更)
为什么:该文件 9 080 行里混住四类内容 —— 真绘制 ≈3.5k / 光栅化缓存 ≈2.5k / 缓存键 ≈1.1k / 布局与命中几何 ≈1.3k。按"函数名前缀"分片是上一轮膨胀的直接原因,本轮按关注点再分一次。
做法:机械搬移成员函数定义(不改一行逻辑)。PlotViewInternal.hpp 里的 pvdetail 全部 inline
⇒ 跨分片安全,无需改任何 include、无需改 Makefile(按 basename 自动收集 .cpp)。
| 文件 | 搬入内容 | 行数变化 |
|---|---|---|
PlotViewRaster.cpp(新) |
光晕离屏层(PaintSignalHalo* / UploadHaloLayer / ReleaseHaloLayer)场景缓存( Ensure/Capture/Blit/Invalidate/ReleaseSceneCache)装饰层( Ensure/Release/Render/BlitDecorCache / ResolveAlphaBlend)宽基底图层与预算( EnsureLaneLayer … BlitWideBuffer、并行重建、滚动补条、预热) |
1 876 |
PlotViewCacheKey.cpp(新) |
MakeSceneCacheKey / SceneCacheMatches / SceneHaloRefSceneContentHash / SceneGeometryHash / SceneDecorHashCollectSceneStyles / FindStyleOnlyLanes / CollectSceneDerived / RepaintSceneCachePatch |
474 |
PlotViewPaint.cpp |
只剩绘制(Paint* / Render* / 输入框绘制) |
9 080 → 6 252(−31%) |
验证(关键)
make release TARGET_FILE_NAME=TargetCheck零警告;Target.exe873 984 → 875 008 B(+1 KB, 属分片后各 TU 的对齐差异;仍远低于 900 KB 阈值)。- 逐像素 A/B:临时写了一个渲染哈希探针(仓库外),对三个场景渲染后备缓冲区并取 FNV 哈希:
- A 默认全览;B 深放大 + 自由标记(含固定点)+ 均值滤波 + 弱峰调整 + 时间光标;C 再平移一帧(触发宽基底滚动/补条)。
- 分片前:
A 2166933039626F66 / B C444ECFEB18FD73D / C 7984446D8E7A4418 - 分片后:完全相同(三个场景逐一一致)。
- 该探针未入库(一次性验证用),结论记录在此以便复现。
Tools/uicheck62/62 全绿。- 顶层注释从"四个分片"更新为"六个分片(按关注点)",并写明"
Paint/PaintLane仍只允许定义在PlotViewPaint.cpp"。
⚠️ 复现 A/B 的坑:机械搬移后用旧的 .bak 回退时,Build/<Config>/ 里会残留
PlotViewRaster.o / PlotViewCacheKey.o,链接探针(Build/Release/*.o)会因重复符号失败 ——
必须先删掉这两个陈旧 .o 再链接。
下一步(接手者请从这里开始)
- P2 续:把"布局与命中几何"也搬出去(
EdgePanelLayoutFor651 行 +ProbeFreeMarker286 行 +FreeMarkerLabelRects118 行 → 新PlotViewPanels.cpp),判据同上(逐像素 0 差异)。 - P3:Toolbar 优先(最小、最容易验证的组件),迁移后跑
uicheck+ 新旧像素对比。 - 每个阶段单独提交,提交信息写清"改了什么 / 为什么 / 怎么验证"。