修复组名编辑态点击穿透;浮动面板 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:
1 parent
1e50494c41
commit
be76f523f3
8 files changed
+307
-11
No files matched your search
@@ -821,7 +821,29 @@ namespace jdi
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return UiEditFieldMouseDown(EditFieldFont(), EditFieldRect(), m_edit, m_scale, x, y);
|
||||
|
||||
// ⚠️⚠️ **编辑态下,按在被编辑的那一行名称区域内(含输入框上下各 3px 的行内边距)
|
||||
// 都必须当作“文本操作”**,不能穿透成行点击。否则:容器行高 > 输入框高度,
|
||||
// 鼠标起点只要落在内边距上就会走 `OnLButtonDown` 的分组分支 ⇒ **分组被展开/收起**
|
||||
//(用户 2026-10-19 报告:“框选编辑文本时组会展开、收起”)。
|
||||
// 横向仍限定在名称区域内:同一行的复选框 / 「N 项」/ GX 徽标 / ✕ 继续可点。
|
||||
const gd::RectF field = EditFieldRect();
|
||||
if (field.Width > 0.0f)
|
||||
{
|
||||
const gd::RectF absorb = NameEditAbsorbRect(field);
|
||||
if (UiPointInRect(absorb, static_cast<float>(x), static_cast<float>(y)) &&
|
||||
!UiPointInRect(field, static_cast<float>(x), static_cast<float>(y)))
|
||||
{
|
||||
// 把落点夹回输入框,保证插入符换算与绘制使用同一套几何
|
||||
//(`UiEditFieldMouseDown` 自己会再算一次文本起点)。
|
||||
const int clampedX = static_cast<int>(std::lround(
|
||||
std::max(field.X + 1.0f, std::min(static_cast<float>(x), field.X + field.Width - 2.0f))));
|
||||
const int clampedY = static_cast<int>(std::lround(
|
||||
std::max(field.Y + 1.0f, std::min(static_cast<float>(y), field.Y + field.Height - 2.0f))));
|
||||
return UiEditFieldMouseDown(EditFieldFont(), field, m_edit, m_scale, clampedX, clampedY);
|
||||
}
|
||||
}
|
||||
return UiEditFieldMouseDown(EditFieldFont(), field, m_edit, m_scale, x, y);
|
||||
}
|
||||
|
||||
bool SignalPanel::OnEditMouseMove(int x)
|
||||
@@ -1245,6 +1267,22 @@ namespace jdi
|
||||
m_pendingCloseRow = -1;
|
||||
m_pendingFilterClear = false;
|
||||
|
||||
// ⚠️⚠️ **内联改名期间,名称区域整行都属于“文本操作区”**:
|
||||
// 行高大于输入框高度(上下各留 3 逻辑像素),鼠标起点落在内边距上时旧实现会继续往下走
|
||||
// 到分组行分支 ⇒ 分组被展开/收起(用户 2026-10-19 报告)。
|
||||
// 这里直接按“文本按下”处理(定位插入符 / 开始拖拽选区),绝不触发行点击。
|
||||
if (m_editField != StyleEditField::NONE && m_editRow >= 0 &&
|
||||
m_editRow < static_cast<int>(m_rows.size()))
|
||||
{
|
||||
const gd::RectF field = EditFieldRect();
|
||||
if (field.Width > 0.0f &&
|
||||
UiPointInRect(NameEditAbsorbRect(field), fx, fy))
|
||||
{
|
||||
OnEditMouseDown(x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 「筛选信号」输入框:单击进入编辑;点击其它位置则先结束筛选编辑(文本已实时生效)。
|
||||
if (IsOnFilterBox(x, y))
|
||||
{
|
||||
@@ -1647,6 +1685,23 @@ namespace jdi
|
||||
const float fx = static_cast<float>(x);
|
||||
const float fy = static_cast<float>(y);
|
||||
|
||||
// ⚠️⚠️ **编辑态下名称区域的双击必须被吃掉**:
|
||||
// 窗口带 `CS_DBLCLKS`,编辑时快速再点一下会被合成为 `WM_LBUTTONDBLCLK`,
|
||||
// 而旧实现直接进入行双击逻辑 ⇒ 分组被展开/收起(或再次进入改名)。
|
||||
// 输入框内的双击本该是“选词”,本组件只提供整段选择,因此这里保持现状不变、
|
||||
// 仅保证**不把双击当成行双击**(用户 2026-10-19 报告)。
|
||||
if (m_editField != StyleEditField::NONE)
|
||||
{
|
||||
const gd::RectF field = EditFieldRect();
|
||||
if (field.Width > 0.0f &&
|
||||
(UiPointInRect(field, fx, fy) ||
|
||||
(m_editRow >= 0 && m_editRow < static_cast<int>(m_rows.size()) &&
|
||||
UiPointInRect(NameEditAbsorbRect(field), fx, fy))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 样式区数值框:双击进入(或保持)输入状态。
|
||||
if (UiPointInRect(m_widthValueRect, fx, fy))
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user