修复组名编辑态点击穿透;浮动面板 GX 徽标悬停提示 + 点击滚动联动;最小网格高度提升到 81 逻辑像素

1) 组名/信号名处于编辑态时,在编辑框内双击、快速连点或框选编辑文本会让分组展开/收起。
   两处根因:
   - 行高大于输入框高度(上下各留 3 逻辑像素),起点落在内边距上时 OnEditMouseDown 返回
     false,宿主把按下交给 OnLButtonDown,命中分组行的 BODY 分支 ⇒ 折叠状态被切换;
   - 窗口带 CS_DBLCLKS,快速第二次按下被合成为 WM_LBUTTONDBLCLK,而 OnDoubleClick 没有
     编辑态保护,直接进入分组行双击逻辑 ⇒ 再次折叠 / 再次改名。
   修法:新增 NameEditAbsorbRect(输入框横向范围 × 整行高度)作为编辑态的“文本吸收区”:
   OnLButtonDown 命中即按文本操作处理(落点夹回输入框再算插入符),OnDoubleClick 命中即
   直接返回。横向仍限定在名称区域,同一行的复选框 / 「N 项」/ GX 徽标 / ✕ 继续可点。

2) 所有实验性功能浮动面板标题栏左侧的 GX 徽标:
   - EdgePanelLayout 新增 badge 矩形,成为绘制 / 悬停 / 手型光标 / 点击联动的唯一几何来源
     (命中顺序 close → badge → title,徽标在标题栏内部,放到 title 之后会被判成拖面板);
   - 悬停时徽标高亮 + 气泡提示(“G12 · 点击滚动到该网格” / “G12 · 已在视界内”),气泡在
     面板像素图层存进缓存之后绘制,避免被烘进位图后在鼠标移开后残留;
   - 点击调用 ScrollLaneIntoView:目标网格不可见时启动与“点选信号联动滚动”同源的平滑动画,
     已完整可见时不做任何改动。

3) 网格被压缩时的最小高度由 54 提升到 81 逻辑像素(1.5 倍)。同时修掉 m_minLaneHeight 被
   二次乘 m_scale 的隐患:Layout 里不再预先乘缩放,滚动条判定改用 laneCount × 81 × scale,
   与实际网格高度使用同一换算(125% 缩放下 128 个网格实测 101.25px = 81×1.25)。

验证(全部离屏:SW_HIDE 窗口 + 只注入合成消息 + BELOW_NORMAL,不占用鼠标键盘屏幕):
- 新增 .preflight/round3check(真实 TestData/MF4-Record.MF4,128 网格)31/31;
  A/B 临时禁用双击保护 ⇒ 1 项如实失败(证明断言有判别力);
- 回归:.preflight/editcheck 20/20、.preflight/check 137/137;
- make release / make debug 零警告。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-19 14:01:19 +08:00
1 parent 1e50494c41
commit be76f523f3
8 files changed
+307 -11

No files matched your search

@@ -1197,6 +1197,21 @@ namespace jdi
return (m_editField == StyleEditField::GROUP_TITLE) ? m_fonts->uiSmall : m_fonts->ui;
}
gd::RectF SignalPanel::NameEditAbsorbRect(const gd::RectF& field) const
{
if (field.Width <= 0.0f || m_editRow < 0 || m_editRow >= static_cast<int>(m_rows.size()))
{
return field;
}
// 与被编辑行同高:输入框上下各留 3 逻辑像素的行内边距,那一段点下去也必须算文本操作。
const gd::RectF row = RowRect(m_editRow);
if (row.Height <= 0.0f)
{
return field;
}
return gd::RectF(field.X, row.Y, field.Width, row.Height);
}
const SignalStyle* SignalPanel::StyleOf(const SignalRef& ref) const
{
return (m_dataSet != nullptr) ? m_dataSet->Style(ref) : nullptr;