修复五项交互缺陷:折起后滚动条 / 单点信号样式 / 线宽实时生效 / 网格菜单限高滚动 / 点选信号滚动绘图区
1) 分组折起后再展开,信号列表的滚动条消失(筛选态与常规态均可复现)
- 根因:AdvanceGroupAnimations 只在“折起完成”时重建行集合;而“展开完成”那一帧
m_contentHeight 从收起态跳回展开态,却没有任何路径重算滚动条可见性 ⇒ 滚动条停在隐藏。
- 修法:任一方向动画结束都 m_rowsDirty = true + BuildRows(),并每帧 RefreshScrollBar(false)。
⚠️ 动画期间不夹取滚动偏移,避免打断与滚动同步的折起动画(scrollSynced)。
2) 单点信号(finiteCount == 1)默认绘制方式由「点线」改为「散点」
- ApplySinglePointDefaultStyle → DrawMode::SCATTER(仍取最大线宽)。
- 新增 SignalPanel::ModeOptionEnabled:单点信号的「线段」「点线」置灰、不可点、
且不参与悬停高亮(避免“看着能点其实点不动”);样式区的绘制与命中都用它。
- PlotView::UpdateAutoScatterStyles 跳过单点信号,否则“放大自动点线”会把它又改回「点线」。
3) 拖动线宽滑块完全不生效(拖动时线宽不变、松手瞬间变了、再移动鼠标又变回去)
- 根因一:AcquirePolyline 的折线缓存键没有 lineWidth,而 BuildPolyline 把线宽烘进
包络带几何(每个像素列的上下包络各向外扩 max(1,线宽)*scale*0.5,「梳状」判定也依赖它)
⇒ 稠密信号(采样数 > 绘图区宽度)永远复用旧线宽的顶点与包络带。
- 根因二:样式补丁只更新“静态场景缓存 + 后备缓冲区”,而每网格图层(宽基底)仍是旧样式像素,
下一帧命中“宽基底快路径”时把新样式覆盖回旧像素。
- 修法:PolylineCacheEntry 增加 lineWidth 并进比较;
样式补丁之后 QueueLaneRebuild(受影响网格) + RenderPendingLaneRebuilds(1)(沿用每帧至多 1 个的预算)。
4) 「目标」行的 GX 标签复用「所属网格」菜单,并先给 PopupMenu 增加「限高 + 条目区滚动 + 尾部固定项」
- MenuLayoutConstraint::maxHeight(OpenLaneMenu 传客户区高度的 62%);
- 固定区 = 最后一个分隔线及其之后的条目(即「新建网格」)始终钉在菜单底部,其余条目可滚动;
- 滚轮滚动条目区(Application 在菜单内滚动时不再关闭菜单,其余情形保持既有行为);
- 键盘移动悬停项自动滚入可视区(EnsureItemVisible);ItemAtPoint 要求条目同时命中滚动视口;
- 滚动区文本用 UiTextClipped(GDI 文本不遵循 GDI+ SetClip),并跳过完全不可见的条目(性能);
- BuildLayout 不再无条件清零 m_scrollOffset(否则 RebuildLayout 会把滚轮位置吃掉);
- 「目标」行 GX 标签点击**不参与**联动滚动(悬停联动保留)。
5) 点选信号名 ⇒ 绘图区自动把目标网格滚动到可视区内(上百个独立网格时旧有高亮无法定位)
- SignalPanel::RequestPlotLaneScroll / TakePlotLaneScrollRequest;
Application::ApplyPendingPlotLaneScroll(WM_LBUTTONDOWN 的面板分支);
PlotView::ScrollLaneIntoView(在可视区上方就上滚、在下方就下滚、已完整可见则不动)。
- 只有“点击信号名”触发;悬停绝不改变视图;勾选框 / GX 徽标 / 移除 ✕ 也不触发。
验证(全部离屏执行,窗口 SW_HIDE + 只注入合成消息 + 进程与线程 BELOW_NORMAL,
不移动真实光标、不抢焦点、不截屏):
- 新增 .preflight/check(不入库)68/68 通过;
- A/B:五处修复全部回退 ⇒ 17 项如实失败(B 4 / C 4 / D 7 / E 2);“折起后滚动条”需要
逐帧重绘驱动动画才能复现,单独回退时 ⇒ 5 项如实失败;恢复后 68/68;
- make release / make debug 零警告。
其它:
- 按要求删除工作区 Tools/(structcheck 脚本)并移除 Makefile 的 structcheck 目标;
- Documents/agent_mem.md 同步:新增 §9.38、§11.2 第 97–103 条与变更日志一行。
This commit is contained in:
1 parent
9cf6b2fedc
commit
2904699eae
19 files changed
+743
-350
No files matched your search
@@ -38,7 +38,9 @@ namespace jdi
|
||||
/**
|
||||
* @brief **只含一个有效采样点**的信号的初始线宽(取样式允许的最大线宽)。
|
||||
*
|
||||
* 单个数据点在「点线」模式下就是一个圆点,半径与线宽成正比;取最大值才能看清。
|
||||
* 单个数据点的初始绘制方式是「散点」,半径随线宽线性增长;取最大值才能看清那个点。
|
||||
* ⚠️ 用户 2026-10-16 要求:初始绘制方式由「点线」改为「**散点**」,
|
||||
* 同时信号面板「样式」行的「线段」/「点线」两个按钮对该信号置灰。
|
||||
* ⚠️ 曾经还对「有效采样点 2…16」的信号也设了「点线 + 2px」的默认样式,
|
||||
* 该需求已**作废**(用户 2026-10-15 明确取消):放大后自动切「点线」的机制
|
||||
* 已经覆盖了那个场景,无需再改默认样式。
|
||||
|
||||
@@ -79,6 +79,24 @@ namespace jdi
|
||||
bool keepOpen = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 打开菜单时的附加布局约束。
|
||||
*/
|
||||
struct MenuLayoutConstraint
|
||||
{
|
||||
/**
|
||||
* @brief 菜单允许的最大高度(**客户区像素**,0 = 不限制)。
|
||||
*
|
||||
* 超过该高度时菜单不再变高:**最后一个分隔线及其之后的条目固定在菜单底部**
|
||||
* (典型用法:把「新建网格」钉在底部),其上方的内容成为可滚动的条目区
|
||||
*(鼠标滚轮 / 键盘方向键滚动)。
|
||||
*
|
||||
* 用于「条目数不定」的菜单:例如加载含上百个信号的 MF4 并把每个信号都放进独立网格时,
|
||||
* 「所属网格」菜单会有上百个条目(既超出屏幕、绘制开销也很大)。
|
||||
*/
|
||||
float maxHeight = 0.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 菜单选择结果。
|
||||
*/
|
||||
@@ -127,9 +145,11 @@ namespace jdi
|
||||
* @param [IN] expandUp 为 true 时菜单**向上展开**,且 `(x, y)` 是菜单的**左下角**
|
||||
* (用于“二级面板贴在按钮左上方”这类锚定);为 false(默认)时向右下展开,
|
||||
* `(x, y)` 是菜单的左上角。
|
||||
* @param [IN] constraint 附加布局约束(最大高度 / 超长时可滚动),默认不限制。
|
||||
*/
|
||||
void Open(MenuScope scope, const gd::RectF& bounds, int x, int y,
|
||||
const std::vector<MenuItem>& items, bool expandUp = false);
|
||||
const std::vector<MenuItem>& items, bool expandUp = false,
|
||||
const MenuLayoutConstraint& constraint = MenuLayoutConstraint());
|
||||
|
||||
/**
|
||||
* @brief 关闭菜单。
|
||||
@@ -196,6 +216,19 @@ namespace jdi
|
||||
*/
|
||||
bool ContainsPoint(int x, int y) const;
|
||||
|
||||
/**
|
||||
* @brief 菜单是否因内容过长而启用了滚动(条目区可滚动、尾部分隔线之后固定到底部)。
|
||||
* @return 启用滚动返回 true。
|
||||
*/
|
||||
bool IsScrollable() const { return m_open && m_scrollEnabled; }
|
||||
|
||||
/**
|
||||
* @brief 处理鼠标滚轮:滚动可滚动菜单的条目区。
|
||||
* @param [IN] delta 滚轮增量(`WM_MOUSEWHEEL` 的 `GET_WHEEL_DELTA_WPARAM`)。
|
||||
* @return 滚动位置发生变化返回 true。
|
||||
*/
|
||||
bool OnMouseWheel(int delta);
|
||||
|
||||
/**
|
||||
* @brief 设置剪贴板所有者窗口句柄(供内联输入框复制/粘贴)。
|
||||
* @param [IN] host 宿主窗口句柄,允许为空。
|
||||
@@ -392,6 +425,13 @@ namespace jdi
|
||||
*/
|
||||
void PaintSubmenu(gd::Graphics& g);
|
||||
|
||||
/**
|
||||
* @brief 键盘移动悬停项后,把该项滚动到可滚动区的可视范围内。
|
||||
* @param [IN] index 目标条目下标。
|
||||
* @return 滚动偏移发生变化返回 true。
|
||||
*/
|
||||
bool EnsureItemVisible(int index);
|
||||
|
||||
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
|
||||
const Theme* m_theme = nullptr; /**< 主题资源。 */
|
||||
float m_scale = 1.0f; /**< DPI 缩放比例。 */
|
||||
@@ -427,6 +467,20 @@ namespace jdi
|
||||
int m_buildY = 0; /**< 最近一次排布使用的锚点纵坐标。 */
|
||||
bool m_buildExpandUp = false; /**< 最近一次排布是否为“向上展开(锚点为左下角)”。 */
|
||||
|
||||
/** 最近一次使用的布局约束(`RebuildLayout` 复用)。 */
|
||||
MenuLayoutConstraint m_constraint;
|
||||
/**
|
||||
* @brief 尾部固定区(钉在菜单底部)的**首个条目下标**;-1 表示没有固定项。
|
||||
*
|
||||
* 由 `BuildLayout` 在启用滚动时设为最后一个分隔线的下标:该分隔线及其之后的条目
|
||||
* (典型:「新建网格」)始终画在菜单底部,其上方的内容在滚动区内。
|
||||
*/
|
||||
int m_pinnedIndex = -1;
|
||||
bool m_scrollEnabled = false; /**< 条目区是否可滚动(内容超过 `maxHeight` 时启用)。 */
|
||||
float m_scrollOffset = 0.0f; /**< 滚动区当前的滚动偏移(像素,0 = 顶部)。 */
|
||||
float m_scrollRegionHeight = 0.0f; /**< 滚动区的内容总高(像素)。 */
|
||||
gd::RectF m_scrollViewport; /**< 滚动区的可视矩形(也是滚动区条目的裁剪矩形)。 */
|
||||
|
||||
bool m_subOpen = false; /**< 二级子菜单是否展开。 */
|
||||
int m_subParentIndex = -1; /**< 展开子菜单的父项下标。 */
|
||||
gd::RectF m_subRect; /**< 子菜单整体矩形。 */
|
||||
|
||||
Reference in new issue
Block a user