From 4f3c88f3986500190637378b9b1e5b8e593ab2fd Mon Sep 17 00:00:00 2001 From: "DeepSeek V4.1 Flash" <> Date: Wed, 28 Oct 2026 12:35:39 +0800 Subject: [PATCH] =?UTF-8?q?UI=20=E9=87=8D=E6=9E=84=EF=BC=9A=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=9B=B4=E6=96=B0=E4=B8=BA=20P0-P3=20+=20P5(1)?= =?UTF-8?q?=EF=BC=88=E5=85=B1=E4=BA=AB=E8=A1=A8=E9=9D=A2=E4=B8=8E=E9=80=80?= =?UTF-8?q?=E5=87=BA=E5=B4=A9=E6=BA=83=E4=BF=AE=E5=A4=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Documents/UI_Refactor_Progress.md:阶段看板标记 P5 部分完成;新增第 5 条提交记录 (UiSurface / top-down DIB / Shutdown 顺序修复 / Render 保护 / 69 项断言 / 8 场景哈希); 修正重复标题;「下一步」重写为 TabBar→菜单→面板→脏区并集。 - Documents/UI_Refactor_Report.md:标题与交付表纳入 P5(1);关键数字更新(69 项断言、 产物 883,200 B、共享 DIB);新增第 7 节描述共享表面与退出期崩溃修复;后续章节重编号。 验证:make release / make debug 零警告;Tools/uicheck 69/69;8 场景渲染哈希与改造前一致。 --- Documents/UI_Refactor_Progress.md | 51 ++++++++++++++++++++++++++----- Documents/UI_Refactor_Report.md | 32 ++++++++++++++----- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/Documents/UI_Refactor_Progress.md b/Documents/UI_Refactor_Progress.md index c09e51c..39bbf0e 100644 --- a/Documents/UI_Refactor_Progress.md +++ b/Documents/UI_Refactor_Progress.md @@ -20,7 +20,7 @@ | **P2** | `PlotViewPaint.cpp` 零行为分片 | ✅ 完成(**逐像素 0 差异**,见 §2/§3) | | **P3** | 迁移 chrome(Toolbar / TabBar / 菜单 / 拾色器 / 列表行) | 🔄 **Toolbar 已完成**,其余待做 | | **P4** | 迁移 5 个浮动面板 | ⏳ 待做 | -| **P5** | 波形管线包成叶子 surface + 共享 DIB | ⏳ 待做 | +| **P5** | 波形管线包成叶子 surface + 共享 DIB | 🔄 **UiSurface + DIB 已完成**;脏区并集待做 | --- @@ -175,13 +175,48 @@ Tools/uicheck/uicheck.exe # 62 passed, 0 failed --- +### 5. `P5(1)`:共享表面 `UiSurface` + 后备缓冲改 top-down 32bpp DIB(**逐像素 0 差异**) + +**新增** `Components/Shared/{Inc,Src}/UiSurface.*`:`{ dc, rect, stride, bits, version, scale }`。 +`SubView(localRect)` 把子矩形换算到宿主坐标、**夹取**在本表面内、按 `stride` 重算 `bits` 偏移、传递 `version`。 + +> ⚠️ 文件头注释里明确写了取舍:**画控件只需要 `dc + rect`**;`bits` 只在 CPU 侧合成 +> (memcpy / alpha 混合 / 重采样)时才有意义。用 `bits` 直写像素来"画"控件会破坏 ClearType、 +> 引入 stride / 翻转 / 写序三类错,是净亏损。 + +**`Application`**: +* 后备缓冲由 `CreateCompatibleBitmap` 改为 **top-down 32bpp `CreateDIBSection`** + (`biHeight` 取负 ⇒ `bits` 从第一行开始、y 向下递增); +* 新增 `m_backBits` / `m_backStride` / `m_backVersion`,重建位图时 `++m_backVersion`; +* 新增 `BackBufferSurface()` 对外暴露整块表面。 + +**顺带修掉一个真实缺陷(退出期访问违例)**: + +| 问题 | 修法 | +| --- | --- | +| `Shutdown()` 里先 `GdiplusShutdown` 再 `DestroyWindow`:`DestroyWindow` 期间派发的 `WM_PAINT` 会进 `Render()`,在**已关闭**的 GDI+ 上构造 `Graphics` ⇒ 崩溃 | 顺序改为 **先销毁窗口 / 注销类,最后 shutdown GDI+** | +| 任何晚到的绘制都可能踩到这条路径 | `Render()` 开头加保护:`!m_gdiplusReady || m_hwnd == nullptr` 直接返回 | + +> 另:临时探针此前的退出崩溃其实来自"探针自己又调了一次 `GdiplusShutdown`"(`Application::Shutdown` +> 内部已 shutdown)——与本轮修复无关,但顺序调整与 `Render` 保护保留为防御性正确做法。 + +**验证** + +1. 8 场景像素哈希与 DIB 改造前**逐一相同**;3 条工具栏功能断言仍 PASS。 +2. `Tools/uicheck` **69/69**(新增 7 条 `UiSurface` 断言:bits 按 stride 偏移、矩形夹取、 + 完全在外返回无效表面、`version`/`scale` 传递)。 +3. `make release` / `make debug` 零警告;`Target.exe` **883 200 B**(< 900 KB)。 + +--- + ## 下一步(接手者请从这里开始) -1. **P3 续**:按同一套路迁移 `TabBar`(标签 + 「+」按钮 + 重命名内联输入框)→ 再迁移 - `PopupMenu` / `ColorPickerPopup` 的条目行。判据同为"8+ 场景像素哈希一致 + 功能断言"。 +1. **P3 续**:`TabBar`(标签 + 「+」+ 重命名内联 + 拖拽排序)→ `PopupMenu` / `ColorPicker` 条目行。 + 建议把"标签"做成 `UiButtonWidget` 的派生(含 ✕ 热区与拖拽),`TabBar` 只保留重命名编辑与排序语义。 2. **P4**:5 个浮动面板(`EdgePanelLayoutFor` 651 行 → 真控件;Stack + Abs + Measure-driven), - 消掉 `rowRefs/rowChecks/rowPoints/rowOrder/rowLevelTracks/...` 等平行数组。 - ⚠️ 每个面板单独一轮;吸顶/滚动/滚动条/滑块复位/行悬停压暗/开关联动是 6 轮补丁叠出的隐式约定。 -3. **P5**:共享 top-down 32bpp `CreateDIBSection` + `SurfaceView{dc,rect,stride,bits,version}`, - 把 56 处 `InvalidateRect` 收敛成脏区并集。 -4. 每阶段单独提交,提交信息写清"改了什么 / 为什么 / 怎么验证"。 + 消掉 `rowRefs/rowChecks/rowPoints/rowOrder/rowLevelTracks/...` 平行数组。 + ⚠️ 每个面板单独一轮;吸顶 / 滚动 / 滚动条 / 滑块复位 / 行悬停压暗 / 开关联动是 6 轮补丁叠出的隐式约定。 +3. **P5(2)**:把 56 处 `InvalidateRect` 收敛为 `Host::Invalidate(rect)` 的区域并集, + 并把 `UiWidget` 的脏区树接到 `Application::Render`(一次回送)。 + ⚠️ 回送仍必须**有无条件 `else`**(历史:某分支缺兜底 ⇒ 一个像素都没回送)。 +4. 每阶段单独提交,判据固定为:`uicheck` 全绿 + **8+ 场景像素哈希一致** + **功能断言**。 diff --git a/Documents/UI_Refactor_Report.md b/Documents/UI_Refactor_Report.md index 1fb8143..3b00142 100644 --- a/Documents/UI_Refactor_Report.md +++ b/Documents/UI_Refactor_Report.md @@ -1,4 +1,4 @@ -# UI 重构报告(P0 / P1 / P2 / P3-Toolbar) +# UI 重构报告(P0 / P1 / P2 / P3-Toolbar / P5-共享表面) 日期:2026-10-28 分支:`UI_Refactor`(从 `dev` 切出;`dev` 又由 `main@df715a0` 切出) 所有提交**只在本地仓库**,`main` / `dev` 未受影响。计划见 `UI_Refactor_Plan.md`,台账见 `UI_Refactor_Progress.md`。 @@ -13,10 +13,13 @@ | **P1** | UI 基础层 `Components/Shared/{Inc,Src}/UiLayout.*` + `UiWidget.*`(约 1 440 行含注释) | ✅ | | **P2** | `PlotView` 实现按关注点重分为**七个分片**;`PlotViewPaint.cpp` 9 080 → **4 913** 行(**−46%**) | ✅ | | **P3** | **Toolbar 已迁移到控件树**(新增 `UiButtonWidget`,公开 API 未变、逐像素 0 差异) | ✅(1/5 组件) | +| **P5(1)** | **共享表面 `UiSurface`** + 后备缓冲改 **top-down 32bpp DIB**;顺带修复退出期崩溃 | ✅ | -五个提交: +六个提交: ``` +955666b UI 重构 P5(1):共享表面 UiSurface + 后备缓冲改 top-down 32bpp DIB;修复退出期绘制崩溃 +e14caec UI 重构:报告更新为 P0-P3(含 Toolbar 迁移),并补记框架裁剪约定变更 84a349f UI 重构 P3:Toolbar 迁移到控件树(新增 UiButtonWidget,逐像素 0 差异 + 功能断言) eb11e63 UI 重构:补充进度台账、阶段报告与共享记忆同步 ec3f93f UI 重构 P2 续:把布局与命中几何从绘制分片拆出(PlotViewPanels.cpp,逐像素 0 差异) @@ -33,9 +36,10 @@ b532046 UI 重构 P2:PlotViewPaint.cpp 按关注点分片(机械搬移, | `PlotViewPaint.cpp` | 9 080 行 | **4 913 行(−46%)** | | 最大源文件 | 9 080(`PlotViewPaint.cpp`) | 4 913(`PlotViewPaint.cpp`) | | `PlotView` 实现文件数 | 4 | **7**(职责单一) | -| 自动化 UI 探针 | **0** | **62 项断言**(入库、可复跑) | +| 自动化 UI 探针 | **0** | **69 项断言**(入库、可复跑) | | 已迁移到控件树的组件 | 0 | **Toolbar**(1 个,含 8 场景像素 A/B + 3 条功能断言) | -| 产物 | 873 984 B | **881 664 B**(+7.7 KB,< 900 KB 阈值) | +| 共享后台位图 | compatible bitmap(无像素指针) | **top-down 32bpp DIB** + `UiSurface{dc,rect,stride,bits,version}` | +| 产物 | 873 984 B | **883 200 B**(+9.2 KB,< 900 KB 阈值) | | 产品像素差异 | — | **0**(分片三场景 + 迁移八场景哈希逐一相同) | --- @@ -174,7 +178,21 @@ flowchart TD --- -## 7. 明确未做的事(避免误解) +## 7. P5(1):共享表面与 top-down DIB + +* 新增 `Components/Shared/{Inc,Src}/UiSurface.*`:`{ dc, rect, stride, bits, version, scale }`; + `SubView()` 换算子矩形、**夹取**在本表面内、按 `stride` 重算 `bits` 偏移、传递 `version`。 +* `Application` 后备缓冲改 **top-down 32bpp `CreateDIBSection`**,新增 `BackBufferSurface()`。 + 这就是"整个应用共享一张后台位图"的落地载体;`bits` 只在 CPU 侧合成时使用(画控件只需 `dc + rect`)。 +* **顺带修掉一个真缺陷**:`Shutdown()` 原本先 `GdiplusShutdown` 再 `DestroyWindow`, + 而 `DestroyWindow` 期间可能派发 `WM_PAINT` ⇒ `Render()` 在已关闭的 GDI+ 上构造 `Graphics` ⇒ 崩溃。 + 现改为**先销毁窗口 / 注销类、最后 shutdown GDI+**,并给 `Render()` 加了 `m_gdiplusReady` 保护。 + +**验证**:8 场景像素哈希与改造前逐一相同;`uicheck` 新增 7 条 `UiSurface` 断言(共 **69/69**)。 + +--- + +## 8. 明确未做的事(避免误解) | 未做 | 原因 | | --- | --- | @@ -186,7 +204,7 @@ flowchart TD --- -## 8. 下一步建议(按收益/风险排序) +## 9. 下一步建议(按收益/风险排序) 1. **P3 继:TabBar**(标签 + 「+」+ 重命名内联输入框)→ 再 `PopupMenu` / `ColorPickerPopup` 条目行。 判据同 Toolbar:**8+ 场景像素哈希一致 + 功能断言**(点击/悬停/取消、重命名提交与取消)。 @@ -199,7 +217,7 @@ flowchart TD --- -## 9. 一句话结论 +## 10. 一句话结论 > 本阶段**首次把一个现有组件(Toolbar)真的换成了控件树**,并且同时以**像素哈希一致**与**功能断言**证明 > 行为未变;同时新增了布局/控件基础层、入库回归网,并把 9 080 行的"万能绘制文件"降到 4 913 行(−46%)。