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

- 拆分网格:实验性功能只由原网格的首个信号继承(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

@@ -934,12 +934,13 @@ namespace jdi
// ✕ 按钮:与面板/标签栏的其它 ✕ 一致,用手型光标作为可点击提示。
return LoadCursorW(nullptr, IDC_HAND);
}
// 「GX」编号徽标:悬停给出提示 + 手型光标;点击把该网格滚动到视界内。
// ⚠️ 必须排在标题栏之前(徽标位于标题栏矩形内部,否则会被判成“可拖拽”)。
// 「GX」编号徽标:用户 2026-10-21 明确要求**悬停不改变鼠标形状**,
// 也不弹出“是否在视界内”的浮动提示(点击行为不变:滚动到该网格)。
// ⚠️ 必须提前 return(而不是落到下面的标题栏判定),否则会被当成“可拖拽”。
if (layout.badge.Width > 0.0f &&
UiPointInRect(layout.badge, static_cast<float>(x), static_cast<float>(y)))
{
return LoadCursorW(nullptr, IDC_HAND);
return nullptr;
}
// 「展开 / 折起」三角指示器:可点击控件 ⇒ 手型光标。
if (layout.disclosure.Width > 0.0f &&
@@ -949,7 +950,9 @@ namespace jdi
}
if (UiPointInRect(layout.title, static_cast<float>(x), static_cast<float>(y)))
{
return LoadCursorW(nullptr, IDC_SIZEALL);
// 标题栏:悬停**保持箭头**,只有按住左键拖动时(`EDGE_PANEL_MOVE`,
// 见本函数开头的拖拽分支)才变成十字箭头(用户 2026-10-21 要求)。
return nullptr;
}
if ((static_cast<EdgePanelKind>(panelKind) == EdgePanelKind::MEAN ||
static_cast<EdgePanelKind>(panelKind) == EdgePanelKind::PEAK) &&
@@ -2720,8 +2723,9 @@ namespace jdi
int panelKind = 0;
if (TopPanelAtPoint(static_cast<float>(x), static_cast<float>(y), panelLane, panelKind))
{
// 标题栏双击 = 展开 / 折起该面板(折起的面板只显示标题栏)。
// ⚠️ 折起状态下标题栏是唯一可见区域,因此这里也是“双击重新展开”的入口。
// 标题栏双击 = 把该面板所属网格**滚动到视界内**(与单击 GX 徽标完全同效)。
// 用户 2026-10-21 明确要求:**只有双击标题栏**才触发这个联动,单击标题栏不触发
//(单击标题栏只是准备拖拽面板);面板的折起/展开只由左侧三角指示器负责。
{
const EdgePanelLayout titleLayout =
EdgePanelLayoutFor(panelLane, static_cast<EdgePanelKind>(panelKind));
@@ -2737,7 +2741,11 @@ namespace jdi
UiPointInRect(titleLayout.disclosure, static_cast<float>(x),
static_cast<float>(y))))
{
ToggleLanePanelCollapsed(panelLane, static_cast<EdgePanelKind>(panelKind));
m_dragMode = PlotDragMode::NONE;
if (ScrollLaneIntoView(panelLane))
{
SetHint(L"正在滚动到 G" + std::to_wstring(panelLane + 1) + L" 网格…");
}
return true;
}
}
@@ -2884,7 +2892,18 @@ namespace jdi
int panelKind = 0;
if (TopPanelAtPoint(fx, fy, panelLane, panelKind))
{
return true;
// ⚠️ 例外:**标题栏**(排除徽标 / ✕ / 折起三角)双击有明确语义 ——
// 把该面板所属网格滚动到视界内(用户 2026-10-21 要求,与单击 GX 徽标一致)。
// 其余落点仍然只有“按下”语义。
const EdgePanelLayout layout =
EdgePanelLayoutFor(panelLane, static_cast<EdgePanelKind>(panelKind));
const bool onTitle = layout.title.Width > 0.0f &&
UiPointInRect(layout.title, fx, fy) &&
!(layout.badge.Width > 0.0f && UiPointInRect(layout.badge, fx, fy)) &&
!(layout.close.Width > 0.0f && UiPointInRect(layout.close, fx, fy)) &&
!(layout.disclosure.Width > 0.0f &&
UiPointInRect(layout.disclosure, fx, fy));
return !onTitle;
}
}
// 右下角「回到最上方」浮动按钮:按下只登记、抬起才生效 ⇒ 只有单击语义。