收尾: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:
DeepSeek V4.1 Flash committed 2026-10-16 04:38:12 +08:00
1 parent e6b7bf66ec
commit d2e6fdd085
11 files changed
+296 -132

No files matched your search

+22 -32
View File
@@ -701,6 +701,20 @@ namespace jdi
SignalRef m_selected; /**< 当前选中信号(跨标签页共享)。 */
};
/**
* @brief 一个实验性功能浮动面板的 UI 状态(展开开关 + 左上角位置)。
*
* 四类实验性功能(边沿计数 / 边沿计数(中心轴)/ 均值滤波 / 弱峰调整)各自持有一个,
* 因此 `Lane` 里不必再重复 12 个(4×3)同形字段 —— 这属于「同一含义被拆成多份」的冗余。
* 面板的**每信号参数**放在 `Lane::*Items` 里,与这里的位置/展开状态分开。
*/
struct LanePanelState
{
bool open = true; /**< 面板是否展开(点击面板上的 ✕ 后置 false)。 */
double x = -1.0; /**< 面板左上角横坐标(客户区像素;<0 表示自动定位)。 */
double y = -1.0; /**< 面板左上角纵坐标(<0 表示自动定位)。 */
};
/**
* @brief 一个波形网格(纵向泳道),可容纳多条信号叠加显示。
*/
@@ -769,14 +783,8 @@ namespace jdi
/** `edgeValue` 是否已经初始化(首次开启时取可见幅值范围的中点)。 */
bool edgeValueValid = false;
/** 边沿统计浮动面板是否展开(点击面板上的 ✕ 后置 false)。 */
bool edgePanelOpen = true;
/** 统计面板左上角位置(客户区像素;<0 表示自动定位到绘图区右侧)。 */
double edgePanelX = -1.0;
/** 统计面板左上角纵坐标(<0 表示自动定位)。 */
double edgePanelY = -1.0;
/** 边沿计数浮动面板的 UI 状态(展开 + 位置)。 */
LanePanelState edgePanel;
/**
* @brief 「实验性功能 → 边沿计数(中心轴)」开关。
@@ -810,14 +818,8 @@ namespace jdi
return FindEdgeCenterItem(ref) != nullptr;
}
/** 中心轴统计浮动面板是否展开。 */
bool edgeCenterPanelOpen = true;
/** 中心轴统计面板左上角位置(客户区像素;<0 表示自动定位)。 */
double edgeCenterPanelX = -1.0;
/** 中心轴统计面板左上角纵坐标(<0 表示自动定位)。 */
double edgeCenterPanelY = -1.0;
/** 中心轴边沿计数浮动面板的 UI 状态(展开 + 位置)。 */
LanePanelState edgeCenterPanel;
/**
* @brief 「实验性功能 → 均值滤波」开关。
@@ -850,14 +852,8 @@ namespace jdi
return FindMeanFilterItem(ref) != nullptr;
}
/** 均值滤波浮动面板是否展开。 */
bool meanFilterPanelOpen = true;
/** 均值滤波面板左上角位置(客户区像素;<0 表示自动定位)。 */
double meanFilterPanelX = -1.0;
/** 均值滤波面板左上角纵坐标(<0 表示自动定位)。 */
double meanFilterPanelY = -1.0;
/** 均值滤波浮动面板的 UI 状态(展开 + 位置)。 */
LanePanelState meanFilterPanel;
/**
* @brief 「实验性功能 → 弱峰调整」开关。
@@ -892,14 +888,8 @@ namespace jdi
return FindWeakPeakItem(ref) != nullptr;
}
/** 弱峰调整浮动面板是否展开。 */
bool weakPeakPanelOpen = true;
/** 弱峰调整面板左上角位置(客户区像素;<0 表示自动定位)。 */
double weakPeakPanelX = -1.0;
/** 弱峰调整面板左上角纵坐标(<0 表示自动定位)。 */
double weakPeakPanelY = -1.0;
/** 弱峰调整浮动面板的 UI 状态(展开 + 位置)。 */
LanePanelState weakPeakPanel;
};
/**