收尾:LanePanelState 抽取 + 错误提示非模态化(清空上一轮的“未完成”)
一、Lane 的内聚性(上一轮建议 5,本轮完成)
- 新增 struct LanePanelState { bool open = true; double x = -1.0; double y = -1.0; };
- Lane 的 12 个平铺面板字段(edgePanelOpen/X/Y 等 × 4 类实验性功能)
→ 4 个聚合成员 edgePanel / edgeCenterPanel / meanFilterPanel / weakPeakPanel;
- 访问点全部改为 lane.edgePanel.open 形式(DataModelTab.cpp 快照拷贝、
PlotViewInteraction.cpp 面板拖拽、PlotViewPaint.cpp 面板层序绘制);
- RebuildLanes 内部的 LaneCarry 同步收敛为 4 个 LanePanelState,
12 行逐字段赋值简化为 4 行整体赋值。
- 教训:批量改名不能对“声明”和“使用”跑同一组替换对,
否则声明行会变成 `bool edgePanel.open = true;` 这类非法代码。
二、错误提示与模态阻塞解耦(上一轮建议 1,本轮完成)
- Application 新增 SetModalErrorsEnabled(bool) / ModalErrorsEnabled(),
成员 m_modalErrorsEnabled 默认 true(交互场景行为不变);
- Initialize 最先执行 SetModalErrorsEnabled(showCommand != SW_HIDE):
隐藏窗口(自动化/离屏)下没人能点掉模态框,等于把进程钉死;
- SetStatusMessage(text, isError=true):允许模态时原样 MessageBoxW,
否则改走非模态通道 m_plot.ShowPersistentHint(text)(绘图区底部浮层);
普通提示与空文本依旧被忽略;
- PlotView 新增公开接口 ShowPersistentHint(text)(内部转 SetHintSticky),
不向宿主暴露粘滞/淡出等内部细节。
三、顺带修掉一个真实缺陷
- PlotView::Paint 在 m_lanes.empty() 时提前 return,而提示浮层在其后的
叠加层绘制 ⇒ 一个信号都没勾选时任何错误都显示不出来,恰恰是
“文件加载失败”最需要提示的场景;该分支补一次 PaintHint(g)。
四、验证(全部离屏:SW_HIDE + 不注入输入 + BELOW_NORMAL)
- make release / make debug:通过,零警告;Build/Release/Target.exe = 764416 B;
- verify 49/49、datacheck 69/69、edgecheck 46/46、panelanim 156/156;
- 新增探针 .preflight/perf/errcheck 19/19:默认值 / 隐藏窗口自动降级 / 宿主显式开关;
工作线程 + 5s 超时判定“不阻塞”(旧行为会永久阻塞,判失败并 ExitProcess,
探针不会挂住);EnumWindows 统计本进程 #32770 顶层窗口数量前后不变;
错误文本进入 m_hintText / m_hintSticky / HintNeedsAnimation / m_hintShownAt;
像素级:有提示帧与无提示帧在绘图区内的差异像素 3781,且全帧差异同为 3781
(证明差异只来自提示)。
五、文档
- Documents/agent_mem.md:§9.37 新增第八节(本轮补齐)、第九节(仅剩 MF4 项)、
§11.2 新增第 93–95 条硬约束、变更日志新增一行;
- Documents/refactor_report_2026-10-16.md:§7.3 / §7.4 标记完成,新增 §九 收尾补记
(含 9.1–9.5:聚合化、解耦、探针、验证结果、变更清单)。
This commit is contained in:
1 parent
e6b7bf66ec
commit
d2e6fdd085
11 files changed
+296
-132
No files matched your search
+55
-5
@@ -2230,12 +2230,44 @@ Components/Shared/Src/UiControls.cpp
|
||||
6. ⚠️ **拆分不会减小机器码,反而略增**:实测 754 176 → 764 416 B(+10 240 B,+1.4%),
|
||||
因为 `inline` 工具函数每个引用它的 TU 各生成一份(PE 无 ICF)。
|
||||
|
||||
#### 八、本轮仍**未**完成(诚实记录)
|
||||
#### 八、`LanePanelState` 抽取 + 错误提示非模态化(本轮补齐,同一轮次的第二遍)
|
||||
|
||||
1. `Lane` 抽出 `LanePanelState`(内聚性重构,非冗余清理):未执行。`Lane` 含 4 类实验性功能的
|
||||
状态与各自面板坐标,建议后续把「开关 + 每信号参数 + 面板位置」抽成 `LanePanelState`。
|
||||
2. `SetStatusMessage(..., isError)` 的模态阻塞解耦:未执行(需要用户拍板提示样式)。
|
||||
3. 上一轮建议的 MF4 压缩块 / `##DL` 数据列表:按用户要求继续不做。
|
||||
1. **`Lane` 的 12 个平铺面板字段**(`edgePanelOpen/X/Y` × 4 类实验性功能)→ **4 个聚合成员**
|
||||
`LanePanelState edgePanel / edgeCenterPanel / meanFilterPanel / weakPeakPanel`;
|
||||
`LanePanelState { bool open=true; double x=-1; double y=-1; }`。
|
||||
访问点全部改为 `lane.edgePanel.open` 形式(`DataModelTab.cpp` 快照拷贝、
|
||||
`PlotViewInteraction.cpp` 拖拽、`PlotViewPaint.cpp` 面板层序绘制);
|
||||
`RebuildLanes` 内部的 `LaneCarry` 同步收敛为 4 个 `LanePanelState`(逐字段赋值 → 整体赋值)。
|
||||
⚠️ **教训**:批量改名脚本**不能对「声明」和「使用」跑同一组替换对** ——
|
||||
`edgePanelOpen → edgePanel.open` 用在 `LaneCarry` 的**声明行**上会生成
|
||||
`bool edgePanel.open = true;`(非法)。声明处必须单独重写。
|
||||
2. **错误提示与模态阻塞解耦**:`Application::SetModalErrorsEnabled(bool)` + `ModalErrorsEnabled()`,
|
||||
成员 `m_modalErrorsEnabled` 默认 `true`;`Initialize(instance, showCommand)` **最先**执行
|
||||
`SetModalErrorsEnabled(showCommand != SW_HIDE)`(隐藏窗口下弹模态框无人能点掉 = 进程被钉死)。
|
||||
`SetStatusMessage(text, isError=true)`:允许模态 → 原样 `MessageBoxW`;
|
||||
不允许 → `m_plot.ShowPersistentHint(text)`(绘图区底部非模态浮层)。
|
||||
普通提示与空文本仍被忽略 ⇒ **交互场景行为完全不变**。
|
||||
`PlotView` 新增公开 `ShowPersistentHint(text)`(内部转 `SetHintSticky`),
|
||||
不暴露粘滞/淡出细节。
|
||||
3. ⚠️ **顺带修掉真实缺陷**:`PlotView::Paint` 在 `m_lanes.empty()` 时提前 `return`,
|
||||
而提示浮层在其后的叠加层里绘制 ⇒ **一个信号都没勾选时任何错误都显示不出来**
|
||||
(恰恰是"文件加载失败"最需要提示的场景)。修法:该分支补一次 `PaintHint(g)`。
|
||||
这是**探针先失败、才回头发现的**。
|
||||
4. **新增探针 `.preflight/perf/errcheck`(19/19)**:默认值/隐藏窗口降级/宿主显式开关;
|
||||
`SetStatusMessage` 从**工作线程**调用须 5s 内返回(旧行为永久阻塞 ⇒ 判失败并 `ExitProcess`,
|
||||
探针不会挂);`EnumWindows` 统计本进程 `#32770` 顶层窗口数量前后不变;
|
||||
错误文本进 `m_hintText`、`m_hintSticky`、`HintNeedsAnimation()`、`m_hintShownAt != 0`;
|
||||
**像素级**:有/无提示两帧在绘图区内的差异像素 3781,且**全帧差异也是 3781**(差异只来自提示)。
|
||||
5. **验证**:`make release` / `make debug` 零警告,`Target.exe` **764 416 B**(结构改动,无新增膨胀);
|
||||
`verify` 49/49、`datacheck` 69/69、`edgecheck` 46/46、`panelanim` 156/156、`errcheck` 19/19。
|
||||
|
||||
#### 九、本轮仍**未**完成(诚实记录)
|
||||
|
||||
1. 上一轮建议的 MF4 压缩块 / `##DL` 数据列表:按用户要求继续不做。
|
||||
|
||||
> ⚠️ 排查教训(写进 §11.2):**同一组批量改名不能同时覆盖「声明」与「使用」**;
|
||||
> 并且**任何"宿主级反馈通道"都必须做像素级验证** —— 通道存在 ≠ 通道可见
|
||||
>(`Paint` 的 early-return 会静默把它吃掉)。
|
||||
|
||||
---
|
||||
|
||||
@@ -2289,6 +2321,7 @@ Components/Shared/Src/UiControls.cpp
|
||||
| 2026-10-16 | DeepSeek-V4.1-Flash(**另一台设备**) | **分组折起/展开动画 + 筛选态可折起(项数按筛选计数)+ 悬浮组名可交互与"先滚动再折起" + 「适应视图」与「Y 轴自适应」彻底同源(详见 §9.35)**。① **折起动画**:`SignalPanel::m_groupAnims` + `GroupRowScale()` —— 每行速度倍率 `1 + 1.2×ordinal/(行数−1)`(**离组名越远越快收尽**)叠加 ease-out cubic(末段减速),总时长 `clamp(115+14×行数, 140, 300)` ms;`BuildRows` 输出**非整行高**,低于 0.75 逻辑 px 的行不再产生;宿主 `WM_TIMER` 同时驱动滚动与折起动画(`Render` 判定改为二者取或);新增 `SetRowClip/ClearRowClip` 把行内容裁到本行(否则垂直居中文本溢出到相邻行)。② **筛选态折起**:筛选模式改用**独立**的 `m_filterCollapsed`(默认展开,不污染普通列表),`ListRow::displayCount` 承载"该组内符合筛选条件的个数",筛选文本/清空/数据变化即清空。③ **悬浮组名可交互**:根因是 `HitRow` 只按滚动偏移映射行 ⇒ 点击穿透到下层;修法:`HitRow` 先用 `StickyGroupRowIndex()`+`StickyGroupRowTop()` 判定悬浮行矩形并临时用 `m_rowYOverrideActive` + 新的 `RowHitPart()` 算行内区域,并跳过高度为 0 的行;新增 `ToggleGroupFromRow()`:正悬浮时 `StartScrollAnimationTo(行内容偏移, groupIndex)`(挂起请求 `m_pendingGroupToggle`),滚动到位后才启动折起动画。④ **单点信号上两种自适应不一致**:`FitSinglePointCluster` 曾另算"半径留白 + 跨度 1"且把 `fitYToSelection` 置回 false ⇒ 点「适应视图」既改区间又**关掉 Y 轴自适应**;修法:单点簇只负责时间轴(居中 + 一大格 1s),**逐网格幅值轴与常规路径/Y 轴自适应完全同源**(`fitYToSelection` → `AutoRangeLaneToView`,否则 `autoRange=true`,再接 `ApplySinglePointValueMargins`),且**绝不改写** `fitYToSelection`。验证:新增离屏探针 `.preflight/perf/panelanim_main.cpp`(真实 `Application` + `SW_HIDE`)**94/94 通过**(连跑 3 次稳定;覆盖折起/展开的分帧过渡、单调收敛、越靠下越矮、末态精确无残留、筛选计数与独立折起状态、悬浮四个可交互区域全部命中且下层行仍可点、点击后"先滚动到位再折起"、真实 MF4 单点信号两种自适应逐位一致/往返稳定);**A/B** 三组(回退绘图区修复 / 禁用悬浮命中优先 / 动画时长置 0)分别 **4 / 13 / 8 项如实失败**;既有 `verify` **49/49**(顺带修正 4 条与远端新规则不符的过期断言)、`datacheck` **69/69**、`edgecheck` **46/46**;`make release` 零警告。 |
|
||||
| 2026-10-16 | DeepSeek-V4.1-Flash(**另一台设备**) | **动画改「抽拉卷尺」式刚性平移 + 筛选态折叠三角修正 + 样式区「目标」行绘制/布局修正(详见 §9.36)**。① **动画重做**(推翻上一轮的“按行缩放”):整组信号作为**刚性整体**平移,**行高永不变**、只维护一个逐行平移量 `m_rowShift` ⇒ 动画期间**无需重建行集合**(流畅关键);收起时逐条被组名栏吞掉、展开时逐条冒出;中途反向点击**从当前位移续接**不跳变;时长 `clamp(115+6×行数, 150, 320)` ms。② **藏进组名栏的裁剪**:信号行越过组名的**绘制**下边界即裁掉,且除 GDI 裁剪外**必须用 `g.SetClip(..., CombineModeIntersect)` 同时收紧 GDI+ 裁剪**(否则行内色块/复选框/徽标画到组名栏上)。③ **悬浮组名折起改为“一边滚动一边收起”**(推翻“先滚动到位再折起”):`scrollSynced` 让滚动与平移按同一进度推进 ⇒ 组名屏幕位置恒定;结束时滚动偏移恰好落在“组名正好在最上方”,并且**无跳变**;旧 `m_pendingGroupToggle` 机制删除。④ **筛选态折叠三角**:`PaintFileRow` 改读 `IsGroupCollapsed()`(筛选模式用的是独立的 `m_filterCollapsed`),修复“三角维持筛选前状态”。⑤ **「目标」行**:`PaintTargetRow` 误用列表裁剪版 `PaintRowText` ⇒ 名称与 GX 文本被完全裁掉(改用 `UiText`);GX 标签改为**右对齐到内容列右边缘**、名称无标签时占满内容列;`EditFieldRect()` 对目标行只返回名称矩形(否则改名输入框把 GX 标签包进去)。验证:离屏探针 `.preflight/perf/panelanim_main.cpp` **147/147 通过**(连跑 3 次稳定;含逐帧断言组名栏像素零变化、`m_rowsDirty` 恒 false、滚动单调且恰好落位、筛选/普通态折叠三角逐像素 0 差异、目标行文本像素存在与两端对齐);**A/B** 五组(回退筛选三角+非刚性平移 / 回退目标行绘制与布局 / 关闭同步滚动 / 去掉 GDI+ 收紧裁剪 / 不续接位移)分别 **4 / 6 / 6 / 2 / 1 项如实失败**;`verify` **49/49**、`datacheck` **69/69**、`edgecheck` **46/46**;`make clean && make all` 零警告。 |
|
||||
| 2026-10-16 | DeepSeek-V4.1-Flash(**另一台设备**) | **分组折起热区与改名输入框修正 + 数据模型去冗余(单一名称)+ 新增 `Components/Shared` 组件 + 过时注释/命名大清理 + 二进制瘦身 24.6% 并完成多文件拆分(详见 §9.37 与本轮报告 `Documents/refactor_report_2026-10-16.md`)**。① **折起热区**(用户要求):点分组**名称**不再折起,只有**折叠三角**或**「组X」标签**(新增 `RowPart::GROUP_TITLE`)才折起。② **分组改名输入框不再吞掉「N 项」**:`RowNameRect` 右边界改为项数左缘;新增 `GroupLabelText`/`GroupStatsText` 作为文本与宽度的唯一来源。③ **`SignalData`/`SignalGroup` 只留一个名称字段**:删除 `displayName` 与 `Title()`(31 处改用 `name`),`SetSignalDisplayName`/`SetGroupDisplayName` → **`RenameSignal`/`RenameGroup`**(空名一律拒绝);删除死成员 `Application::m_loadingBytes`。④ **新增 `Components/Shared`**(用户要求):从 `PaintUtil` 迁出全部**控件**(图标/复选框/滑块/内联输入框/颜色样块/取值胶囊配色)到 `UiControls.hpp/.cpp`,`PaintUtil` 只留低层原语;依赖方向固定 `Components/* → Components/Shared → Utilities`。⑤ **过时注释/命名**:`文件下标`→`分组下标`、`文件分组`→`分组` 等一批;形参名 `file`→`axis`/`group`;`PaintFileRow`→`PaintGroupRow`、`FileCloseRect`→`GroupCloseRect`、`OpenFileMenu`→`OpenGroupMenu`、`FileGroupLabelWidth`→`GroupLabelWidth`、`StyleEditField::FILE_NAME`→`GROUP_TITLE`;修复 `DataModel.hpp` 两处被压扁的注释块与 `NewTab` 重复文档块。⑥ **多文件拆分(本轮完成)**:`PlotView.cpp`(13 695 行)+ `SignalPanel.cpp` + `Application.cpp` + `DataModel.cpp` 四个大文件全部按功能拆成多个协作文件(私有内部头 + 具名命名空间 + 全 `inline` + 按名字分桶),最大单文件 544 KB → 276 KB。⑦ **二进制瘦身**:真因是 **ICO 里 256×256 未压缩 BMP 条目(270 KB,占整包 27%)**,改为 **PNG 存储**(观感零变化)⇒ `Target.exe` **1 013 248 → 764 416 B(−24.6%)**;实测“拆分不会减小机器码,反而 +1.4%”、`--gc-sections` 反而 +9 KB(已回退)。验证:`panelanim` **156/156**、`verify` **49/49**、`datacheck` **69/69**、`edgecheck` **46/46**;**A/B** 回退两处 UI 修复 **10 项如实失败**;`make release`/`make debug` 零警告。⚠️ **未完成(已如实记录)**:`PlotView.cpp`(13.7 K 行)与其它大文件的多文件化拆分、`LanePanelState` 抽取、模态提示解耦。 |
|
||||
| 2026-10-16 | DeepSeek-V4.1-Flash(**另一台设备**) | **收尾:`LanePanelState` 抽取 + 错误提示非模态化(把上一行的「未完成」清零,详见 §9.37 第八节与报告 `Documents/refactor_report_2026-10-16.md` §九)**。① **`Lane` 的 12 个平铺面板字段**(`edgePanelOpen/X/Y` × 4 类实验性功能)→ **4 个 `LanePanelState`**(`struct LanePanelState { bool open=true; double x=-1; double y=-1; }`),访问点全部改为 `lane.edgePanel.open` 形式;`RebuildLanes` 的 `LaneCarry` 同步收敛为 4 个 `LanePanelState`(逐字段赋值 → 整体赋值)。⚠️ 教训:**批量改名脚本不能对「声明」与「使用」跑同一组替换对**(会生成 `bool edgePanel.open = true;` 非法声明),声明处须单独重写。② **错误提示与模态阻塞解耦**:新增 `Application::SetModalErrorsEnabled(bool)`/`ModalErrorsEnabled()`(成员默认 `true`),`Initialize` **最先**执行 `SetModalErrorsEnabled(showCommand != SW_HIDE)`(隐藏窗口弹模态框 = 进程被钉死);`SetStatusMessage(err,true)` 允许模态时原样 `MessageBoxW`,否则走 `m_plot.ShowPersistentHint(text)`(绘图区底部非模态浮层);`PlotView` 新增公开 `ShowPersistentHint`。普通提示/空文本仍被忽略 ⇒ **交互行为不变**。③ **顺带修掉真实缺陷**:`PlotView::Paint` 在 `m_lanes.empty()` 时提前 `return`,提示浮层在其后绘制 ⇒ **未勾选任何信号时错误永远不可见**(正是"加载失败"场景),该分支补一次 `PaintHint(g)`。④ **新增探针 `.preflight/perf/errcheck` 19/19**:默认值/隐藏降级/宿主开关、**工作线程 + 5s 超时**判"不阻塞"(旧行为会永久阻塞 ⇒ 判失败并 `ExitProcess`,探针不挂)、`EnumWindows` 数本进程 `#32770` 顶层窗口数不变、提示文本/粘滞/需重绘/起始时刻、**像素级**"有/无提示"差异 3781 且全帧差异同为 3781。验证:`make release`/`make debug` 零警告,`Target.exe` **764 416 B**;`verify` 49/49、`datacheck` 69/69、`edgecheck` 46/46、`panelanim` 156/156。 |
|
||||
|
||||
---
|
||||
|
||||
@@ -2688,6 +2721,23 @@ Components/Shared/Src/UiControls.cpp
|
||||
实测 `PlotView` 拆分 +5 120 B、四个文件全部拆完 +10 240 B(共 +1.4%)。
|
||||
这是**可维护性换体积**的有意取舍;若日后必须压体积,优先考虑把工具函数收敛到单个 TU
|
||||
(用 `extern` 声明 + 单一实现)而不是撤销拆分。
|
||||
93. ⚠️⚠️ **批量改名脚本不能同时覆盖「声明」与「使用」**(`LanePanelState` 抽取时踩到):
|
||||
把 `edgePanelOpen → edgePanel.open` 这类「聚合化」替换对同时用在 `Lane`(使用处)和
|
||||
`RebuildLanes` 内部的 `LaneCarry`(**声明处**)上,会生成
|
||||
`bool edgePanel.open = true;` / `double edgePanel.x = -1.0;` 这类非法声明
|
||||
(报错为 `expected ';' at end of member declaration`)。
|
||||
正确做法:**声明处单独重写**(改为 4 个聚合成员),只让「使用处」走替换对;
|
||||
同一个替换对**不要**在同一个文件上跑第二遍(会二次展开,例如 `a.b` → `a.b.b`)。
|
||||
94. ⚠️⚠️ **任何「宿主级反馈通道」都必须做像素级验证**(本轮实测):
|
||||
`PlotView::Paint` 在 `m_lanes.empty()` 时**提前 return**,而提示浮层在 return 之后的叠加层绘制 ⇒
|
||||
**一个信号都没勾选时任何非模态错误都不可见**(恰恰是「文件加载失败」最需要提示的场景)。
|
||||
「通道存在」(`m_hintText` 被赋值、`HintNeedsAnimation()` 为真)**不等于「通道可见」**:
|
||||
必须抓后备缓冲、比较「有提示 / 无提示」两帧的差异像素(本例 3781 像素,且全帧差异同为 3781)。
|
||||
同理:模态对话框解耦要能**自动判定**(工作线程 + 超时,旧行为会永久阻塞 ⇒ 判失败并 `ExitProcess`,
|
||||
探针不会挂住;再用 `EnumWindows` 数本进程 `#32770` 顶层窗口数量证明没弹框)。
|
||||
95. ⚠️ **模态反馈必须是可关闭的**:`Application::SetModalErrorsEnabled` 默认 `true`,
|
||||
`Initialize(instance, showCommand)` 按 `showCommand != SW_HIDE` **自动降级**为
|
||||
`m_plot.ShowPersistentHint(text)`;隐藏窗口下弹模态框没人能点掉 = 进程被钉死。
|
||||
71. ⚠️ **`FitAll()` 在没有任何可见信号时不得置位 `Tab().ViewInitialized()`**:
|
||||
否则用户先连点几次「适应视图」(此时无信号被勾选)再勾选第一个信号,
|
||||
`Application::SynchronizeView` 会**跳过初次自适应**,视界停在“无信号”那次的整段范围上,
|
||||
|
||||
Reference in new issue
Block a user