修复自适应/首帧卡顿回归 + 派生信号烘值 + 图例交互与托底重做

一、性能(详见 agent_mem §9.19)
- AutoRangeLaneToView:把 DataSet::Style(ref) 从逐采样循环里提出来(远端新增的「调整」
  功能让它每个采样点解析两次,实测 147ms 劣化到 1200ms),并在「视界覆盖整条信号且
  无任何数值变换」时直接取信号已缓存的 min/max(O(1))。工具栏「Y 轴自适应」在全视图下
  1200ms → 0.02ms,结果与逐点扫描逐位一致;有变换时仍逐点套用与绘制相同的变换。
- 新增 WarmLaneLayersStep():加载后宽基底图层从未分配,用户第一次平移/选区放大时
  Paint 会在那一帧同步重建全部网格图层(首帧 64.3ms)。现在改为在「命中静态场景缓存」
  (视界未变、非拖拽)时用既有预算机制每帧至多补 1 个网格,把整批重建摊到静止帧;
  选区放大首帧 64.3ms → 13.0ms。

二、派生信号
- 「构建为新信号」把源信号的「调整」变换(系数 → 绝对值 → 垂直镜像 → Y 偏移,以及
  水平镜像=数据反序)烘进派生采样值,新信号样式一律保持默认(不再是"继承的指纹");
  仅时间轴偏移 offsetTime 因派生信号与源信号共用同一个文件时间轴仍需继承。

三、交互
- 网格 GX 拖拽让位判据改为「鼠标指针」:指针越过相邻网格的中心水平线即让位并出现吸附
  提示(原先按"被拖网格的中心",要求把整个网格拖过去一格才吸附)。
- GX 徽标悬停高亮:徽标本体在装饰缓存里被冻结,高亮改为贴图之后的叠加层,并新增
  m_hoverBadge 状态驱动重绘/取消;QueryCursor 在徽标上返回 IDC_HAND —— 与左侧信号列表
  里同一个 GX 徽标一致。
- 修复「中键平移过视界之后图例悬停/点击/双击改名全部失效」:整幅重绘路径会清空
  m_legendHits,而装饰缓存命中时 PaintLaneLegend 提前 return 导致永不重建。现在把该函数
  拆成「几何 → 命中/装饰矩形 → 绘制」三段,任何路径都先重建命中矩形。

四、绘制
- 每个信号图例单独加圆角托底(配色/圆角风格与 GX 徽标一致);装饰矩形改为逐块
  (徽标一块 + 每个条目一块 + 每个 Y 轴胶囊一块),不再覆盖整条图例带;每块托底先用
  不透明底色铺满「外接整数像素再外扩 1px」的矩形再画圆角 —— 消除「GX/图例周边旧波形
  像素残留」(逐像素验证:装饰矩形内 0 差异)。
- 图例悬停高亮改为不透明托底并在其上重绘色块与文字(否则不透明托底会把图例内容盖住),
  同时保留对应信号的曲线光晕;Y 轴刻度胶囊补不透明外接底色,消除同类残留。

验证:离屏 Application harness(窗口 SW_HIDE + 直接注入鼠标消息 + 从后备缓冲区截图,
不占用鼠标/键盘/屏幕)40/40 通过;zoomcheck 新增 mode 20-26 量化;make release 零警告。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-14 01:55:34 +08:00
1 parent 940b8e67e6
commit 7c32eca004
4 files changed
+590 -183

No files matched your search

+33 -2
View File
@@ -1767,6 +1767,14 @@ namespace jdi
EdgePanelKind m_pendingPanelCloseKind = EdgePanelKind::COUNT; /**< 待关闭面板的功能类型。 */
int m_hoverLane = -1; /**< 当前悬停网格下标。 */
/**
* @brief 上一帧鼠标是否悬停在某个网格的“GX”编号徽标上(是则记录网格下标,否则 -1)。
*
* 徽标本体绘制在静态场景 / 装饰缓存里(不随鼠标变化),悬停高亮是**贴图之后的叠加层**
*(见 PaintLegendHighlight)。鼠标在同一个网格的徽标范围内移动时 `m_hoverLane` 不变,
* 因此必须单独记住这个状态才能触发重绘与取消高亮。
*/
int m_hoverBadge = -1;
int m_mouseX = 0; /**< 最近一次鼠标横坐标(用于悬停提示定位)。 */
int m_mouseY = 0; /**< 最近一次鼠标纵坐标(用于悬停提示定位)。 */
bool m_spanHover = false; /**< 鼠标是否悬停在双光标差值标签上。 */
@@ -1859,12 +1867,23 @@ namespace jdi
gd::PointF m_edgePanelDragOffset; /**< 抓取面板时的相对偏移(保持不跳变)。 */
/**
* @brief 图例条目的命中信息(用于点选与双击改名)。
* @brief 图例条目的命中信息(用于点选与双击改名),同时记录"悬停高亮"重绘内容所需
* 的全部几何与颜色。
*
* 悬停高亮画在**装饰缓存贴图之后**(随鼠标变化,不能进缓存),且托底必须**不透明**
*(半透明叠加会让底下的旧像素透出来)。为了在"不透明托底"上仍能看到色块与文字,
* 这里把绘制时用到的色块矩形 / 文本矩形 / 颜色也一并记下来,供悬停时原样重绘。
*/
struct LegendHit
{
SignalRef ref; /**< 对应信号。 */
gd::RectF rect; /**< 条目矩形(已含色块与文本)。 */
gd::RectF rect; /**< 条目托底矩形(同时是命中区域)。 */
gd::RectF swatch; /**< 色块矩形。 */
gd::RectF text; /**< 文本矩形。 */
std::wstring label; /**< 已经过省略处理的显示文本。 */
std::uint32_t swatchColor = 0; /**< 色块颜色。 */
float swatchOpacity = 1.0f; /**< 色块不透明度。 */
std::uint32_t textColor = 0; /**< 文本颜色。 */
};
std::vector<LegendHit> m_legendHits; /**< 最近一次绘制时记录的图例条目矩形。 */
@@ -2484,6 +2503,18 @@ namespace jdi
* @return 队列中仍有待重画网格返回 true。
*/
bool RenderPendingLaneRebuilds(int budget);
/**
* @brief **空闲预热**:静置期间用既有预算机制**每帧至多补画 1 个网格图层**。
*
* 图层不存在(刚加载 / 网格数量变化)或还是旧跨度时,若等到用户**第一次**
* 平移 / 选区放大才去建,`Paint` 会在那一帧里**同步重建全部网格图层**
*(5 个网格实测 30~80ms)—— 这就是"选区放大的第一帧特别卡"的根因
*(该帧其余工作只有约 16ms 的占位拉伸)。
*
* 这里只在**视界没有变化**(命中静态场景缓存 ⇒ 本帧视图与缓存同源)且**不在拖拽中**时
* 调用一次,把整批重建的代价摊到若干静止帧上;任何交互帧都不再承担它。
*/
void WarmLaneLayersStep();
/** @brief 使全部图层失效。 */
void InvalidateWideBuffer(); /** @brief 释放全部图层位图。 */
void ReleaseWideBuffer();