收尾: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
@@ -54,6 +54,22 @@ namespace jdi
|
|||||||
*/
|
*/
|
||||||
LRESULT HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
LRESULT HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置错误反馈是否使用模态对话框。
|
||||||
|
*
|
||||||
|
* 模态错误框会抢断用户当前操作;宿主在不需要打断(或无法交互)的场景下
|
||||||
|
* 应关闭它,此时错误信息改为在绘图区浮层中非模态展示。
|
||||||
|
*
|
||||||
|
* @param [IN] enabled true 表示允许弹出模态错误框。
|
||||||
|
*/
|
||||||
|
void SetModalErrorsEnabled(bool enabled) { m_modalErrorsEnabled = enabled; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询错误反馈是否使用模态对话框。
|
||||||
|
* @return 允许弹出模态错误框返回 true。
|
||||||
|
*/
|
||||||
|
bool ModalErrorsEnabled() const { return m_modalErrorsEnabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief 鼠标交互的作用目标。
|
* @brief 鼠标交互的作用目标。
|
||||||
@@ -410,6 +426,13 @@ namespace jdi
|
|||||||
bool m_hintTimerActive = false; /**< 提示浮层淡出定时器是否已启动。 */
|
bool m_hintTimerActive = false; /**< 提示浮层淡出定时器是否已启动。 */
|
||||||
/** 信号列表「滚动到目标信号」动画的定时器是否已启动(见 `SignalPanel::AdvanceScrollAnimation`)。 */
|
/** 信号列表「滚动到目标信号」动画的定时器是否已启动(见 `SignalPanel::AdvanceScrollAnimation`)。 */
|
||||||
bool m_scrollTimerActive = false;
|
bool m_scrollTimerActive = false;
|
||||||
|
/**
|
||||||
|
* 错误反馈是否使用模态对话框(默认开启;`Initialize` 遇到隐藏窗口时自动关闭)。
|
||||||
|
*
|
||||||
|
* 隐藏窗口(无人可点确定)下弹模态框等于把进程卡死,因此按启动方式自动降级为
|
||||||
|
* 绘图区非模态浮层提示;调用方也可用 `SetModalErrorsEnabled` 显式控制。
|
||||||
|
*/
|
||||||
|
bool m_modalErrorsEnabled = true;
|
||||||
std::wstring m_windowTitleText; /**< 上次写入窗口标题的完整文本(用于避免重复设置)。 */
|
std::wstring m_windowTitleText; /**< 上次写入窗口标题的完整文本(用于避免重复设置)。 */
|
||||||
int m_tabMenuIndex = -1; /**< 标签栏右键菜单的目标标签页下标。 */
|
int m_tabMenuIndex = -1; /**< 标签栏右键菜单的目标标签页下标。 */
|
||||||
int m_plotMenuLane = -1; /**< 绘图区右键菜单的目标网格下标。 */
|
int m_plotMenuLane = -1; /**< 绘图区右键菜单的目标网格下标。 */
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ namespace jdi
|
|||||||
{
|
{
|
||||||
m_instance = instance;
|
m_instance = instance;
|
||||||
|
|
||||||
|
// 隐藏窗口启动(自动化/后台)时没人能点掉模态错误框,会自动降级为非模态提示。
|
||||||
|
SetModalErrorsEnabled(showCommand != SW_HIDE);
|
||||||
|
|
||||||
EnableDpiAwareness();
|
EnableDpiAwareness();
|
||||||
m_dpi = QuerySystemDpi();
|
m_dpi = QuerySystemDpi();
|
||||||
m_scale = static_cast<float>(m_dpi) / 96.0f;
|
m_scale = static_cast<float>(m_dpi) / 96.0f;
|
||||||
@@ -487,12 +490,19 @@ namespace jdi
|
|||||||
|
|
||||||
void Application::SetStatusMessage(const std::wstring& text, bool isError)
|
void Application::SetStatusMessage(const std::wstring& text, bool isError)
|
||||||
{
|
{
|
||||||
// 界面不再占用底部空间显示常驻提示;仅把真实错误以对话框形式反馈给用户。
|
// 界面不再占用底部空间显示常驻提示;仅把真实错误反馈给用户。
|
||||||
if (!isError || text.empty())
|
if (!isError || text.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MessageBoxW(m_hwnd, text.c_str(), kWindowTitle, MB_ICONWARNING | MB_OK);
|
// 模态错误框会抢断用户当前操作,因此把"是否需要打断"交给宿主决定:
|
||||||
|
// 允许时弹框;不允许时改为绘图区底部的非模态浮层提示。
|
||||||
|
if (m_modalErrorsEnabled)
|
||||||
|
{
|
||||||
|
MessageBoxW(m_hwnd, text.c_str(), kWindowTitle, MB_ICONWARNING | MB_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_plot.ShowPersistentHint(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT Application::HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT Application::HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
|||||||
@@ -533,6 +533,16 @@ namespace jdi
|
|||||||
*/
|
*/
|
||||||
bool HintNeedsAnimation() const;
|
bool HintNeedsAnimation() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 以**非模态**方式向用户提示一条信息(绘图区底部浮层,停留至下一条提示替换)。
|
||||||
|
*
|
||||||
|
* 宿主(`Application`)把不宜用模态对话框打断的操作反馈(例如加载/导出错误)
|
||||||
|
* 交给本接口显示即可,也便于在无交互(隐藏窗口)场景下保持可用。
|
||||||
|
*
|
||||||
|
* @param [IN] text 提示文本;传空串则立即清除提示。
|
||||||
|
*/
|
||||||
|
void ShowPersistentHint(const std::wstring& text);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 清除已启用的时间光标。
|
* @brief 清除已启用的时间光标。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -509,6 +509,11 @@ namespace jdi
|
|||||||
m_hintShownAt = (text.empty()) ? 0 : GetTickCount64();
|
m_hintShownAt = (text.empty()) ? 0 : GetTickCount64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlotView::ShowPersistentHint(const std::wstring& text)
|
||||||
|
{
|
||||||
|
SetHintSticky(text);
|
||||||
|
}
|
||||||
|
|
||||||
void PlotView::ReleaseHint()
|
void PlotView::ReleaseHint()
|
||||||
{
|
{
|
||||||
// 粘滞结束:从这里开始重新计时(先停留再淡出)。
|
// 粘滞结束:从这里开始重新计时(先停留再淡出)。
|
||||||
@@ -1125,11 +1130,11 @@ namespace jdi
|
|||||||
lane.edgeValue = (yMin + yMax) * 0.5;
|
lane.edgeValue = (yMin + yMax) * 0.5;
|
||||||
lane.edgeValueValid = true;
|
lane.edgeValueValid = true;
|
||||||
}
|
}
|
||||||
lane.edgePanelOpen = true;
|
lane.edgePanel.open = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lane.edgePanelOpen = false;
|
lane.edgePanel.open = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1177,11 +1182,11 @@ namespace jdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lane.edgeCenterPanelOpen = true;
|
lane.edgeCenterPanel.open = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lane.edgeCenterPanelOpen = false;
|
lane.edgeCenterPanel.open = false;
|
||||||
}
|
}
|
||||||
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
||||||
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
||||||
@@ -1271,11 +1276,11 @@ namespace jdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lane.weakPeakPanelOpen = true;
|
lane.weakPeakPanel.open = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lane.weakPeakPanelOpen = false;
|
lane.weakPeakPanel.open = false;
|
||||||
}
|
}
|
||||||
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
||||||
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
||||||
@@ -1360,11 +1365,11 @@ namespace jdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lane.meanFilterPanelOpen = true;
|
lane.meanFilterPanel.open = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lane.meanFilterPanelOpen = false;
|
lane.meanFilterPanel.open = false;
|
||||||
}
|
}
|
||||||
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
// 关闭后若本标签页**已无任何预览曲线功能**,立即释放派生曲线数据(缓存 + 后台线程的
|
||||||
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
// thread_local 工作缓冲)—— 否则关掉面板后内存不会下降(用户报告)。
|
||||||
|
|||||||
@@ -1282,21 +1282,21 @@ namespace jdi
|
|||||||
switch (m_edgePanelDragKind)
|
switch (m_edgePanelDragKind)
|
||||||
{
|
{
|
||||||
case EdgePanelKind::CENTER:
|
case EdgePanelKind::CENTER:
|
||||||
lane.edgeCenterPanelX = left;
|
lane.edgeCenterPanel.x = left;
|
||||||
lane.edgeCenterPanelY = top;
|
lane.edgeCenterPanel.y = top;
|
||||||
break;
|
break;
|
||||||
case EdgePanelKind::MEAN:
|
case EdgePanelKind::MEAN:
|
||||||
lane.meanFilterPanelX = left;
|
lane.meanFilterPanel.x = left;
|
||||||
lane.meanFilterPanelY = top;
|
lane.meanFilterPanel.y = top;
|
||||||
break;
|
break;
|
||||||
case EdgePanelKind::PEAK:
|
case EdgePanelKind::PEAK:
|
||||||
lane.weakPeakPanelX = left;
|
lane.weakPeakPanel.x = left;
|
||||||
lane.weakPeakPanelY = top;
|
lane.weakPeakPanel.y = top;
|
||||||
break;
|
break;
|
||||||
case EdgePanelKind::COUNT:
|
case EdgePanelKind::COUNT:
|
||||||
default:
|
default:
|
||||||
lane.edgePanelX = left;
|
lane.edgePanel.x = left;
|
||||||
lane.edgePanelY = top;
|
lane.edgePanel.y = top;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_dragMoved = true;
|
m_dragMoved = true;
|
||||||
|
|||||||
@@ -693,6 +693,9 @@ namespace jdi
|
|||||||
{
|
{
|
||||||
InvalidateSceneCache();
|
InvalidateSceneCache();
|
||||||
PaintEmptyState(g);
|
PaintEmptyState(g);
|
||||||
|
// ⚠️ 空状态(尚未勾选任何信号)也必须绘制提示浮层:加载失败 / 解析异常正是
|
||||||
|
// **最需要**非模态提示的场景,若在此提前返回,宿主的错误信息将永远不可见。
|
||||||
|
PaintHint(g);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4667,9 +4670,9 @@ namespace jdi
|
|||||||
const bool enabled = meanFilter ? lane.meanFilter
|
const bool enabled = meanFilter ? lane.meanFilter
|
||||||
: (weakPeak ? lane.weakPeak
|
: (weakPeak ? lane.weakPeak
|
||||||
: (centerAxis ? lane.edgeCenter : lane.edgeCount));
|
: (centerAxis ? lane.edgeCenter : lane.edgeCount));
|
||||||
const bool open = meanFilter ? lane.meanFilterPanelOpen
|
const bool open = meanFilter ? lane.meanFilterPanel.open
|
||||||
: (weakPeak ? lane.weakPeakPanelOpen
|
: (weakPeak ? lane.weakPeakPanel.open
|
||||||
: (centerAxis ? lane.edgeCenterPanelOpen : lane.edgePanelOpen));
|
: (centerAxis ? lane.edgeCenterPanel.open : lane.edgePanel.open));
|
||||||
if (!enabled || !open)
|
if (!enabled || !open)
|
||||||
{
|
{
|
||||||
return layout;
|
return layout;
|
||||||
@@ -4748,12 +4751,12 @@ namespace jdi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 首次使用(位置为负)时自动放到绘图区右侧,并各网格依次错开,避免完全重叠。
|
// 首次使用(位置为负)时自动放到绘图区右侧,并各网格依次错开,避免完全重叠。
|
||||||
const double storedX = meanFilter ? lane.meanFilterPanelX
|
const double storedX = meanFilter ? lane.meanFilterPanel.x
|
||||||
: (weakPeak ? lane.weakPeakPanelX
|
: (weakPeak ? lane.weakPeakPanel.x
|
||||||
: (centerAxis ? lane.edgeCenterPanelX : lane.edgePanelX));
|
: (centerAxis ? lane.edgeCenterPanel.x : lane.edgePanel.x));
|
||||||
const double storedY = meanFilter ? lane.meanFilterPanelY
|
const double storedY = meanFilter ? lane.meanFilterPanel.y
|
||||||
: (weakPeak ? lane.weakPeakPanelY
|
: (weakPeak ? lane.weakPeakPanel.y
|
||||||
: (centerAxis ? lane.edgeCenterPanelY : lane.edgePanelY));
|
: (centerAxis ? lane.edgeCenterPanel.y : lane.edgePanel.y));
|
||||||
float left = (storedX >= 0.0)
|
float left = (storedX >= 0.0)
|
||||||
? static_cast<float>(storedX)
|
? static_cast<float>(storedX)
|
||||||
: (m_plotRect.X + m_plotRect.Width - width - 16.0f * m_scale);
|
: (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();
|
const std::vector<Lane>& lanes = m_tab->Lanes();
|
||||||
for (const Lane& lane : lanes)
|
for (const Lane& lane : lanes)
|
||||||
{
|
{
|
||||||
mixFloat(static_cast<float>(lane.edgePanelX));
|
mixFloat(static_cast<float>(lane.edgePanel.x));
|
||||||
mixFloat(static_cast<float>(lane.edgePanelY));
|
mixFloat(static_cast<float>(lane.edgePanel.y));
|
||||||
mixFloat(static_cast<float>(lane.edgeCenterPanelX));
|
mixFloat(static_cast<float>(lane.edgeCenterPanel.x));
|
||||||
mixFloat(static_cast<float>(lane.edgeCenterPanelY));
|
mixFloat(static_cast<float>(lane.edgeCenterPanel.y));
|
||||||
mixFloat(static_cast<float>(lane.meanFilterPanelX));
|
mixFloat(static_cast<float>(lane.meanFilterPanel.x));
|
||||||
mixFloat(static_cast<float>(lane.meanFilterPanelY));
|
mixFloat(static_cast<float>(lane.meanFilterPanel.y));
|
||||||
mixFloat(static_cast<float>(lane.weakPeakPanelX));
|
mixFloat(static_cast<float>(lane.weakPeakPanel.x));
|
||||||
mixFloat(static_cast<float>(lane.weakPeakPanelY));
|
mixFloat(static_cast<float>(lane.weakPeakPanel.y));
|
||||||
mix(lane.edgePanelOpen ? 1ull : 0ull);
|
mix(lane.edgePanel.open ? 1ull : 0ull);
|
||||||
mix(lane.edgeCenterPanelOpen ? 1ull : 0ull);
|
mix(lane.edgeCenterPanel.open ? 1ull : 0ull);
|
||||||
mix(lane.meanFilterPanelOpen ? 1ull : 0ull);
|
mix(lane.meanFilterPanel.open ? 1ull : 0ull);
|
||||||
mix(lane.weakPeakPanelOpen ? 1ull : 0ull);
|
mix(lane.weakPeakPanel.open ? 1ull : 0ull);
|
||||||
mix(lane.edgeValueValid ? 1ull : 0ull);
|
mix(lane.edgeValueValid ? 1ull : 0ull);
|
||||||
mixDouble(lane.edgeValue);
|
mixDouble(lane.edgeValue);
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-5
@@ -2230,12 +2230,44 @@ Components/Shared/Src/UiControls.cpp
|
|||||||
6. ⚠️ **拆分不会减小机器码,反而略增**:实测 754 176 → 764 416 B(+10 240 B,+1.4%),
|
6. ⚠️ **拆分不会减小机器码,反而略增**:实测 754 176 → 764 416 B(+10 240 B,+1.4%),
|
||||||
因为 `inline` 工具函数每个引用它的 TU 各生成一份(PE 无 ICF)。
|
因为 `inline` 工具函数每个引用它的 TU 各生成一份(PE 无 ICF)。
|
||||||
|
|
||||||
#### 八、本轮仍**未**完成(诚实记录)
|
#### 八、`LanePanelState` 抽取 + 错误提示非模态化(本轮补齐,同一轮次的第二遍)
|
||||||
|
|
||||||
1. `Lane` 抽出 `LanePanelState`(内聚性重构,非冗余清理):未执行。`Lane` 含 4 类实验性功能的
|
1. **`Lane` 的 12 个平铺面板字段**(`edgePanelOpen/X/Y` × 4 类实验性功能)→ **4 个聚合成员**
|
||||||
状态与各自面板坐标,建议后续把「开关 + 每信号参数 + 面板位置」抽成 `LanePanelState`。
|
`LanePanelState edgePanel / edgeCenterPanel / meanFilterPanel / weakPeakPanel`;
|
||||||
2. `SetStatusMessage(..., isError)` 的模态阻塞解耦:未执行(需要用户拍板提示样式)。
|
`LanePanelState { bool open=true; double x=-1; double y=-1; }`。
|
||||||
3. 上一轮建议的 MF4 压缩块 / `##DL` 数据列表:按用户要求继续不做。
|
访问点全部改为 `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(**另一台设备**) | **分组折起/展开动画 + 筛选态可折起(项数按筛选计数)+ 悬浮组名可交互与"先滚动再折起" + 「适应视图」与「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(**另一台设备**) | **动画改「抽拉卷尺」式刚性平移 + 筛选态折叠三角修正 + 样式区「目标」行绘制/布局修正(详见 §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(**另一台设备**) | **分组折起热区与改名输入框修正 + 数据模型去冗余(单一名称)+ 新增 `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%)。
|
实测 `PlotView` 拆分 +5 120 B、四个文件全部拆完 +10 240 B(共 +1.4%)。
|
||||||
这是**可维护性换体积**的有意取舍;若日后必须压体积,优先考虑把工具函数收敛到单个 TU
|
这是**可维护性换体积**的有意取舍;若日后必须压体积,优先考虑把工具函数收敛到单个 TU
|
||||||
(用 `extern` 声明 + 单一实现)而不是撤销拆分。
|
(用 `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()`**:
|
71. ⚠️ **`FitAll()` 在没有任何可见信号时不得置位 `Tab().ViewInitialized()`**:
|
||||||
否则用户先连点几次「适应视图」(此时无信号被勾选)再勾选第一个信号,
|
否则用户先连点几次「适应视图」(此时无信号被勾选)再勾选第一个信号,
|
||||||
`Application::SynchronizeView` 会**跳过初次自适应**,视界停在“无信号”那次的整段范围上,
|
`Application::SynchronizeView` 会**跳过初次自适应**,视界停在“无信号”那次的整段范围上,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
> 其余结构体(`SignalStyle` / `TabConfig` / `Lane` / `TimeAxis` / `SignalRef` / `EdgeScanState` 等)
|
> 其余结构体(`SignalStyle` / `TabConfig` / `Lane` / `TimeAxis` / `SignalRef` / `EdgeScanState` 等)
|
||||||
> 逐字段核对后未发现同类“同义多字段”现象;`Lane` 的“体量过大”属**内聚性**问题而非冗余,
|
> 逐字段核对后未发现同类“同义多字段”现象;`Lane` 的“体量过大”属**内聚性**问题而非冗余,
|
||||||
> 见 §五 的 `LanePanelState` 建议。
|
> 已按 §7.3 / §9.1 抽出 `LanePanelState`(本轮完成)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -263,16 +263,16 @@ Components/*(功能组件) ──▶ Components/Shared(UI 控件) ─
|
|||||||
|
|
||||||
组件文件数(拆分后):`PlotView` 6、`Application` 5、`SignalPanel` 5、`Shared` 2、`TabBar` 2、`Toolbar` 2、`Main` 2。
|
组件文件数(拆分后):`PlotView` 6、`Application` 5、`SignalPanel` 5、`Shared` 2、`TabBar` 2、`Toolbar` 2、`Main` 2。
|
||||||
|
|
||||||
### 7.3 `Lane` 的内聚性(上一轮建议 5)
|
### 7.3 `Lane` 的内聚性 —— **已完成(本轮补齐,见 §九)**
|
||||||
|
|
||||||
`Lane` 内含 4 类实验性功能的状态 + 各自的面板坐标,已超 200 行;建议抽出
|
`Lane` 内含 4 类实验性功能的状态 + 各自的面板坐标(12 个平铺字段);已抽出
|
||||||
`LanePanelState`(开关 + 每信号参数 + 面板位置),`Lane` 只保留结构与归属。
|
`LanePanelState { bool open; double x; double y; }`,`Lane` 只保留「开关 + 每信号参数 + 面板状态」
|
||||||
属**结构内聚**重构而非去冗余,需同步改 `DataModel` 与 `PlotView` 的多处访问点,本轮未做。
|
四项成员(`edgePanel` / `edgeCenterPanel` / `meanFilterPanel` / `weakPeakPanel`)。
|
||||||
|
|
||||||
### 7.4 错误提示与模态阻塞解耦(上一轮建议 1)
|
### 7.4 错误提示与模态阻塞解耦 —— **已完成(本轮补齐,见 §九)**
|
||||||
|
|
||||||
`SetStatusMessage(..., isError=true)` 仍直接 `MessageBoxW`;自动化 / 离屏场景与其耦合,
|
`SetStatusMessage(..., isError=true)` 不再是「无条件 `MessageBoxW`」:模态与否由宿主决定
|
||||||
建议改为宿主级非模态提示。本轮未做(与“不影响功能”的约束存在交互设计决策,需用户拍板样式)。
|
(`Application::SetModalErrorsEnabled`),隐藏窗口启动时**自动**降级为绘图区非模态提示。
|
||||||
|
|
||||||
### 7.5 MF4 压缩块 / 数据列表(上一轮建议 2–3)
|
### 7.5 MF4 压缩块 / 数据列表(上一轮建议 2–3)
|
||||||
|
|
||||||
@@ -318,3 +318,92 @@ Components/*(功能组件) ──▶ Components/Shared(UI 控件) ─
|
|||||||
* `Documents/agent_mem.md` 同步更新(§9.37 + §11.2 约束 + 变更日志)。
|
* `Documents/agent_mem.md` 同步更新(§9.37 + §11.2 约束 + 变更日志)。
|
||||||
* 上一轮报告 `Documents/refactor_report_2026-10-15.md` **已删除**(其有效内容已并入
|
* 上一轮报告 `Documents/refactor_report_2026-10-15.md` **已删除**(其有效内容已并入
|
||||||
`agent_mem.md` 与本文)。
|
`agent_mem.md` 与本文)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、收尾补记(同一轮次的第二遍:把「仍未完成」清空)
|
||||||
|
|
||||||
|
上一版报告在 §7.3 / §7.4 留下两项「本轮未做」。这一遍把它们做完,并在过程中又发现并修掉
|
||||||
|
一个**真实缺陷**。所有改动都是「结构内聚 + 反馈通道」类,**不改任何功能性行为**。
|
||||||
|
|
||||||
|
### 9.1 `LanePanelState`:`Lane` 的 12 个平铺面板字段 → 4 个聚合成员
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Utilities/Inc/DataModel.hpp
|
||||||
|
struct LanePanelState
|
||||||
|
{
|
||||||
|
bool open = true; /**< 浮动面板是否展开。 */
|
||||||
|
double x = -1.0; /**< 面板左上角 X(-1 表示尚未定位,首次绘制时自动摆放)。 */
|
||||||
|
double y = -1.0; /**< 面板左上角 Y。 */
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
* `Lane` 的 `edgePanelOpen/edgePanelX/edgePanelY` 等 **12 个字段**被
|
||||||
|
`LanePanelState edgePanel / edgeCenterPanel / meanFilterPanel / weakPeakPanel` 取代;
|
||||||
|
访问点全部改为 `lane.edgePanel.open` 这样的**结构内聚**形式(`DataModelTab.cpp` 的快照拷贝、
|
||||||
|
`PlotViewInteraction.cpp` 的浮动面板拖拽、`PlotViewPaint.cpp` 的面板层序绘制)。
|
||||||
|
* `RebuildLanes` 内部的「网格自身状态携带」结构 `LaneCarry` 同步收敛:原来 12 个平铺字段
|
||||||
|
改为 4 个 `LanePanelState`,逐字段赋值也简化为整体赋值(少 8 行、少 8 个易漏字段)。
|
||||||
|
* **收益**:参数的归属一眼可辨(哪个坐标属于哪个功能)、新增一类实验性功能时只需加 1 个成员;
|
||||||
|
同时把「3 个字段必须一起改」的隐式约束变成类型约束。
|
||||||
|
* ⚠️ 教训(已写进 `agent_mem.md`):批量改名脚本**不能**在「声明」与「使用」上跑同一组替换对 ——
|
||||||
|
对 `Lane` 使用的 `edgePanelOpen → edgePanel.open` 用在 `LaneCarry` 的**声明行**上会得到
|
||||||
|
`bool edgePanel.open = true;` 这种非法声明。修正方式是**声明处单独重写**(4 个聚合成员),
|
||||||
|
只让「使用处」走替换对。
|
||||||
|
|
||||||
|
### 9.2 错误反馈:模态对话框 → 可关闭(隐藏窗口自动降级为非模态提示)
|
||||||
|
|
||||||
|
* `Application` 新增 `SetModalErrorsEnabled(bool)` / `ModalErrorsEnabled()`,
|
||||||
|
成员 `m_modalErrorsEnabled` **默认 `true`**(保持交互场景的既有行为);
|
||||||
|
`Initialize(instance, showCommand)` 在**最先**执行 `SetModalErrorsEnabled(showCommand != SW_HIDE)`。
|
||||||
|
理由:隐藏窗口(自动化/离屏)下弹模态框**没有人能点掉**,等于把进程钉死。
|
||||||
|
* `SetStatusMessage(text, /*isError*/true)` 分支化:
|
||||||
|
允许模态 → 原样 `MessageBoxW`;不允许 → `m_plot.ShowPersistentHint(text)`(绘图区底部浮层)。
|
||||||
|
普通提示(`isError == false`)与空文本依旧被忽略 —— **交互体验与此前完全一致**。
|
||||||
|
* `PlotView` 新增公开接口 `ShowPersistentHint(text)`(内部转 `SetHintSticky`),
|
||||||
|
把「私有提示机制」变成「宿主可用的反馈通道」,且不暴露粘滞/淡出等内部细节。
|
||||||
|
* **顺带修掉一个真实缺陷**:`PlotView::Paint` 在 `m_lanes.empty()` 时**提前 return**,
|
||||||
|
而提示浮层在 return 之后的叠加层里绘制 ⇒ **「一个信号都没勾选」时任何错误都显示不出来**,
|
||||||
|
恰恰是「文件加载失败」这一最需要提示的场景。修法是在该分支补一次 `PaintHint(g)`。
|
||||||
|
这一条是**探针先失败、才回头发现的**(见 9.3),说明「非模态通道」本身也需要像素级验证。
|
||||||
|
|
||||||
|
### 9.3 新增离屏探针 `.preflight/perf/errcheck`(19/19)
|
||||||
|
|
||||||
|
模态/非模态无法用「截图看着对」来判断,因此写成可自动判定的断言:
|
||||||
|
|
||||||
|
| 断言组 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 默认与降级 | 默认 `ModalErrorsEnabled() == true`;`Initialize(..., SW_HIDE)` 后为 `false`;宿主可显式开关 |
|
||||||
|
| 不被打断 | 从**工作线程**调用 `SetStatusMessage(err,true)`,5 s 内必须返回(旧行为会永久阻塞 ⇒ 直接判失败并 `ExitProcess`,探针**不会挂住**) |
|
||||||
|
| 不产生对话框 | 用 `EnumWindows` 统计**本进程**中类名 `#32770` 的顶层窗口,调用前后数量不变 |
|
||||||
|
| 走到提示通道 | `m_hintText` 等于错误文本、`m_hintSticky == true`、`HintNeedsAnimation() == true`、`m_hintShownAt != 0` |
|
||||||
|
| **真的画出来** | 「有提示」帧与「无提示」帧在绘图区矩形内的差异像素 **3781**,且全帧差异 3781(说明差异**只**来自提示) |
|
||||||
|
| 提示不吞消息 | 成功提示 / 空文本错误不进入提示通道;第二条错误顶掉第一条 |
|
||||||
|
|
||||||
|
### 9.4 本轮验证(全部离屏,`SW_HIDE` + 无输入注入 + `BELOW_NORMAL`)
|
||||||
|
|
||||||
|
| 项目 | 结果 |
|
||||||
|
| --- | --- |
|
||||||
|
| `make release` / `make debug` | 通过,**零警告** |
|
||||||
|
| 产物体积 | `Build/Release/Target.exe` **764 416 B**(与拆分后一致;本轮是纯结构改动,未引入新代码膨胀) |
|
||||||
|
| `.preflight/perf/verify`(界面与像素) | **49/49** |
|
||||||
|
| `.preflight/perf/datacheck`(数据层) | **69/69** |
|
||||||
|
| `.preflight/perf/edgecheck`(边沿统计) | **46/46** |
|
||||||
|
| `.preflight/perf/panelanim`(分组折起动画 + 两处 UI 修复) | **156/156** |
|
||||||
|
| `.preflight/perf/errcheck`(本轮新增) | **19/19** |
|
||||||
|
| 上一遍的 A/B(回退两处 UI 修复) | 如实失败 **9** 项(失败文案逐条点名「点组名不应折起」「改名框不应包住条目计数」),恢复后 156/156 |
|
||||||
|
|
||||||
|
### 9.5 本轮变更清单
|
||||||
|
|
||||||
|
```
|
||||||
|
修改 Utilities/Inc/DataModel.hpp 新增 LanePanelState;Lane 的 12 个平铺面板字段 → 4 个聚合成员
|
||||||
|
修改 Utilities/Src/DataModelInternal.hpp LaneCarry 同步收敛为 4 个 LanePanelState(含整体赋值简化)
|
||||||
|
修改 Utilities/Src/DataModelTab.cpp 面板状态快照拷贝改用 .open/.x/.y
|
||||||
|
修改 Components/PlotView/Src/PlotViewInteraction.cpp 浮动面板拖拽改用 .open/.x/.y
|
||||||
|
修改 Components/PlotView/Src/PlotViewPaint.cpp 面板层序绘制同改;空状态分支补 PaintHint(缺陷修复)
|
||||||
|
修改 Components/PlotView/Inc/PlotView.hpp 新增公开 ShowPersistentHint
|
||||||
|
修改 Components/PlotView/Src/PlotViewFeatures.cpp 实现 ShowPersistentHint
|
||||||
|
修改 Components/Application/Inc/Application.hpp SetModalErrorsEnabled / ModalErrorsEnabled / m_modalErrorsEnabled
|
||||||
|
修改 Components/Application/Src/Application.cpp Initialize 按 showCommand 自动降级;SetStatusMessage 分支化
|
||||||
|
新增 .preflight/perf/errcheck_main.cpp 模态/非模态解耦探针(gitignored,不随产物提交)
|
||||||
|
```
|
||||||
+22
-32
@@ -701,6 +701,20 @@ namespace jdi
|
|||||||
SignalRef m_selected; /**< 当前选中信号(跨标签页共享)。 */
|
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 一个波形网格(纵向泳道),可容纳多条信号叠加显示。
|
* @brief 一个波形网格(纵向泳道),可容纳多条信号叠加显示。
|
||||||
*/
|
*/
|
||||||
@@ -769,14 +783,8 @@ namespace jdi
|
|||||||
/** `edgeValue` 是否已经初始化(首次开启时取可见幅值范围的中点)。 */
|
/** `edgeValue` 是否已经初始化(首次开启时取可见幅值范围的中点)。 */
|
||||||
bool edgeValueValid = false;
|
bool edgeValueValid = false;
|
||||||
|
|
||||||
/** 边沿统计浮动面板是否展开(点击面板上的 ✕ 后置 false)。 */
|
/** 边沿计数浮动面板的 UI 状态(展开 + 位置)。 */
|
||||||
bool edgePanelOpen = true;
|
LanePanelState edgePanel;
|
||||||
|
|
||||||
/** 统计面板左上角位置(客户区像素;<0 表示自动定位到绘图区右侧)。 */
|
|
||||||
double edgePanelX = -1.0;
|
|
||||||
|
|
||||||
/** 统计面板左上角纵坐标(<0 表示自动定位)。 */
|
|
||||||
double edgePanelY = -1.0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 「实验性功能 → 边沿计数(中心轴)」开关。
|
* @brief 「实验性功能 → 边沿计数(中心轴)」开关。
|
||||||
@@ -810,14 +818,8 @@ namespace jdi
|
|||||||
return FindEdgeCenterItem(ref) != nullptr;
|
return FindEdgeCenterItem(ref) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 中心轴统计浮动面板是否展开。 */
|
/** 中心轴边沿计数浮动面板的 UI 状态(展开 + 位置)。 */
|
||||||
bool edgeCenterPanelOpen = true;
|
LanePanelState edgeCenterPanel;
|
||||||
|
|
||||||
/** 中心轴统计面板左上角位置(客户区像素;<0 表示自动定位)。 */
|
|
||||||
double edgeCenterPanelX = -1.0;
|
|
||||||
|
|
||||||
/** 中心轴统计面板左上角纵坐标(<0 表示自动定位)。 */
|
|
||||||
double edgeCenterPanelY = -1.0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 「实验性功能 → 均值滤波」开关。
|
* @brief 「实验性功能 → 均值滤波」开关。
|
||||||
@@ -850,14 +852,8 @@ namespace jdi
|
|||||||
return FindMeanFilterItem(ref) != nullptr;
|
return FindMeanFilterItem(ref) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 均值滤波浮动面板是否展开。 */
|
/** 均值滤波浮动面板的 UI 状态(展开 + 位置)。 */
|
||||||
bool meanFilterPanelOpen = true;
|
LanePanelState meanFilterPanel;
|
||||||
|
|
||||||
/** 均值滤波面板左上角位置(客户区像素;<0 表示自动定位)。 */
|
|
||||||
double meanFilterPanelX = -1.0;
|
|
||||||
|
|
||||||
/** 均值滤波面板左上角纵坐标(<0 表示自动定位)。 */
|
|
||||||
double meanFilterPanelY = -1.0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 「实验性功能 → 弱峰调整」开关。
|
* @brief 「实验性功能 → 弱峰调整」开关。
|
||||||
@@ -892,14 +888,8 @@ namespace jdi
|
|||||||
return FindWeakPeakItem(ref) != nullptr;
|
return FindWeakPeakItem(ref) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 弱峰调整浮动面板是否展开。 */
|
/** 弱峰调整浮动面板的 UI 状态(展开 + 位置)。 */
|
||||||
bool weakPeakPanelOpen = true;
|
LanePanelState weakPeakPanel;
|
||||||
|
|
||||||
/** 弱峰调整面板左上角位置(客户区像素;<0 表示自动定位)。 */
|
|
||||||
double weakPeakPanelX = -1.0;
|
|
||||||
|
|
||||||
/** 弱峰调整面板左上角纵坐标(<0 表示自动定位)。 */
|
|
||||||
double weakPeakPanelY = -1.0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -78,24 +78,16 @@ namespace jdi
|
|||||||
bool edgeCount = false;
|
bool edgeCount = false;
|
||||||
double edgeValue = 0.0;
|
double edgeValue = 0.0;
|
||||||
bool edgeValueValid = false;
|
bool edgeValueValid = false;
|
||||||
bool edgePanelOpen = true;
|
LanePanelState edgePanel;
|
||||||
double edgePanelX = -1.0;
|
|
||||||
double edgePanelY = -1.0;
|
|
||||||
bool edgeCenter = false;
|
bool edgeCenter = false;
|
||||||
std::vector<Lane::EdgeCenterItem> edgeCenterItems;
|
std::vector<Lane::EdgeCenterItem> edgeCenterItems;
|
||||||
bool edgeCenterPanelOpen = true;
|
LanePanelState edgeCenterPanel;
|
||||||
double edgeCenterPanelX = -1.0;
|
|
||||||
double edgeCenterPanelY = -1.0;
|
|
||||||
bool meanFilter = false;
|
bool meanFilter = false;
|
||||||
std::vector<Lane::MeanFilterItem> meanFilterItems;
|
std::vector<Lane::MeanFilterItem> meanFilterItems;
|
||||||
bool meanFilterPanelOpen = true;
|
LanePanelState meanFilterPanel;
|
||||||
double meanFilterPanelX = -1.0;
|
|
||||||
double meanFilterPanelY = -1.0;
|
|
||||||
bool weakPeak = false;
|
bool weakPeak = false;
|
||||||
std::vector<Lane::WeakPeakItem> weakPeakItems;
|
std::vector<Lane::WeakPeakItem> weakPeakItems;
|
||||||
bool weakPeakPanelOpen = true;
|
LanePanelState weakPeakPanel;
|
||||||
double weakPeakPanelX = -1.0;
|
|
||||||
double weakPeakPanelY = -1.0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 先记下每个信号原来所在网格的网格自身状态:
|
// 先记下每个信号原来所在网格的网格自身状态:
|
||||||
@@ -123,24 +115,16 @@ namespace jdi
|
|||||||
carry.edgeCount = lane.edgeCount;
|
carry.edgeCount = lane.edgeCount;
|
||||||
carry.edgeValue = lane.edgeValue;
|
carry.edgeValue = lane.edgeValue;
|
||||||
carry.edgeValueValid = lane.edgeValueValid;
|
carry.edgeValueValid = lane.edgeValueValid;
|
||||||
carry.edgePanelOpen = lane.edgePanelOpen;
|
carry.edgePanel = lane.edgePanel;
|
||||||
carry.edgePanelX = lane.edgePanelX;
|
|
||||||
carry.edgePanelY = lane.edgePanelY;
|
|
||||||
carry.edgeCenter = lane.edgeCenter;
|
carry.edgeCenter = lane.edgeCenter;
|
||||||
carry.edgeCenterItems = lane.edgeCenterItems;
|
carry.edgeCenterItems = lane.edgeCenterItems;
|
||||||
carry.edgeCenterPanelOpen = lane.edgeCenterPanelOpen;
|
carry.edgeCenterPanel = lane.edgeCenterPanel;
|
||||||
carry.edgeCenterPanelX = lane.edgeCenterPanelX;
|
|
||||||
carry.edgeCenterPanelY = lane.edgeCenterPanelY;
|
|
||||||
carry.meanFilter = lane.meanFilter;
|
carry.meanFilter = lane.meanFilter;
|
||||||
carry.meanFilterItems = lane.meanFilterItems;
|
carry.meanFilterItems = lane.meanFilterItems;
|
||||||
carry.meanFilterPanelOpen = lane.meanFilterPanelOpen;
|
carry.meanFilterPanel = lane.meanFilterPanel;
|
||||||
carry.meanFilterPanelX = lane.meanFilterPanelX;
|
|
||||||
carry.meanFilterPanelY = lane.meanFilterPanelY;
|
|
||||||
carry.weakPeak = lane.weakPeak;
|
carry.weakPeak = lane.weakPeak;
|
||||||
carry.weakPeakItems = lane.weakPeakItems;
|
carry.weakPeakItems = lane.weakPeakItems;
|
||||||
carry.weakPeakPanelOpen = lane.weakPeakPanelOpen;
|
carry.weakPeakPanel = lane.weakPeakPanel;
|
||||||
carry.weakPeakPanelX = lane.weakPeakPanelX;
|
|
||||||
carry.weakPeakPanelY = lane.weakPeakPanelY;
|
|
||||||
for (const SignalRef& ref : lane.signals)
|
for (const SignalRef& ref : lane.signals)
|
||||||
{
|
{
|
||||||
previousCarry.emplace_back(ref, carry);
|
previousCarry.emplace_back(ref, carry);
|
||||||
@@ -165,24 +149,24 @@ namespace jdi
|
|||||||
lane.edgeCount = carry.edgeCount;
|
lane.edgeCount = carry.edgeCount;
|
||||||
lane.edgeValue = carry.edgeValue;
|
lane.edgeValue = carry.edgeValue;
|
||||||
lane.edgeValueValid = carry.edgeValueValid;
|
lane.edgeValueValid = carry.edgeValueValid;
|
||||||
lane.edgePanelOpen = carry.edgePanelOpen;
|
lane.edgePanel.open = carry.edgePanel.open;
|
||||||
lane.edgePanelX = carry.edgePanelX;
|
lane.edgePanel.x = carry.edgePanel.x;
|
||||||
lane.edgePanelY = carry.edgePanelY;
|
lane.edgePanel.y = carry.edgePanel.y;
|
||||||
lane.edgeCenter = carry.edgeCenter;
|
lane.edgeCenter = carry.edgeCenter;
|
||||||
lane.edgeCenterItems = carry.edgeCenterItems;
|
lane.edgeCenterItems = carry.edgeCenterItems;
|
||||||
lane.edgeCenterPanelOpen = carry.edgeCenterPanelOpen;
|
lane.edgeCenterPanel.open = carry.edgeCenterPanel.open;
|
||||||
lane.edgeCenterPanelX = carry.edgeCenterPanelX;
|
lane.edgeCenterPanel.x = carry.edgeCenterPanel.x;
|
||||||
lane.edgeCenterPanelY = carry.edgeCenterPanelY;
|
lane.edgeCenterPanel.y = carry.edgeCenterPanel.y;
|
||||||
lane.meanFilter = carry.meanFilter;
|
lane.meanFilter = carry.meanFilter;
|
||||||
lane.meanFilterItems = carry.meanFilterItems;
|
lane.meanFilterItems = carry.meanFilterItems;
|
||||||
lane.meanFilterPanelOpen = carry.meanFilterPanelOpen;
|
lane.meanFilterPanel.open = carry.meanFilterPanel.open;
|
||||||
lane.meanFilterPanelX = carry.meanFilterPanelX;
|
lane.meanFilterPanel.x = carry.meanFilterPanel.x;
|
||||||
lane.meanFilterPanelY = carry.meanFilterPanelY;
|
lane.meanFilterPanel.y = carry.meanFilterPanel.y;
|
||||||
lane.weakPeak = carry.weakPeak;
|
lane.weakPeak = carry.weakPeak;
|
||||||
lane.weakPeakItems = carry.weakPeakItems;
|
lane.weakPeakItems = carry.weakPeakItems;
|
||||||
lane.weakPeakPanelOpen = carry.weakPeakPanelOpen;
|
lane.weakPeakPanel.open = carry.weakPeakPanel.open;
|
||||||
lane.weakPeakPanelX = carry.weakPeakPanelX;
|
lane.weakPeakPanel.x = carry.weakPeakPanel.x;
|
||||||
lane.weakPeakPanelY = carry.weakPeakPanelY;
|
lane.weakPeakPanel.y = carry.weakPeakPanel.y;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 收集全部可见信号引用。
|
// 收集全部可见信号引用。
|
||||||
|
|||||||
@@ -429,21 +429,21 @@ namespace jdi
|
|||||||
lane.edgeCount = source.edgeCount;
|
lane.edgeCount = source.edgeCount;
|
||||||
lane.edgeValue = source.edgeValue;
|
lane.edgeValue = source.edgeValue;
|
||||||
lane.edgeValueValid = source.edgeValueValid;
|
lane.edgeValueValid = source.edgeValueValid;
|
||||||
lane.edgePanelOpen = source.edgePanelOpen;
|
lane.edgePanel.open = source.edgePanel.open;
|
||||||
lane.edgePanelX = source.edgePanelX;
|
lane.edgePanel.x = source.edgePanel.x;
|
||||||
lane.edgePanelY = source.edgePanelY;
|
lane.edgePanel.y = source.edgePanel.y;
|
||||||
lane.edgeCenter = source.edgeCenter;
|
lane.edgeCenter = source.edgeCenter;
|
||||||
lane.edgeCenterPanelOpen = source.edgeCenterPanelOpen;
|
lane.edgeCenterPanel.open = source.edgeCenterPanel.open;
|
||||||
lane.edgeCenterPanelX = source.edgeCenterPanelX;
|
lane.edgeCenterPanel.x = source.edgeCenterPanel.x;
|
||||||
lane.edgeCenterPanelY = source.edgeCenterPanelY;
|
lane.edgeCenterPanel.y = source.edgeCenterPanel.y;
|
||||||
lane.weakPeak = source.weakPeak;
|
lane.weakPeak = source.weakPeak;
|
||||||
lane.weakPeakPanelOpen = source.weakPeakPanelOpen;
|
lane.weakPeakPanel.open = source.weakPeakPanel.open;
|
||||||
lane.weakPeakPanelX = source.weakPeakPanelX;
|
lane.weakPeakPanel.x = source.weakPeakPanel.x;
|
||||||
lane.weakPeakPanelY = source.weakPeakPanelY;
|
lane.weakPeakPanel.y = source.weakPeakPanel.y;
|
||||||
lane.meanFilter = source.meanFilter;
|
lane.meanFilter = source.meanFilter;
|
||||||
lane.meanFilterPanelOpen = source.meanFilterPanelOpen;
|
lane.meanFilterPanel.open = source.meanFilterPanel.open;
|
||||||
lane.meanFilterPanelX = source.meanFilterPanelX;
|
lane.meanFilterPanel.x = source.meanFilterPanel.x;
|
||||||
lane.meanFilterPanelY = source.meanFilterPanelY;
|
lane.meanFilterPanel.y = source.meanFilterPanel.y;
|
||||||
// 拆分后每个子网格只保留自己那个信号的均值滤波 / 中心轴 / 弱峰调整条目。
|
// 拆分后每个子网格只保留自己那个信号的均值滤波 / 中心轴 / 弱峰调整条目。
|
||||||
lane.meanFilterItems.clear();
|
lane.meanFilterItems.clear();
|
||||||
lane.edgeCenterItems.clear();
|
lane.edgeCenterItems.clear();
|
||||||
|
|||||||
Reference in new issue
Block a user