修复拆分网格误继承实验性功能 / 阶跃线宽 / 面板拖拽残影 / 自由标记卡顿与交互

- 拆分网格:实验性功能只由原网格的首个信号继承(LaneCarry::owner);
  SplitLane 只让第一份继承;新增 PruneLaneSignalItems 按 lane.signals 过滤四类
  逐信号条目(修复"新网格出现别人的固定点、面板里却查不到")
- 阶跃信号:包络带横向膨胀半径 ceil -> floor(1px 线宽不再把竖直沿撑成 3px)
- 浮动面板:面板位置移出 PanelGlobalKey(拖动单个面板不再重画全部面板),
  新增 vacatedRects 让"上一帧被移动/缩小/关闭的面板腾出的区域"也强制重画
- 自由标记:新增 FreeMarkerContents 内容缓存(键不含视界),大量固定点时拖光标/平移不再逐帧采样;
  透明度滑块与光标模式解耦(始终显示);悬停胶囊恢复不透明(瞄着被遮住的数据点时除外);
  胶囊与面板五列按实测文本撑开,不再省略
- 面板交互:折起指示器与信号列表组名同款三角;GX 徽标/标题栏悬停不改光标、移除徽标气泡;
  标题栏双击滚动到该网格(单击不触发,双击不再折起)
- 验证:新增离屏 .preflight/fixcheck 37/37(三处 A/B 均能如实失败);
  回归 round3check 31/31、round4check 34/34、round5check 5/5、editcheck 20/20、convcheck 18/18;
  make release/debug 零警告
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-21 17:21:09 +08:00
1 parent 3400ac7c29
commit 8f735d51be
8 files changed
+654 -198

No files matched your search

+52 -40
View File
@@ -419,61 +419,73 @@ namespace jdi
std::vector<Lane> pieces;
pieces.reserve(signals.size());
for (const SignalRef& ref : signals)
for (std::size_t signalSlot = 0; signalSlot < signals.size(); ++signalSlot)
{
const SignalRef& ref = signals[signalSlot];
// ⚠️ 只有**首个信号**所在的网格继承原网格的实验性功能(用户 2026-10-21 要求:
// 拆分后只有“拆分前的网格内的第一个信号”保留已应用的功能)。
// 否则拆分会把一个网格的功能(以及它的逐信号条目)复制到每一份上。
const bool primary = (signalSlot == 0);
Lane lane;
lane.autoRange = source.autoRange;
lane.yMin = source.yMin;
lane.yMax = source.yMax;
lane.fitYToSelection = source.fitYToSelection;
lane.edgeCount = source.edgeCount;
lane.edgeValue = source.edgeValue;
lane.edgeValueValid = source.edgeValueValid;
lane.edgePanel.open = source.edgePanel.open;
lane.edgePanel.collapsed = source.edgePanel.collapsed;
lane.edgePanel.x = source.edgePanel.x;
lane.edgePanel.y = source.edgePanel.y;
lane.edgeCenter = source.edgeCenter;
lane.edgeCenterPanel.open = source.edgeCenterPanel.open;
lane.edgeCenterPanel.collapsed = source.edgeCenterPanel.collapsed;
lane.edgeCenterPanel.x = source.edgeCenterPanel.x;
lane.edgeCenterPanel.y = source.edgeCenterPanel.y;
lane.weakPeak = source.weakPeak;
lane.weakPeakPanel.open = source.weakPeakPanel.open;
lane.weakPeakPanel.collapsed = source.weakPeakPanel.collapsed;
lane.weakPeakPanel.x = source.weakPeakPanel.x;
lane.weakPeakPanel.y = source.weakPeakPanel.y;
lane.meanFilter = source.meanFilter;
lane.meanFilterPanel.open = source.meanFilterPanel.open;
lane.meanFilterPanel.collapsed = source.meanFilterPanel.collapsed;
lane.meanFilterPanel.x = source.meanFilterPanel.x;
lane.meanFilterPanel.y = source.meanFilterPanel.y;
// 拆分后每个子网格只保留自己那个信号的均值滤波 / 中心轴 / 弱峰调整条目。
lane.meanFilterItems.clear();
lane.edgeCenterItems.clear();
lane.weakPeakItems.clear();
for (const Lane::MeanFilterItem& item : source.meanFilterItems)
if (primary)
{
if (item.ref == ref)
lane.edgeCount = source.edgeCount;
lane.edgeValue = source.edgeValue;
lane.edgeValueValid = source.edgeValueValid;
lane.edgePanel = source.edgePanel;
lane.edgeCenter = source.edgeCenter;
lane.edgeCenterPanel = source.edgeCenterPanel;
lane.weakPeak = source.weakPeak;
lane.weakPeakPanel = source.weakPeakPanel;
lane.meanFilter = source.meanFilter;
lane.meanFilterPanel = source.meanFilterPanel;
lane.freeMarker = source.freeMarker;
lane.freeMarkerCursor = source.freeMarkerCursor;
lane.freeMarkerPanel = source.freeMarkerPanel;
lane.freeMarkerOpacity = source.freeMarkerOpacity;
// 拆分后每个子网格只保留自己那个信号的均值滤波 / 中心轴 / 弱峰调整 / 自由标记条目。
for (const Lane::MeanFilterItem& item : source.meanFilterItems)
{
lane.meanFilterItems.push_back(item);
if (item.ref == ref)
{
lane.meanFilterItems.push_back(item);
}
}
}
for (const Lane::EdgeCenterItem& item : source.edgeCenterItems)
{
if (item.ref == ref)
for (const Lane::EdgeCenterItem& item : source.edgeCenterItems)
{
lane.edgeCenterItems.push_back(item);
if (item.ref == ref)
{
lane.edgeCenterItems.push_back(item);
}
}
}
for (const Lane::WeakPeakItem& item : source.weakPeakItems)
{
if (item.ref == ref)
for (const Lane::WeakPeakItem& item : source.weakPeakItems)
{
lane.weakPeakItems.push_back(item);
if (item.ref == ref)
{
lane.weakPeakItems.push_back(item);
}
}
for (const Lane::FreeMarkerItem& item : source.freeMarkerItems)
{
if (item.ref == ref)
{
lane.freeMarkerItems.push_back(item);
}
}
for (const SignalRef& collapsed : source.freeMarkerCollapsedGroups)
{
if (collapsed == ref)
{
lane.freeMarkerCollapsedGroups.push_back(collapsed);
}
}
}
lane.signals.push_back(ref);
PruneLaneSignalItems(lane);
pieces.push_back(std::move(lane));
}
// 用 pieces 替换原网格(插入到原位置,因此其后方的网格整体顺次后移)。