收尾: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
@@ -509,6 +509,11 @@ namespace jdi
|
||||
m_hintShownAt = (text.empty()) ? 0 : GetTickCount64();
|
||||
}
|
||||
|
||||
void PlotView::ShowPersistentHint(const std::wstring& text)
|
||||
{
|
||||
SetHintSticky(text);
|
||||
}
|
||||
|
||||
void PlotView::ReleaseHint()
|
||||
{
|
||||
// 粘滞结束:从这里开始重新计时(先停留再淡出)。
|
||||
@@ -1125,11 +1130,11 @@ namespace jdi
|
||||
lane.edgeValue = (yMin + yMax) * 0.5;
|
||||
lane.edgeValueValid = true;
|
||||
}
|
||||
lane.edgePanelOpen = true;
|
||||
lane.edgePanel.open = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lane.edgePanelOpen = false;
|
||||
lane.edgePanel.open = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1177,11 +1182,11 @@ namespace jdi
|
||||
}
|
||||
}
|
||||
}
|
||||
lane.edgeCenterPanelOpen = true;
|
||||
lane.edgeCenterPanel.open = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lane.edgeCenterPanelOpen = false;
|
||||
lane.edgeCenterPanel.open = false;
|
||||
}
|
||||
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
||||
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
||||
@@ -1271,11 +1276,11 @@ namespace jdi
|
||||
}
|
||||
}
|
||||
}
|
||||
lane.weakPeakPanelOpen = true;
|
||||
lane.weakPeakPanel.open = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lane.weakPeakPanelOpen = false;
|
||||
lane.weakPeakPanel.open = false;
|
||||
}
|
||||
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
||||
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
||||
@@ -1360,11 +1365,11 @@ namespace jdi
|
||||
}
|
||||
}
|
||||
}
|
||||
lane.meanFilterPanelOpen = true;
|
||||
lane.meanFilterPanel.open = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lane.meanFilterPanelOpen = false;
|
||||
lane.meanFilterPanel.open = false;
|
||||
}
|
||||
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
||||
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
||||
|
||||
@@ -1282,21 +1282,21 @@ namespace jdi
|
||||
switch (m_edgePanelDragKind)
|
||||
{
|
||||
case EdgePanelKind::CENTER:
|
||||
lane.edgeCenterPanelX = left;
|
||||
lane.edgeCenterPanelY = top;
|
||||
lane.edgeCenterPanel.x = left;
|
||||
lane.edgeCenterPanel.y = top;
|
||||
break;
|
||||
case EdgePanelKind::MEAN:
|
||||
lane.meanFilterPanelX = left;
|
||||
lane.meanFilterPanelY = top;
|
||||
lane.meanFilterPanel.x = left;
|
||||
lane.meanFilterPanel.y = top;
|
||||
break;
|
||||
case EdgePanelKind::PEAK:
|
||||
lane.weakPeakPanelX = left;
|
||||
lane.weakPeakPanelY = top;
|
||||
lane.weakPeakPanel.x = left;
|
||||
lane.weakPeakPanel.y = top;
|
||||
break;
|
||||
case EdgePanelKind::COUNT:
|
||||
default:
|
||||
lane.edgePanelX = left;
|
||||
lane.edgePanelY = top;
|
||||
lane.edgePanel.x = left;
|
||||
lane.edgePanel.y = top;
|
||||
break;
|
||||
}
|
||||
m_dragMoved = true;
|
||||
|
||||
@@ -693,6 +693,9 @@ namespace jdi
|
||||
{
|
||||
InvalidateSceneCache();
|
||||
PaintEmptyState(g);
|
||||
// ⚠️ 空状态(尚未勾选任何信号)也必须绘制提示浮层:加载失败 / 解析异常正是
|
||||
// **最需要**非模态提示的场景,若在此提前返回,宿主的错误信息将永远不可见。
|
||||
PaintHint(g);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4667,9 +4670,9 @@ namespace jdi
|
||||
const bool enabled = meanFilter ? lane.meanFilter
|
||||
: (weakPeak ? lane.weakPeak
|
||||
: (centerAxis ? lane.edgeCenter : lane.edgeCount));
|
||||
const bool open = meanFilter ? lane.meanFilterPanelOpen
|
||||
: (weakPeak ? lane.weakPeakPanelOpen
|
||||
: (centerAxis ? lane.edgeCenterPanelOpen : lane.edgePanelOpen));
|
||||
const bool open = meanFilter ? lane.meanFilterPanel.open
|
||||
: (weakPeak ? lane.weakPeakPanel.open
|
||||
: (centerAxis ? lane.edgeCenterPanel.open : lane.edgePanel.open));
|
||||
if (!enabled || !open)
|
||||
{
|
||||
return layout;
|
||||
@@ -4748,12 +4751,12 @@ namespace jdi
|
||||
}
|
||||
|
||||
// 首次使用(位置为负)时自动放到绘图区右侧,并各网格依次错开,避免完全重叠。
|
||||
const double storedX = meanFilter ? lane.meanFilterPanelX
|
||||
: (weakPeak ? lane.weakPeakPanelX
|
||||
: (centerAxis ? lane.edgeCenterPanelX : lane.edgePanelX));
|
||||
const double storedY = meanFilter ? lane.meanFilterPanelY
|
||||
: (weakPeak ? lane.weakPeakPanelY
|
||||
: (centerAxis ? lane.edgeCenterPanelY : lane.edgePanelY));
|
||||
const double storedX = meanFilter ? lane.meanFilterPanel.x
|
||||
: (weakPeak ? lane.weakPeakPanel.x
|
||||
: (centerAxis ? lane.edgeCenterPanel.x : lane.edgePanel.x));
|
||||
const double storedY = meanFilter ? lane.meanFilterPanel.y
|
||||
: (weakPeak ? lane.weakPeakPanel.y
|
||||
: (centerAxis ? lane.edgeCenterPanel.y : lane.edgePanel.y));
|
||||
float left = (storedX >= 0.0)
|
||||
? static_cast<float>(storedX)
|
||||
: (m_plotRect.X + m_plotRect.Width - width - 16.0f * m_scale);
|
||||
@@ -5320,18 +5323,18 @@ namespace jdi
|
||||
const std::vector<Lane>& lanes = m_tab->Lanes();
|
||||
for (const Lane& lane : lanes)
|
||||
{
|
||||
mixFloat(static_cast<float>(lane.edgePanelX));
|
||||
mixFloat(static_cast<float>(lane.edgePanelY));
|
||||
mixFloat(static_cast<float>(lane.edgeCenterPanelX));
|
||||
mixFloat(static_cast<float>(lane.edgeCenterPanelY));
|
||||
mixFloat(static_cast<float>(lane.meanFilterPanelX));
|
||||
mixFloat(static_cast<float>(lane.meanFilterPanelY));
|
||||
mixFloat(static_cast<float>(lane.weakPeakPanelX));
|
||||
mixFloat(static_cast<float>(lane.weakPeakPanelY));
|
||||
mix(lane.edgePanelOpen ? 1ull : 0ull);
|
||||
mix(lane.edgeCenterPanelOpen ? 1ull : 0ull);
|
||||
mix(lane.meanFilterPanelOpen ? 1ull : 0ull);
|
||||
mix(lane.weakPeakPanelOpen ? 1ull : 0ull);
|
||||
mixFloat(static_cast<float>(lane.edgePanel.x));
|
||||
mixFloat(static_cast<float>(lane.edgePanel.y));
|
||||
mixFloat(static_cast<float>(lane.edgeCenterPanel.x));
|
||||
mixFloat(static_cast<float>(lane.edgeCenterPanel.y));
|
||||
mixFloat(static_cast<float>(lane.meanFilterPanel.x));
|
||||
mixFloat(static_cast<float>(lane.meanFilterPanel.y));
|
||||
mixFloat(static_cast<float>(lane.weakPeakPanel.x));
|
||||
mixFloat(static_cast<float>(lane.weakPeakPanel.y));
|
||||
mix(lane.edgePanel.open ? 1ull : 0ull);
|
||||
mix(lane.edgeCenterPanel.open ? 1ull : 0ull);
|
||||
mix(lane.meanFilterPanel.open ? 1ull : 0ull);
|
||||
mix(lane.weakPeakPanel.open ? 1ull : 0ull);
|
||||
mix(lane.edgeValueValid ? 1ull : 0ull);
|
||||
mixDouble(lane.edgeValue);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user