修复信号面板滚动条跟随、工具栏连点丢状态、图层竖向网格线步长、多网格单点自适应与单点信号拖拽
用户 2026-10-15 报告的五个问题,逐一给出根因与修法(详见 Documents/agent_mem.md §9.32):
1. 拖动信号面板滚动条、鼠标移到绘图区后“滑块卡在原地不动”
根因:Application::WM_MOUSEMOVE 的 plotOnlyMove 只看 inPlot && m_mouseOverPlot,
拖滚动条进入绘图区后判定“本帧只影响绘图区” ⇒ 面板滚动偏移已变却从不重绘。
修法:新增 draggingNonPlot(正在拖非绘图区组件时一律走完整失效)。
2. 工具栏快速连点 / 双击丢状态
根因:(a) 窗口类带 CS_DBLCLKS,快速第二次按下被合成 WM_LBUTTONDBLCLK 而工具栏未处理
(那一次按下完全丢失);
(b) HandleMouseMove 只要鼠标不在工具栏上就调 OnMouseLeave(),清掉 m_pressedIndex
⇒ 按住期间从按钮边缘划出再回到按钮松手不会触发任何动作。
修法:WM_LBUTTONDBLCLK 命中工具栏时按“按下”处理;m_activeTarget == TOOLBAR 期间不调 OnMouseLeave()。
3. 网格叠底:拖拽期间竖向网格线错位 / 丢失,操作信号样式时“闪烁”
根因:PaintLane 的竖向主刻步长由 Tab().ViewMin/ViewMax 推出,而渲染信号图层时该区间已被
RenderLaneLayerRegion 改成“宽窗口”(≈2× 前台)⇒ 图层辅助线步长 2×、位置与前台不同、
“与主刻重合则跳过”的判据也随之错位 ⇒ 贴图后网格线错位 / 整条丢失,
并在“图层帧 ↔ 结算帧”之间来回切换时闪烁。
修法:新增 m_renderTimeStep,由 RenderLaneLayerRegion 用前台视界跨度算好传入
(与纵向 m_wideTickSpan/m_wideTickHeight 同一思路),PaintLane 优先使用它。
4. 多个网格、每个网格只有一个数据点时「适应视图」把数据点甩飞
修法:新增 FitSinglePointLanes(),按用户给出的规则:
* 左右边界 = 所有网格中最左 / 最右数据点的时间,再向外各偏“一个网格小格”的时间跨度;
* 逐网格 Y 自适应,并在纵向上下各留“一个 Y 小格”的高度;
* 全部数据点在同一时刻时 ⇒ 时间跨度 1s 且以该时刻居中(与首个单点信号的初始视图对齐);
* 某网格只有一个取值 ⇒ 该网格 Y 跨度 1 且居中。
仅在全部可见信号都是单点(finiteCount == 1)时启用,否则交回常规 FitAll。
5. 单点信号的悬停高亮与拖拽换网格
修法:HitTestSignal 新增单点分支(SinglePointScreenPos + 容差 = max(常规容差, 该点绘制半径));
悬停用环状光晕且不改鼠标形状(QueryCursor 不查 HitTestSignal),按下拖拽后才改 IDC_SIZEALL;
拖拽虚影对单点信号回退为实心点 + 环。
验证(全部离屏,不占用鼠标 / 键盘 / 屏幕):
- .preflight/check(SW_HIDE + 只注入合成消息 + 进程/线程 BELOW_NORMAL)**67/67 通过**,连跑 3 次稳定。
其中 [C] 直接量“宽基底图层位图自身”的网格线间距(图层主刻 123px vs 前台 122px、辅助线 25px vs 25px),
并断言拖拽帧确实来自宽基底贴图路径(m_wideLastValid)。
- A/B 判别:回退上述六处修复后 **17 项如实失败**([C] 辅助线 49px vs 25px、20 vs 40 条、最大偏移 539px)。
- make release:三个改动文件重新编译 **零警告**;链接用临时 `make release TARGET_FILE_NAME=Target_check` 通过。
同步记忆:Documents/agent_mem.md 新增 §9.32、§11.2 第 64–68 条硬约束、变更日志末行。
This commit is contained in:
1 parent
68d8b7ede6
commit
aee3a388b5
5 files changed
+541
-40
No files matched your search
@@ -1707,6 +1707,88 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
|
||||
---
|
||||
|
||||
### 9.32 信号面板滚动条跟随 / 工具栏连点丢状态 / 图层网格线步长 / 多网格单点自适应 / 单点信号拖拽(本轮,起源设备)
|
||||
|
||||
> 本轮五项(用户 2026-10-15 第四轮)。离屏验证 `.preflight/check` **67/67 通过**(连跑 3 次稳定);
|
||||
> **A/B** 回退六处修复后 **17 项如实失败**(含 [C] 的"辅助线 49px vs 前台 25px / 20 vs 40 条 / 最大偏移 539px")。
|
||||
|
||||
#### 一、拖动信号面板滚动条、鼠标移到绘图区后"滑块卡在原地不动"
|
||||
|
||||
- **根因**:`Application::WM_MOUSEMOVE` 里
|
||||
`plotOnlyMove = (m_activeTarget == Target::PLOT) || (inPlot && m_mouseOverPlot)`。
|
||||
拖滚动条时鼠标很容易进入绘图区 ⇒ `inPlot && m_mouseOverPlot` 为真 ⇒ 判定"本帧只影响绘图区"
|
||||
⇒ 只 `InvalidatePlotRect`;而面板的滚动偏移**已经变了**却没有重绘 ⇒ 滑块看着不动(滚动值其实在变)。
|
||||
- **修法**:`draggingNonPlot = (m_activeTarget != NONE) && != PLOT && != EDIT_FIELD`,
|
||||
`plotOnlyMove` 必须先排除它(正在拖拽非绘图区组件时,一律走完整失效)。
|
||||
- 验证 `[A]`:真实按下滚动条 + 移入绘图区移动两次 ⇒ 滚动偏移 `0 → 2088.7 → 1766.1`、`m_chromeDirty` 为真、松手结束拖拽。
|
||||
|
||||
#### 二、工具栏快速连点 / 双击丢状态
|
||||
|
||||
- **两个根因**:
|
||||
(a) 窗口类带 `CS_DBLCLKS`,快速第二次按下被 Windows 合成 `WM_LBUTTONDBLCLK`,而工具栏没处理它
|
||||
⇒ **那一次按下完全丢失**("连点好几下,开关只切换了几次");
|
||||
(b) `HandleMouseMove` 只要鼠标不在工具栏上就调 `m_toolbar.OnMouseLeave()` ⇒ 清掉 `m_pressedIndex`
|
||||
⇒ 随后在按钮上松手什么也不发生(按住期间从按钮边缘划出即命中这条)。
|
||||
- **修法**:`WM_LBUTTONDBLCLK` 命中工具栏时按"按下"处理(`SetFocus`/`SetCapture`/`OnLButtonDown`);
|
||||
`m_activeTarget == Target::TOOLBAR` 期间**不调** `OnMouseLeave()`。
|
||||
- 验证 `[B]`:三次快速点击(第 2/3 次走 `WM_LBUTTONDBLCLK`)⇒ `NONE → SINGLE → DOUBLE → NONE`;
|
||||
按住 → 移出一屏 → 回到按钮松手仍能切换。
|
||||
|
||||
#### 三、网格叠底:拖拽期间竖向网格线错位/丢失 + 操作信号样式时"闪烁"
|
||||
|
||||
- **根因**:`PaintLane` 的竖向网格**主刻步长**由 `Tab().ViewMax() - Tab().ViewMin()` 推出,
|
||||
而渲染信号图层时 `RenderLaneLayerRegion` 把该区间改成了**宽窗口**(≈2× 前台)
|
||||
⇒ 图层里的辅助线步长 2×、位置与前台不同,且"与主刻重合则跳过"的判据也随之错位
|
||||
⇒ 贴图后网格线**错位 / 整条丢失**;在"拖拽帧(图层像素)"与"结算帧(整幅重绘)"之间来回切换时就是用户看到的**闪烁**。
|
||||
- **修法**:新增 `PlotView::m_renderTimeStep`,由 `RenderLaneLayerRegion` 用**前台视界跨度**算好传入
|
||||
(`PaintLane` 优先用它;与纵向已做对的 `m_wideTickSpan/m_wideTickHeight` 同一思路),渲染完恢复原值。
|
||||
- 验证 `[C]`:① 直接检查**图层位图自己的像素** —— 图层主刻间距 123px vs 前台 122px、**辅助线间距 25px vs 25px**;
|
||||
② 子窗口贴图帧与同视界整幅重绘帧的竖线数量一致(**10 主 / 40 辅**)且逐列偏移 ≤1px;
|
||||
③ 断言贴图帧确实来自宽基底路径(`m_wideLastValid`)。
|
||||
A/B(回退)如实报:辅助线 **49px vs 25px**、**20 vs 40 条**、最大列偏移 **539px**。
|
||||
|
||||
#### 四、多个网格、每个网格只有一个数据点时「适应视图」
|
||||
|
||||
用户给出的规则(逐条落地在 `PlotView::FitSinglePointLanes()`):
|
||||
|
||||
* **时间轴**:左边界 = 所有网格中**最左**的数据点时间,再向左偏**一个网格小格**对应的时间跨度
|
||||
(`TimeGridCellSeconds()`,与网格绘制同源);右边界 = 最右数据点时间 + 一个小格。
|
||||
* **Y 轴(逐网格)**:按该网格自己的数据点范围自适应;若网格内存在**时间一致但 Y 值不一致**的多个单点
|
||||
⇒ 纵向上下边界也各留**一个 Y 小格**的高度(`LaneValueGridCell()`,与网格绘制同源)。
|
||||
* **最极端情况**(网格中所有数据点都在**同一个时间位置**):每个网格的适应按
|
||||
"首个网格加载且加载为单数据点信号时"的时间轴对齐方式 —— **跨度 1s、以该时刻居中**。
|
||||
* 某网格只有一个取值 ⇒ 该网格 Y 跨度 **1** 且居中于该值。
|
||||
* ⚠️ 规则只在**所有可见信号都是单点**(`finiteCount == 1`)时启用,否则交回常规 `FitAll`。
|
||||
|
||||
验证 `[D]`:MERGED 后把 b0 移到新网格(网格0 = {a0=5.0, a1=−3.0}、网格1 = {b0=−2.0})⇒
|
||||
时间视界 `[0.000, 3.800]`(数据 `[0.1, 3.7]` ± 一小格 0.1)、网格0 区间覆盖 4.5~5.5、
|
||||
网格1 = `[−2.5, −1.5]`(跨度 1 居中)、同刻退化用例跨度 1 居中于 0.1;并含"有常规信号时规则不生效"的反向断言。
|
||||
|
||||
#### 五、单点信号的高亮与拖拽换网格
|
||||
|
||||
- `HitTestSignal` 新增**单点分支**(`SinglePointScreenPos()` + 容差 = `max(常规命中容差, 该点绘制半径)`)——
|
||||
单点信号没有折线可测距,不单独处理就永远悬停不到。
|
||||
- 悬停:光晕换成**圆环**(复用 `PaintSignalHalo`,单点用环)且**不改鼠标形状**
|
||||
(`QueryCursor` 不查 `HitTestSignal`);按下后进入常规信号拖拽(`IDC_SIZEALL`、虚影为实心点 + 环)。
|
||||
- 验证 `[E]`:命中判定、`QueryCursor == nullptr`、光晕 57600 像素、从网格1 拖到网格0 成功。
|
||||
|
||||
#### 六、本轮验证方法学(重要教训)
|
||||
|
||||
- 离屏 `.preflight/check`:`SW_HIDE` 窗口 + 只注入合成消息 + 进程/线程 `BELOW_NORMAL`;**67/67 通过**。
|
||||
- ⚠️ **A/B 必须让被测代码真的参与编译**:该 harness 链接的是 `Build/Release/*.o`,
|
||||
只改源文件不 `make release` ⇒ 测的仍是旧目标文件(实测"回退后依然全绿"的假结论);
|
||||
`Copy-Item` 还会**保留时间戳**,使 `make` 认为 `.o` 最新(实测"恢复后直接 make 不重编译")
|
||||
⇒ **回退/恢复后都要把时间戳推到当前,再 `make release`**,最后用临时输出名验证链接
|
||||
(`make release TARGET_FILE_NAME=Target_check`,因为用户正在运行 `Target.exe` 时它被锁定)。
|
||||
- ⚠️ **判别力要靠"量"而不是"看起来对"**:本轮的 `[C]` 一开始写的是"两帧逐列比较",
|
||||
但在图层没被真正使用时两帧**恒等** ⇒ 毫无判别力;直到
|
||||
(a) 断言帧确实来自宽基底贴图(`m_wideLastValid`)、(b) 直接检查**图层位图自身的网格线间距**,才真正抓住缺陷。
|
||||
- ⚠️ 网格线检测细节:GDI 写 DIB **不设置 alpha 字节**(比较必须按 24 位掩码);
|
||||
"竖线"的列阈值**必须 ≥ 半个捕获高度**(横向网格线会让每一列都带上几十像素,
|
||||
用小阈值会把 1212/1225 列全判成竖线 → 位置比较彻底失真)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 变更日志(本文件维护记录)
|
||||
|
||||
| 日期 | 设备/模型 | 摘要 |
|
||||
@@ -1751,6 +1833,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.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` 零警告、链接通过。 |
|
||||
|
||||
---
|
||||
|
||||
@@ -2011,6 +2094,26 @@ GDI+ 抗锯齿逐段扫描这些**近竖直、满幅**的边,代价爆炸(
|
||||
组名随最后一行**平滑滚出**(不突然消失),且下边界永不越过下一个分组行的自然位置
|
||||
⇒ **不可能遮住下一个组名**;**折叠的分组不悬浮**(随滚动自然划过)。
|
||||
行几何仍只由 `RowRect()` 提供(用 `m_rowYOverrideActive/m_rowYOverrideY` 覆盖顶部坐标)。
|
||||
64. ⚠️ **图层(宽基底)里的任何刻度步长都必须由"前台视界"显式传入**:
|
||||
渲染图层时 `RenderLaneLayerRegion` 会把 `Tab().ViewMin/ViewMax` 改成**宽窗口**(≈2× 前台),
|
||||
因此 `PaintLane` **绝不能**拿它去 `NiceStep` —— 竖向必须优先用 `m_renderTimeStep`
|
||||
(由 `RenderLaneLayerRegion` 用前台跨度算好传入),横向必须用 `m_wideTickSpan/m_wideTickHeight`。
|
||||
违反时:图层里的辅助线步长 2×、位置与前台不同、"与主刻重合则跳过"的判据也错位
|
||||
⇒ 拖拽期间网格线错位/整条丢失,且在图层帧与结算帧之间**闪烁**(实测 49px vs 25px、20 vs 40 条)。
|
||||
65. ⚠️ **拖动"非绘图区组件"(信号面板滚动条等)时,鼠标移动不得只失效绘图区**:
|
||||
`plotOnlyMove` 必须先排除 `draggingNonPlot = (m_activeTarget != NONE) && != PLOT && != EDIT_FIELD`。
|
||||
否则鼠标一进绘图区就只重绘绘图区,而组件自身的滚动偏移已经变了 ⇒ 滑块/滚动条"卡在原地不动"。
|
||||
66. ⚠️ **工具栏必须把 `WM_LBUTTONDBLCLK` 当作"按下"处理**(窗口类带 `CS_DBLCLKS`:快速连点时第 2 次及以后
|
||||
的按下会被合成成它,不处理就**完全丢失那一次点击**);并且**按住期间不得**因 `OnMouseLeave()` 清掉按下态
|
||||
(`m_pressedIndex`)—— 否则"按住按钮划出边缘再回来松手"不会触发任何动作。
|
||||
67. ⚠️ **单点信号(`finiteCount == 1`)必须在命中测试 / 光晕 / 拖拽虚影里单独处理**:
|
||||
它没有折线可测距,`HitTestSignal` 要用 `SinglePointScreenPos()` + 容差 `max(常规容差, 点绘制半径)`;
|
||||
悬停时**不改鼠标形状**(`QueryCursor` 不查 `HitTestSignal`),只在按下拖拽后改(`IDC_SIZEALL`)。
|
||||
68. ⚠️ **多网格单点信号的「适应视图」规则**(用户 2026-10-15 明确给出):左/右边界 = 所有网格中
|
||||
最左/最右数据点时间再向外偏**一个网格小格**的时间跨度;每个网格的 Y 按自身数据点自适应,
|
||||
若该网格内存在"时间一致但取值不一致"的多个单点 ⇒ 纵向上下各留**一个 Y 小格**;
|
||||
全部点在同一时刻 ⇒ 时间跨度 **1s** 居中于该时刻(与"首个单点信号初始视图"对齐);
|
||||
某网格只有一个取值 ⇒ 该网格 Y 跨度 **1** 居中。仅在**所有可见信号都是单点**时启用。
|
||||
|
||||
### 11.3 离屏验证方法学(本机偏好,强烈建议沿用)
|
||||
|
||||
|
||||
Reference in new issue
Block a user