fix(ui): 选区截取面板空白真正根因、拖拽指示线层序、新建分组修复、避让动画更顺

一、选区截取面板「条目区与按钮之间的空白」(连续三轮未修好的那个)
根因不是内容区几何,而是**底部固定区高度算了两行**:footerHeight 用
`buttonHeight * 2 + 6 + pad` 预留,而布局把「截取为新信号 / 原始信号截取」
两个按钮并排画在同一行 ⇒ 内容区下边界与按钮上边界之间空出一整行。
改为按一行算(两处:高度算式分支 + 布局几何分支同步修改)。
数值核对(scale=1.25、1 条可见信号):GAP 53.8px → 8.8px(= 一个 pad 的预期留白)。

二、拖拽插入指示线不再盖住被拖条目
PaintSignalDragGhost 的绘制顺序改为「插入指示线 → 阴影 → 幽灵行 → 描边」,
指示线始终位于跟随鼠标的那部分之下。

三、「移动到…」二级菜单
* 条目文案改为「组号 | 组名」(不再是括号形式)。
* 修复「新建分组」点了没反应:DataSet::AddGroup 拒收「无信号且无时间轴」的空分组,
  旧实现「先建空组再搬信号」必然在建组那一步失败。新增
  DataSet::MoveSignalToNewGroup 把建组 + 搬运时间轴 + 搬运信号做成原子操作(失败回滚)。
* TabConfig::RemapAfterSignalMove 在目标分组是新建时自行扩展 m_visible
  (调用方不再先 SyncToDataSet —— 那次同步会按旧下标清理引用)。
* Application::MoveSignalCore 增加 newGroupName 参数并返回 bool,避免失败仍报"已移动"。

四、信号拖拽避让动画更流畅
* 插值系数按真实帧间隔计算:1 - exp(-dt/22ms),dt 夹在 1~60ms,帧间隔抖动时不再忽快忽慢。
* 鼠标移动事件里也推进一次插值,快速拖动时让位效果跟得上指针。

验证:删 .o 全量重编译零 error / 零 warning,产物 875,008 B(< 1MB 预警阈值)。
本轮未占用鼠标/键盘/屏幕,未运行任何 GUI 探针;面板空白改为纯数值算式核对。
规则已同步到 Documents/agent_mem.md(含"改面板几何必须数值验证"的教训条目)。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-11-03 20:09:01 +08:00
1 parent 97b361dedd
commit 328a3b3b59
10 files changed
+259 -75

No files matched your search

+8 -5
View File
@@ -399,12 +399,14 @@ namespace jdi
// 因此不再有独立的底部编辑行;「边沿计数」走独立的**表格**分支。
const float buttonHeight = hasButton ? (kEdgePanelButtonHeight * m_scale) : 0.0f;
// 面板底部(内容区之下)占的纵向空间:有按钮时 = pad + 按钮 + pad,无按钮时只有 pad。
// ⚠️ 「选区截取」底部是**两个**按钮行(截取为新信号 / 原始信号截取),
// 因此 footer 要按两行算(用户 2026-11-03 要求)。
// ⚠️ **未启用双光标**时两个按钮都不显示 ⇒ footer 归零(否则按钮位置会留一大段空白)。
// ⚠️⚠️ 「选区截取」的两个按钮(截取为新信号 / 原始信号截取)是**并排在同一行**的
// (见下方的几何赋值),因此 footer 只能按**一行**算。旧实现按 `2 * 按钮高 + 6`
// 预留,而实际只画出并排的一行 ⇒ 内容区下方多出一整行“无意义的空白”
// (用户 2026-11-03 连续三轮报告的那片空白,根因就在这一行)。
// ⚠️ **未启用双光标**时两个按钮都不显示 ⇒ footer 归零(否则面板会留一大段空白)。
const bool clipReady = clipPanel && (Tab().CursorMode() == PlotCursorMode::DOUBLE);
const float footerHeight =
clipPanel ? (clipReady ? (buttonHeight * 2.0f + 6.0f * m_scale + pad) : 0.0f)
clipPanel ? (clipReady ? (buttonHeight + pad) : 0.0f)
: (hasButton ? (buttonHeight + pad) : 0.0f);
const float bottomPad = pad;
@@ -836,8 +838,9 @@ namespace jdi
const float scrollW = kFreeMarkerScrollWidth * m_scale;
const bool clipReadyHere =
clipPanel && (Tab().CursorMode() == PlotCursorMode::DOUBLE);
// ⚠️ 两处(高度算式与这里)必须同为**一行按钮**高:两个按钮并排,不是上下两行。
const float footerHeight =
clipPanel ? (clipReadyHere ? (buttonRowHeight * 2.0f + 6.0f * m_scale + pad) : 0.0f)
clipPanel ? (clipReadyHere ? (buttonRowHeight + pad) : 0.0f)
: (hasButton ? (buttonRowHeight + pad) : 0.0f);
// ⚠️⚠️ 内容区高度必须与高度算式
// `height = titleHeight + pad + view + bottomPad + footerHeight` **严格同源**: