refactor(panels): 面板静态特征收敛为唯一登记表 + 标记面板绘制分段(§17.6 第 1/2 项)

- 新增 pvdetail::PanelKindTraits + PanelTraitsOf(唯一 switch):标题 / 排版类别 /
  滚动字段 / 面板状态 / 功能开关同表登记;新增面板只改「枚举 + 一行」,
  -Wswitch 仍在唯一登记点生效。PanelTitle 改为「前缀 + rangeSuffix 标志」,
  不再依赖 switch(标题降级为数据,不再需要函数指针)。
- PaintPanelMarkerGroups(约 340 行)拆成 6 个具名函数,主函数只保留绘制顺序
  (普通分组栏 -> 条目 -> 表头 -> 吸顶栏 -> 滚动条 -> 透明度行);纯搬移、0 字节变化。
- 顺手修正该函数体遗留的多余缩进。

验证:release/debug/tools 零 warning;UnitTests 260/19;OffscreenChecks -all 7/133;
panels -mode compare 7 面板像素哈希逐项不变;rowgeom compare 965+7 / 1268+7 键 0 差异。
产物 781,824 -> 782,336 B(+512,全部来自登记表)。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-11-04 17:22:06 +08:00
1 parent a9f1563896
commit 0c26da07d2
8 files changed
+761 -453

No files matched your search

+74
View File
@@ -712,5 +712,79 @@ std::vector<PanelRowPlan> PlanListPanelRows(const Lane&, EdgePanelKind) const;
| 行数 | `PlotViewPanelPaint.cpp` 935 → 939;`PlotViewPanels.cpp` 1729 → 1766(新增两个几何函数,净增 37) |
| 样式 | 顺手把机械搬移遗留的"整个函数体多缩进 2 个 tab"修正 |
---
## 第 41 轮(2026-11-04):面板登记表 + 标记面板绘制分段(§17.6 第 1 / 第 2 项,收尾)
> 本轮之后**代码审查进入收尾**:所有"已知问题"要么已修、要么有实测数字支撑地**明确不做**
>(体积、`EdgeScanFor` 哈希化、`EdgePanelLayoutFor` 表驱动化),详见报告 §18。
### P39 面板的五个穷举 `switch` 合成一张 `constexpr` 登记表 ✅
改前新增一种面板要改三处(`PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf`),
实际连 `LanePanelStateOf` / `LanePanelEnabled` 一共是**五处穷举 switch**
(§17.6 只点了三处,另外两处更早就有)。
改后 `PlotViewInternal.hpp` 里只有**一个**登记点:
```cpp
struct PanelKindTraits
{
PanelStyle style; // 排版类别 + 底部控件
const wchar_t* title = L""; // 标题前缀
bool rangeSuffix = false; // 是否追加 EdgeRangeSuffix()
float Lane::*scroll = nullptr; // 内容滚动偏移
LanePanelState Lane::*panel = nullptr; // 面板 UI 状态
bool Lane::*enabled = nullptr; // 功能开关
};
inline constexpr PanelKindTraits PanelTraitsOf(EdgePanelKind kind); // 唯一 switch
```
* 五个消费者全部退化成一行取值:`return lane.*(PanelTraitsOf(kind).scroll);`
* **`PanelTitle` 不再是 switch**:标题是数据(前缀字符串 + 一个 `rangeSuffix` 标志),
运行时后缀只对两种「边沿计数」追加 ⇒ §17.6 里"`PanelTitle` 依赖运行时字符串所以先解决
'标题是函数'的问题"就此解决(不需要函数指针,也不需要 `std::wstring` 进表)。
* ⚠️ `PanelStyle` 的三个具名构造函数(`ListPanelStyle` / `CountTablePanelStyle` /
`MarkerPanelStyle`)是刻意加的:表里若写 6 个裸 bool,聚合顺序错一位就变成
"表格面板带按钮"这种没人看得出来的错误。
* 体积代价:**+512 B**(7 份 traits 记录进 `.rdata` + `PanelTitle` 多一个分支)。
用 512 B 换"新增面板只改两处 + 编译期强制登记",判定值得。
### P40 `PaintPanelMarkerGroups` 拆成 6 个具名函数 ✅
| 函数 | 职责 |
| --- | --- |
| `MeasureMarkerColumnWidths` | 六列实测文本宽度 → 写回 `Lane::freeMarkerColumnWidths` |
| `PaintMarkerGroupBar` | 一个信号分组栏(三角 / 名称 / `N 标记点` / ✕) |
| `PaintMarkerColumnSeparators` | 列分隔竖线(条目行与表头共用) |
| `PaintMarkerRow` | 一个固定点条目(六列 + 分隔线 + 行尾 ✕) |
| `PaintMarkerTableHeader` | 一个展开分组的表头(不透明底衬 + 六列标题) |
| `PaintMarkerOpacityRow` | 底部「标记透明度」滑块行 |
| `PaintPanelMarkerGroups` | **只负责顺序**:普通分组栏 → 条目 → 表头 → 吸顶栏 → 滚动条 → 透明度行 |
* 原实现把这条顺序约束埋在一个 340 行函数的循环中间("为什么表头要在这里画"),
现在它是主函数里唯一的逻辑,注释也只剩一句"后两段必须压在上面"。
* 提取时顺带把机械搬移遗留的"函数体多缩进 2 个 tab"修正(整个函数重新缩进)。
* **零体积极限验证**:P39 之后产物已经是 782,336 B,P40 之后**完全相同** ⇒ 纯搬移。
### 过程中的一个判断(值得记)
`contents`(固定点内容缓存)原来在"画完普通分组栏之后"才取,现在提前到最前面。
两者唯一的区别是缓存重建的时机,而 `FreeMarkerContents` **不改任何绘制状态**
(只读采样 + 拼字符串 + 写 `m_freeMarkerContent`)⇒ 对像素无影响,双基线也证实了。
### 本轮验证
| 项 | 结果 |
| --- | --- |
| `make release` / `make debug` / `make -C Tools` | 零 error / 零 warning |
| 产物 | 781,824 → **782,336 B**(+512,全部来自 P39 的登记表;P40 为 0) |
| `UnitTests` | `checks=260 failed=0 cases=19` |
| `OffscreenChecks -all` | 7/7 PASS,`checks=133 failed=0` |
| `panels -mode compare` | 7 个面板像素哈希**逐项不变**(含 `resample=2BFC74B3D9B3239C`) |
| `rowgeom -mode compare` | 965 + 7 键 0 差异;`-data MF4-Record.MF4` 1268 + 7 键 0 差异 |
| 行数 | `PlotViewPanelPaint.cpp` 939 → 977(6 个函数头 + 说明);`PlotViewPanels.cpp` 1766 → 1758(`PanelTitle` 变短) |
| 读点 | `PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf` / `LanePanelStateOf` / `LanePanelEnabled` 的调用点**一处未改**(签名不变) |