修复浮动面板双击穿透、网格高亮触发来源、新增样式区「目标」行与联动平滑滚动
用户 2026-10-15 第六轮报告的四个问题与要求(详见 Documents/agent_mem.md §9.34):
1. 在网格内的实验性功能浮动面板上双击任意位置会穿透到下层网格,导致网格触发自适应。
根因:PlotView::OnDoubleClick 在“差值标签 / 光标标签 / 光标线 / 图例”都不命中时
无条件调用 FitAll()。
修法:在该函数最前面(高于一切下层命中)用 TopPanelAtPoint() 判定,命中浮动面板
则直接消费(面板自身双击无额外语义)。确立“上层元素的交互不得影响下层”的规则。
2. 未开启任何工具栏功能时鼠标移到网格上会让整个网格变色高亮(旧需求已不适用)。
修法:取消“鼠标在网格里移动就高亮”的行为;改为在信号选择区域悬停某条信号时,
若该信号已被勾选绘制到某个网格,则该网格变色高亮,并且该信号曲线本身也高亮;
鼠标移开即恢复。悬停未勾选的信号不产生任何高亮。
实现:PlotView 新增 m_externalHoverSignal + SetExternalHoverSignal()(与 m_hoverSignal
分开保存,因为绘图区 OnMouseLeave 会清掉后者,而列表悬停时鼠标不在绘图区内)、
EffectiveHoverLane();SignalPanel 新增 HoveredSignal(),并在 InvalidateRows()
里一并作废;Application::Render() 每帧同步(覆盖 WM_MOUSELEAVE / 数据变化 /
切换标签页等全部路径)。GX 徽标的悬停高亮仍按鼠标位置独立判定。
3. 在信号样式自定义区域最上方(预设颜色色块之上)新增「目标」行。
内容:当前正在被编辑的目标信号名称;若它已绘制到网格,则在名称后方显示所在 GX 标签。
交互:与信号选择区域的信号行一致 —— 名称/GX 标签悬停有高亮提示,且悬停时同样触发
该信号所在网格高亮 + 曲线高亮;单击不进入编辑(只触发联动滚动),双击才进入改名
(复用 StyleEditField::SIGNAL_NAME,m_editRow < 0 表示目标是选中信号)。
实现:SignalPanel 新增 m_targetRowRect / PaintTargetRow / UpdateTargetRowGeometry
(名称宽度与“是否有 GX 标签”都可能在不重排时变化,因此按需重算并带缓存键)、
StyleHit::TARGET_NAME / TARGET_BADGE;DesiredStyleHeight() 与 LayoutStyleControls()
相应多算一行。
4. 联动机制更新:从文件导入大量信号(如 MF4 的 124 条)时,被选中的信号可能被滚动到
可见范围之外而找不到。
修法:新增 SignalPanel::ScrollToSignalAnimated()(+ AdvanceScrollAnimation),
触发联动时把信号列表平滑滚动到目标信号完整可见:
* 目标在视界上方 ⇒ 向上滚动,且顶部让出一个组行高度,避免被悬浮组名遮挡;
* 目标在视界下方 ⇒ 向下滚动到完整露出;
* 已经完整可见则不动;
* ease-out cubic(越远越快、靠近变慢),时长 = clamp(距离×0.35ms, 130, 300),
总时长有上限;用户滚轮 / 拖滚动条立即取消动画。
触发点:绘图区内把某条信号选为当前目标(点击图例、点击信号曲线、双击图例改名)
⇒ PlotView::SelectSignal() 发布请求(TakePanelScrollRequest()),宿主在鼠标消息
处理后调用 ApplyPendingPanelScroll();样式自定义区的任何交互(预设色块、自定义
颜色入口、样式按钮、线宽/透明度滑块与数值框、「系数/偏移」「镜像」二级菜单、
绝对值)以及「目标」行的单击也都会触发同一次滚动。
宿主:Application 新增 16ms 定时器(kScrollTimerId)驱动动画,并由 Render 自管开关
(与提示浮层淡出同一套做法)。
验证(全部离屏,不占用鼠标 / 键盘 / 屏幕):
- .preflight/check(SW_HIDE + 只注入合成消息 + 进程/线程 BELOW_NORMAL)**73/73 通过**,
连跑 3 次稳定:[A] 浮动面板双击不移视界,且对照组(空白处双击)必须触发自适应;
[B] 鼠标在网格里移动不高亮;[C] 列表悬停 → 网格高亮 + 移开恢复 + 未勾选信号不高亮;
[D] 目标行的布局/占位/GX 标签位置与显隐/悬停联动/单击不编辑 + 双击改名(初始文本正确);
[E] 长列表 122 行:动画分多帧、单调、时长上限 300ms、目标完整可见且不被悬浮组名遮挡、
已可见时不动、滚轮取消动画;[F] 样式区交互与绘图区联动都会滚动到目标并完整显示;
[G] 布局回归(目标行在列表下方、样式区仍完整、默认无悬停与高亮)。
- A/B 判别:回退六处实现后 **15 项如实失败**(含"面板双击仍触发自适应"、"鼠标移到网格即高亮"、
"目标行不联动"、"联动瞬移而非动画")。
- make release:全部源文件重新编译 **零警告**;链接用临时 `make release TARGET_FILE_NAME=Target_check` 通过。
同步记忆:Documents/agent_mem.md 新增 §9.34、§11.2 第 72–75 条硬约束、变更日志新行。
This commit is contained in:
1 parent
73389f424c
commit
cb9d3e4b8f
7 files changed
+848
-32
No files matched your search
@@ -1863,6 +1863,85 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
|
||||
---
|
||||
|
||||
### 9.34 浮动面板不穿透 / 网格高亮改由信号列表触发 / 样式区「目标」行 / 联动平滑滚动(本轮,起源设备)
|
||||
|
||||
> 本轮四项(用户 2026-10-15 第六轮)。离屏验证 `.preflight/check` **73/73 通过**(连跑 3 次稳定);
|
||||
> **A/B** 回退六处实现后 **15 项如实失败**。
|
||||
|
||||
#### 一、浮动面板上双击不再穿透到网格(用户报告)
|
||||
|
||||
- **根因**:实验性功能的浮动面板绘制在网格之上,但 `PlotView::OnDoubleClick` 在
|
||||
"差值标签 → 光标标签 → 光标线 → 图例" 都不命中时**无条件** `FitAll()` ⇒
|
||||
在面板上双击任意位置都会让网格莫名其妙地自适应一次。
|
||||
- **修法**:在 `OnDoubleClick` 的**最前面**(高于一切下层命中)用
|
||||
`TopPanelAtPoint()` 判定,命中浮动面板则直接消费(面板自身双击无额外语义)。
|
||||
这是"上层元素的交互不得影响下层"的通用做法,与 `QueryCursor` / `OnLButtonDown`
|
||||
里已有的面板守卫同源。
|
||||
|
||||
#### 二、网格变色高亮改由"信号列表悬停"触发(用户重新定义)
|
||||
|
||||
- **旧行为(已取消)**:鼠标在网格里移动 ⇒ `m_hoverLane = LaneAtY(y)` ⇒ 整个网格变色高亮。
|
||||
- **新行为**:
|
||||
* 鼠标**在网格里移动不再触发**任何网格高亮;
|
||||
* 在**信号列表**里悬停某条信号 ⇒ 若它已勾选绘制到某个网格,则该网格变色高亮,
|
||||
**并且该信号曲线本身也高亮**(复用 `PaintSignalHalo`);鼠标移开即恢复;
|
||||
* 悬停**未勾选**的信号不产生任何高亮(`LaneOfSignal` 只认可见信号);
|
||||
* 悬停信号行的 ✕(移除)**不算**"悬停到该信号"。
|
||||
- **实现要点**:
|
||||
* `PlotView` 新增 `m_externalHoverSignal` + `SetExternalHoverSignal()`:
|
||||
⚠️ **必须与 `m_hoverSignal` 分开**——绘图区的 `OnMouseLeave` 会清掉后者,
|
||||
而列表悬停时鼠标恰恰不在绘图区内;
|
||||
* 新增 `PlotView::EffectiveHoverLane()`:`m_hoverLane`(浮动面板悬停)优先,
|
||||
否则取外部悬停信号所在网格;`PaintHoverHighlight` 与光晕都改用它 /
|
||||
`m_hoverSignal ?: m_externalHoverSignal`;
|
||||
* `SignalPanel` 新增 `HoveredSignal()`(列表信号行 / 「目标」行),
|
||||
⚠️ 不能用 `m_hoverRow` 现算(鼠标移出列表即被清、行下标会因重建而失效),
|
||||
且在 `InvalidateRows()` 里一并作废(结构变化后悬停引用不再可信);
|
||||
* 同步时机:`Application::Render()` **每帧**同步(覆盖 WM_MOUSELEAVE、数据变化、
|
||||
切换标签页等全部改变悬停的路径,而不只是 WM_MOUSEMOVE)。
|
||||
* GX 徽标的悬停高亮仍按鼠标纵坐标现算(它与"悬停网格高亮"已解耦)。
|
||||
|
||||
#### 三、样式区顶部「目标」行(用户要求)
|
||||
|
||||
- 位置:样式自定义区**最上方**(预设颜色色块之上),与其余五行同高同间距
|
||||
(`DesiredStyleHeight()` 因此多算一行;标签列文字「目标」)。
|
||||
- 内容:当前**正在被编辑的目标信号**(= 选中信号)的名称;
|
||||
**已绘制到网格时**在名称**后方**显示它所在的 GX 标签(`TargetLaneIndex()`)。
|
||||
- 交互(用户要求"与信号选择区域的信号相同"):
|
||||
* 名称悬停 ⇒ 一层 `hover` 背景;GX 标签悬停 ⇒ `accentSoft` 底 + `accent` 边;
|
||||
两者都用手型光标;
|
||||
* **悬停名称 / GX 标签也触发绘图区的网格高亮 + 曲线高亮**(与列表悬停同效);
|
||||
* **单击不进入编辑**,只触发"滚动到目标信号"的联动;**双击**才进入改名
|
||||
(复用 `StyleEditField::SIGNAL_NAME`,用 `m_editRow < 0` 表示"目标是选中信号");
|
||||
* 名称颜色与列表一致:已绘制 = `text`,未绘制 = `textMuted`。
|
||||
- ⚠️ 名称 / GX 标签的矩形依赖**文本实际宽度**与**是否已绘制**,
|
||||
这两者都可能在不重排的情况下变化 ⇒ 用 `UpdateTargetRowGeometry()` 在
|
||||
绘制 / 悬停 / 命中 / 取光标四处按需重算(带小缓存键)。
|
||||
|
||||
#### 四、联动:把信号列表**平滑滚动**到目标信号(用户要求)
|
||||
|
||||
- **触发**:绘图区内把某条信号选为当前目标(点击图例、点击信号曲线、双击图例改名)
|
||||
⇒ `PlotView::SelectSignal()` 记录一个待处理请求(`TakePanelScrollRequest()`),
|
||||
宿主在鼠标消息处理后取走并调用 `SignalPanel::ScrollToSignalAnimated()`;
|
||||
另外样式自定义区的**任何交互**(预设色块、自定义颜色入口、样式按钮、
|
||||
线宽 / 透明度滑块与数值框、「系数/偏移」「镜像」二级菜单、绝对值)与
|
||||
「目标」行的单击也都会触发同一次滚动。
|
||||
- **滚动目标位置**(`SignalScrollTarget()`):
|
||||
* 目标在当前视界**上方** ⇒ 向上滚动到 `rowTop - 组名高度`,
|
||||
⚠️ **顶部必须避让悬浮组名**(用户明确要求"完全出现时不会被浮动组名遮挡"):
|
||||
悬浮组名只可能是目标自己那个分组的组名(分组连续排列,见 `StickyGroupRowTop`),
|
||||
因此让出**一个组行高度**即可;
|
||||
* 目标在视界**下方** ⇒ 向下滚动到 `rowBottom - 列表高度`;
|
||||
* 已经完整可见 ⇒ **不动**。
|
||||
- **动画**(`AdvanceScrollAnimation()`,宿主用 16ms 定时器驱动):
|
||||
* ease-out cubic(起步快、靠近目标变慢 —— 用户要求"越远时越快,靠近时变慢");
|
||||
* 时长 = `clamp(距离 × 0.35ms, 130ms, 300ms)`(用户要求"不要太久");
|
||||
* 用户滚轮 / 拖滚动条 ⇒ **立即取消**动画(否则互相打架)。
|
||||
- ⚠️ 动画只改"面板的滚动偏移",因此宿主只需持续 `InvalidateRect`(整帧),
|
||||
由 `Render` 检测 `ScrollAnimationActive()` 自管定时器(与提示浮层淡出同一套做法)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 变更日志(本文件维护记录)
|
||||
|
||||
| 日期 | 设备/模型 | 摘要 |
|
||||
@@ -1907,6 +1986,7 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **全局 Y 轴自适应跟随网格结构 + 组名悬浮 + 稀疏信号默认点线 + 单点光标吸附 + 放大自动点线(详见 §9.29)**。① **新网格不继承全局 Y 轴自适应**:`RebuildLanes` 对新出现的信号返回默认 `LaneCarry()` ⇒ `fitYToSelection=false`;修法:重建前先算 `previousAllAutoFit`(非空且**每个**网格都开着 = 全局开启的正式定义),`LaneCarry` 加 `matched` 标记,新信号用它当默认;并新增 `ReapplyGlobalAutoFitIfEnabled()` 在 **`Layout()`(网格数变化)/`RefreshLanes()`(信号数变化)/`SplitLane()`** 之后立即重算 ⇒ 新勾选(按**当前视界**自适应)、取消显示(剩余信号重新收敛)、拆分(每份各自自适应)三项全覆盖。② **组名悬浮**:新增 `SignalPanel::StickyGroupRowIndex()` + `PaintStickyGroupRow()`(不透明底 + 底部边界线),`RowRect` 加 `m_rowYOverrideActive/Y` 覆盖行顶部(行内所有几何的唯一来源);判据 = 分组行已在列表上边界之上且本组最后一行仍在列表内;常规循环**跳过**被钉住的行(否则画两次)。③ **稀疏信号默认样式**:新增 `ApplySparseDefaultStyle`(1 个有效点 → 点线 + **最大线宽 10px**;2..16 → 点线 + 2px),在 `BuildSignalGroup`/`InsertDerivedSignal` 两处调用;线宽常量统一到 `DataModel.hpp`(`kSignalLineWidthMin/Max`)并被 SignalPanel 滑块引用;`ComputeStats` 输出 `firstFiniteIndex`、`SignalData` 新增 `singlePointTime`。④ **单点光标吸附**:`SnapTimeToSample` 新增半径分支(`kCursorSnapPointRadiusPixels=8` 逻辑像素)吸附 `singlePointTime`,半径外自由移动(**吸附而非卡住**)。⑤ **放大自动点线**:`SignalStyle` 新增 `autoScatterActive/autoScatterSavedMode/autoScatterUserOverride`,`AxisSparseInView`(间距 > 半个绘图区宽度,与吸附上门限同源,**单点轴不算稀疏**)+ `UpdateAutoScatterStyles()`(在 `SetTimeView` 等四处调用)⇒ 进入阈值自动切点线、退出阈值恢复原样式,**用户手动改过则不恢复**(判定必须放在恢复判断**之前**,否则用户改完紧接着缩出去会被覆盖)。验证:新增离屏 `.preflight/check` **65/65 通过**(连跑 3 次稳定,覆盖 7 组断言;含“钉住行与自然位置逐像素一致”“单点吸附半径内外”“用户手动改样式后退出不覆盖”),**A/B**:临时禁用六个机制后 **21 项如实失败**;`make release` 零警告。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **组名平滑悬浮 + 单点信号初始视图 + 光标吸附统一判定(自动点线同源)(详见 §9.30)**。① **组名悬浮平滑化**:位置改为 `StickyGroupRowTop = min(列表上边界, 本组最后一行下边界 − 组名高度)` ⇒ 组名随最后一行**自然滚出**(不再突然消失),且下边界永不越过下一个分组行的自然位置 ⇒ **不再遮住下一组名**(旧实现固定钉在列表上边界会把下一组名盖住,让别人以为后面的信号属于上一组);**折叠的分组不悬浮**(随滚动自然划过);底部边界线只在真的“浮”起来时才画。② **单点信号初始视图**:新增 `PlotView::FitSinglePointSignal()`(无任何信号被勾选、勾选的第一个信号只有 1 个有效点时生效)—— 数据点居中、**时间跨度 1s**、**Y 跨度 1**,并置 `autoRange=false`/`fitYToSelection=false`;`Application::SynchronizeView` 首次勾选时先试它、失败才 `FitAll()`;`AutoRangeLaneToView` 的退化区间改为 `PadRange` 同款留白 `max(1,|v|×0.1)`。③ **吸附判定统一**(用户给出的唯一判据):新增 `GridMinorCellCount()`(网格一横排小格数 N,与网格绘制同源)+ `SignalSnapEnabled()`(**当且仅当**某信号在当前一屏内的数据点 `< N×4` 才开启吸附,随视界实时重算 ⇒ 疏密信号自适应),`SnapTimeToSample` **只按鼠标所在网格**判定、同网格内所有符合判定的信号数据点都参与、吸附半径 = 一个网格小格宽且不超过半个局部采样间距(吸附≠卡住);旧的 `SampleSpacingPixels`(6px 下门限+半屏宽上门限)**已删除**。④ **自动点线改为与吸附判定完全同源**(`UpdateAutoScatterStyles` 调 `SignalSnapEnabled`),旧 `AxisSparseInView` **已删除**;进入阈值自动切点线、不再满足自动恢复、用户手动改过则不恢复。⑤ **需求作废**:“2…16 个有效采样点默认点线 + 2px”**已取消**(只保留“1 个有效点 → 点线 + 最大线宽”);`SignalData::singlePointTime` 升级为 **`sparseTimes`/`sparseValues`**(有效点 ≤ 1024 时全部缓存,供吸附与单点视图使用)。验证:新增离屏 `.preflight/check` **55/55 通过**(连跑 3 次稳定;覆盖组名悬浮四种场景、单点初始视图、吸附判定/网格作用域/多信号/动态切换/单点半径、自动点线同源与用户覆盖);**A/B** 禁用三项机制 ⇒ **14 项如实失败**;`make release` 零警告。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **自适应范围/时机澄清 + 适应视图与 Y 轴自适应互不干扰 + 吸附跟随时间偏移(详见 §9.31)**。① **澄清“自适应范围/时机”**(修正记忆里“额外要求视界内至少有一个可见数据点”这句不完善的表述):**首个网格**显示内容时 **Y 轴与时间轴都**自适应;只有一个数据点的信号要**居中显示在网格里**(`FitSinglePointSignal`:居中 + 时间跨度 1s + Y 跨度 1);**后续新增网格只做 Y 轴自适应、不再调整时间轴**。② **「适应视图」与「Y 轴自适应」互相干扰**:根因是两条自适应路径**留白不同**(`PadRange` 6% vs `AutoRangeLaneToView` 5%)⇒ 视界未变时也会算出不同区间、网格被无意义重绘(实测切一次 **143513** 像素、反向 **137326** 像素)。修法:新增 `DataModel.hpp` 的 **`PadValueRange()`** 作为唯一留白实现(含退化区间 `max(1,|v|×0.1)`),`PadRange` 与 `AutoRangeLaneToView` 共用 ⇒ 四个步骤(适应视图→开自适应→关自适应→再适应视图)**区间逐位相同且绘图区逐像素 0 差异**。③ **「适应视图」在单点信号上让数据点“飞了”**:`FitAll()` 开头先试 `FitSinglePointSignal()`(仅一个网格 + 唯一可见信号为单点),与首次加载效果一致且幂等。④ **吸附跟随「调整 → 时间轴偏移」**:采样点画在 `time[k] + offsetTime` 处而光标存的是显示时间,旧实现按源时刻吸附 ⇒ 落到历史位置;修法:`SignalSnapEnabled`/`HasVisibleSample`/`NearestSnapSample`/`LocalSampleSpacing` 全部加 `timeShift`,查找时 `time - timeShift` 回源空间、返回时加回去,`UpdateAutoScatterStyles` 同步传 `offsetTime`。验证:离屏 `.preflight/check` **39/39 通过**(连跑 3 次稳定;含像素级零变化断言与“真缩放会重绘”对照组);**A/B** 回退三项修复 ⇒ **7 项如实失败**(含 143513/137326 像素重绘症状);`make release` 零警告。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **浮动面板不穿透 / 网格高亮改由信号列表触发 / 样式区「目标」行 / 联动平滑滚动(详见 §9.34)**。① **浮动面板上双击穿透到网格**:`PlotView::OnDoubleClick` 在所有下层命中都不成立时无条件 `FitAll()` ⇒ 在面板上双击会让网格莫名其妙自适应一次;修法:**最前面**用 `TopPanelAtPoint()` 判定并消费。② **网格变色高亮的触发来源重新定义**(旧行为"鼠标在网格里移动就高亮"**作废**):改为**信号列表 / 样式区「目标」行悬停到某条已绘制信号** ⇒ 该信号所在网格变色高亮**且该信号曲线本身也高亮**(新增 `m_externalHoverSignal`,与 `m_hoverSignal` 分开保存,由 `Render()` 每帧同步;新增 `EffectiveHoverLane()`)。③ **样式区「目标」行**(样式自定义区最上方):显示当前编辑的目标信号名称 + (已绘制时)名称**后方**的 GX 标签,悬停高亮并联动网格/曲线高亮,**单击不编辑、双击改名**。④ **联动平滑滚动**:绘图区选中信号(点图例 / 点曲线 / 双击图例)与样式区任何交互都触发 `ScrollToSignalAnimated()`(ease-out cubic、时长 `clamp(距离×0.35ms,130,300)`、**上行让出组行高度避免被悬浮组名遮挡**、滚轮/拖滚动条即取消)。验证:离屏 `.preflight/check` **73/73 通过**(连跑 3 次稳定;含浮动面板双击不移视界 vs 空白处双击必自适应的对照组、未勾选信号悬停不高亮、目标行 GX 标签位置与单击/双击区分、长列表 122 行平滑滚动与遮挡检查);**A/B** 回退六处实现 ⇒ **15 项如实失败**;`make release` 零警告、链接通过。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **「适应视图」边界规则撤回重做:单值散点让出半径 + 单点簇视图(详见 §9.33)**。① **初次自适应没有发生**(用户报告):`FitAll()` 在**没有任何可见信号**时也把 `ViewInitialized()` 置 true ⇒ 随后勾选第一个信号时 `SynchronizeView` 认为已初始化、**跳过自适应**(实测 MF4 视界停在 42.386s,数据点被推到右边缘外);修法:只有存在可见信号才置位,并让初次自适应与工具栏「适应视图」**共用 `FitAll()` 一条路径**。② **单值散点被裁掉半个**(用户报告):旧规则"左右各留一小格"在"单值 + 连续信号"下既不准也不够(`WIN_Motor_StallCurrentVolBrk` 只有 1 个有效点,正好落在边界上);按用户要求**撤回旧策略**(删除 `FitSinglePointLanes`/`TimeGridCellSeconds`/`LaneValueGridCell`/`FitSinglePointSignal`),改为:**任何一条边界被单值散点顶住就让出该散点的半径(+1px)**,只在散点**会被裁切**时才扩展(内部散点不动视界),边界不是单值散点时边界就落在信号点上。③ **特例**:全部可见数据点都是单值信号且时刻相同 ⇒ 时间轴以该时刻居中、缩放到**一大格 = 1s**(视界 10s,`NiceStep(10,10)==1.0`),每个网格的幅值区间保证其数据点都能完整画出(退化成单值时跨度 1 居中)。验证:离屏 `.preflight/check` **62/62 通过**(连跑 3 次稳定;含**真实文件** `TestData/MF4-Record.MF4`:`WIN_Motor_StallCurrentVolBrk`(1 点) + `m_MOT_Current_DCom[0]`(8475 点) 复现用户场景,散点圆心离绘图区左边界 16.5px、半径 15px ⇒ 完整可见);**A/B** 回退四处规则后 **20 项如实失败**(含"散点正好压在绘图区右边缘"、"初次视界 42.386s");`make release` 零警告、链接通过。 |
|
||||
| 2026-10-15 | DeepSeek-V4.1-Flash(**起源设备**) | **信号面板滚动条跟随 / 工具栏连点丢状态 / 图层网格线步长 / 多网格单点自适应 / 单点信号拖拽(详见 §9.32)**。① **滚动条"卡住"**:`Application::WM_MOUSEMOVE` 的 `plotOnlyMove` 只看 `inPlot && m_mouseOverPlot`,拖滚动条进绘图区后判定"只影响绘图区"⇒ 面板滚动值变了却不重绘;修法:新增 `draggingNonPlot`(正在拖非绘图区组件时一律完整失效)。② **工具栏丢点击**:窗口类带 `CS_DBLCLKS` ⇒ 快速第二次按下被合成 `WM_LBUTTONDBLCLK` 而工具栏没处理(**按下丢失**);且 `HandleMouseMove` 只要不在工具栏上就 `OnMouseLeave()` ⇒ 清掉 `m_pressedIndex`(按住划出再回按钮松手无效);两处都已修。③ **网格线错位/丢失/闪烁**:`PaintLane` 的竖向主刻步长取自 `Tab().ViewMin/ViewMax`,而渲染信号图层时该区间已被改成**宽窗口**(≈2×)⇒ 图层辅助线步长 2×、位置与前台不同、判重判据也错位;修法:新增 `m_renderTimeStep`,由 `RenderLaneLayerRegion` 用**前台跨度**算好传入。④ **多网格单点「适应视图」**:新增 `FitSinglePointLanes()`(左右边界 = 最左/最右数据点 ± **一个网格小格**;逐网格 Y 自适应、各留**一个 Y 小格**;全部点同刻 ⇒ 跨度 1s 居中;单值网格 ⇒ Y 跨度 1 居中)。⑤ **单点信号**:`HitTestSignal` 新增单点分支 + 环状光晕 + 可拖拽换网格(悬停**不改光标**,按下后才改)。验证:离屏 `.preflight/check` **67/67 通过**(连跑 3 次稳定);**A/B** 回退六处修复 ⇒ **17 项如实失败**(含 [C] 辅助线 49px vs 25px、20 vs 40 条、最大偏移 539px);`make release` 零警告、链接通过。 |
|
||||
|
||||
@@ -2208,6 +2288,31 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
`Application::SynchronizeView` 会**跳过初次自适应**,视界停在“无信号”那次的整段范围上,
|
||||
单值信号的数据点既不居中、还会有一半被裁在网格外(用户 2026-10-15 报告)。
|
||||
另外「适应视图」两条路径(初次自适应 / 工具栏按钮)必须**只有一条实现**(都走 `FitAll`)。
|
||||
72. ⚠️ **上层元素的交互不得穿透到下层**(用户 2026-10-15 第六轮明确要求):
|
||||
实验性功能的浮动面板浮在网格之上,`PlotView::OnDoubleClick` 必须**最先**用
|
||||
`TopPanelAtPoint()` 判定并消费 —— 旧实现在"差值标签/光标标签/光标线/图例都不命中"时
|
||||
无条件 `FitAll()`,于是在面板上双击会让网格莫名其妙地自适应一次。
|
||||
新增/修改任何"空白处点击/双击"的默认行为时,都要先过一遍所有更上层的元素
|
||||
(浮动面板、菜单、拾色器、装饰层)。
|
||||
73. ⚠️ **网格变色高亮的触发来源只有两个**(旧行为"鼠标在网格里移动就高亮"**已作废**):
|
||||
① 鼠标悬停在实验性功能浮动面板上 ⇒ 高亮该面板所属网格;
|
||||
② 信号列表 / 样式区「目标」行**悬停到某条已绘制信号** ⇒ 高亮它所在网格**并且
|
||||
该信号曲线本身也高亮**(`PaintSignalHalo`)。
|
||||
`PlotView` 的 `m_externalHoverSignal` 必须与 `m_hoverSignal` **分开保存**
|
||||
(绘图区 `OnMouseLeave` 会清掉后者,而列表悬停时鼠标不在绘图区内),
|
||||
并由 `Application::Render()` **每帧**同步(覆盖 WM_MOUSELEAVE / 数据变化 / 切标签页)。
|
||||
`SignalPanel::HoveredSignal()` 不能在 `InvalidateRows()` 之后继续有效(必须一并作废)。
|
||||
74. ⚠️ **样式区「目标」行**(用户 2026-10-15 第六轮要求):位于样式自定义区**最上方**,
|
||||
显示当前正在编辑的目标信号名称,**已绘制到网格时**在名称**后方**加 GX 标签;
|
||||
悬停名称/GX 同时触发绘图区网格高亮 + 曲线高亮;**单击不进入编辑**(只做联动滚动),
|
||||
**双击才进入改名**(`StyleEditField::SIGNAL_NAME` + `m_editRow < 0` 表示目标信号)。
|
||||
它的名称宽度与"是否有 GX 标签"都可能在**未重排**时变化 ⇒ 必须用
|
||||
`UpdateTargetRowGeometry()` 按需重算(带缓存键),不能只在 `LayoutStyleControls()` 里算一次。
|
||||
75. ⚠️ **联动滚动必须是平滑动画,且目标不得被悬浮组名遮挡**(用户 2026-10-15 第六轮要求):
|
||||
`SignalPanel::ScrollToSignalAnimated()` + `AdvanceScrollAnimation()`
|
||||
(ease-out cubic;时长 = `clamp(距离×0.35ms, 130, 300)`;宿主 16ms 定时器驱动)。
|
||||
向上滚动时顶部要**让出一个组行高度**(悬浮组名只可能是目标自己那个分组的组名,
|
||||
因为分组在列表里连续排列)。用户滚轮 / 拖滚动条必须**立即取消**动画。
|
||||
|
||||
### 11.3 离屏验证方法学(本机偏好,强烈建议沿用)
|
||||
|
||||
|
||||
Reference in new issue
Block a user