Commit Graph
27 Commits
Author SHA1 Message Date
DeepSeek V4.1 Flash b960b03cb5 「阶数 N」改称「迭代次数 N」;修复大文件放大后的平移卡顿与越界三角样式
一、命名(用户要求)
- 实验性功能里的「阶数 N」全部改为「迭代次数 N」(面板滑块标签、均值滤波/中心轴
  的数值框标签、构建提示语)。
- 相关标识符与函数参数统一改名:order → iterations(Lane::MeanFilterItem::iterations、
  Lane::weakBoostIterations、ComputeWeakWaveBoost/ComputeMovingAverageIterated 的形参、
  MeanFilterCurveFor/WeakBoostCurveFor/WeakBoostValueAt/EdgeCenterCountsFor、
  各曲线缓存项的字段、EdgePanelLayout::rowIterations/sliderIterations、
  PlotEditTarget::MEAN_FILTER_ITERATIONS/EDGE_CENTER_ITERATIONS、
  PlotDragMode::BOOST_ITERATIONS、kWeakBoostIterationsMin/Max/Label、
  DerivedSignalRequest::iterations 等)。网格拖拽重排里的局部 order 为避免歧义
  改名为 laneOrder;`std::memory_order_*`、`rowOrder`→`rowIterations` 一并核对无误。
- 导出信号尾缀统一为「N次迭代」:
  `<原信号> (N点均值 M次迭代)`、`<原信号> (弱波增强 X% M次迭代)`;
  弱波增强此前缺失该信息,现已补上(两种派生信号都恒定带迭代次数)。
  状态提示语同步为「… M 次迭代信号。」。

二、越界三角与光标读数的样式统一(用户要求)
- 新增 `kMarkerTriangleGap`:网格内数据点越界时,方向三角与数值标注之间**留出间隙**
  (此前三角与胶囊贴在一起,看起来像胶囊上多出的尖角);中心轴/均值滤波/弱波增强的
  派生取值标注同样处理。
- 光标时间读数(以及双光标 Δt 读数)改用与网格内数据点**完全一致**的越界样式:
  三角画在胶囊**外侧**、尖端朝外、与胶囊之间留出同样的间隙;为此把读数胶囊在越界一侧
  向内让出「三角深度 + 间隙」。旧的"三角压在胶囊上沿"的画法以及为它额外留出的叠放
  间距(kCursorTipStackGap)一并删除。

三、大文件放大后"平移 / 改配色非常卡"的根因与修复(用户要求,流畅性优先)
用离屏探针(`.preflight/perf3`)在 VERY_BIG_DATA(1.77GB、2580 万采样 × 5 信号、
1224×796 绘图区)上先量化,实测到的三个根因:
1. **包络带"梳状化"**:当信号的振荡周期与像素列宽度相当时(编码器方波在 2ms/大格下
   约 3 个采样点一列),逐列包络会在"全高"与"极窄"之间交替——实测 1224 列里有 988 处
   全高跳变。这种多边形让 GDI+ 的扫描线填充耗时暴涨:同一条 2448 顶点的路径
   **27.6ms → 1.1ms(±1 列极值扩展后快 25 倍)**。这正是"某些放大等级下平移特别卡"
   (实测 2ms/大格平移 87ms,其余等级 17~20ms)的原因。
   → `EmitEnvelopeBand` 在拼装包络带时对列窗口做 ±1 列的极值扩展(纵向最多各多 1 像素,
   肉眼不可辨),一次性消除该病理。
2. **派生预览曲线按折线逐段描边**:均值滤波/弱波增强曲线在可见采样数超过像素列数时
   仍按"每 2 像素一个顶点"的抗锯齿折线绘制,而这类曲线常叠在方波上(大量近垂直跳变),
   实测单条 12~42ms,5 个网格合计上百毫秒。
   → 稠密时改用**逐像素列的包络带**(复用 `EmitEnvelopeBand`)一次 FillPath,实测
   0.56ms / 1.53ms(分别快 22 倍 / 28 倍),视觉与细折线一致(列宽就是 1 像素)。
3. **悬停光晕用宽笔描整条折线**:实测悬停一帧多花 35ms。
   → 包络带模式下改为"把带整体外扩后填充一次"(`PaintBandHalo`),悬停帧恢复正常。

另外修掉两个相关的固定开销:
- `UiMeasureTextWidth` 增加 (字体, 文本) 记忆化缓存:它是布局代码的热点(浮动面板几何
  按「网格数 × 面板种类」重复计算,每帧重复测量同一批字符串成百上千次),实测单个面板
  的绘制因此从 3.2ms 降到 1ms 量级。字体重建(DPI 变化)时由 `UiClearMeasureCache` 作废。

实测(VERY_BIG_DATA 全选 5 信号,绘图区全重绘 = 平移一帧):
- 20ms/大格(用户报告的场景):平移 20.1ms → **11.3ms**;
- 2ms/大格(此前最糟):平移 86.7ms → **12.3ms**;
- 网格 1 开弱波增强:63.9ms → **17.6ms**;5 个网格全开:136.6ms → **31.9ms**;
- 悬停信号:整帧 49.6ms → **15.5ms**(与不悬停持平,光晕几乎免费)。
仍存的已知热点:0.5ms/大格附近(可见约 1000 个采样点、走**逐点描边**路径)平移约
28~39ms —— 该区间采样比像素还稀疏、无法用包络带替代,且用户明确要求保留抗锯齿,
本次未动。

四、验证
- 离屏 harness(窗口 SW_HIDE、不占用鼠标/键盘/屏幕)**355 项检查全部通过**,
  新增 `[AD]`:越界读数胶囊向内让位、三角在外侧、三角与胶囊间有真实间隙、
  胶囊上方不再有内容;取值标注与三角之间保留 `kMarkerTriangleGap` 的间隙(用
  散点模式排除波形干扰后逐像素断言)。`[X]/[Y]/[AA]/[AB]/[Z]` 等既有用例同步通过。
- 性能结论来自 `.preflight/perf3`(离屏探针 + 两套微基准),已随任务清理。
2026-10-10 20:13:21 +08:00
DeepSeek V4.1 Flash 8c8508e5f8 弱波增强:去掉前置滤波并新增「阶数 N」滑块;修复选区放大越界绘制与浮动面板 ✕ 交互
- 弱波增强不再做任何前置滤波(删除内部的 5 点滑动平均 BoostShapeAt):
  极值点直接在输入采样上识别。需要平滑时用户可以先用「均值滤波」构建一条
  滤波后的信号,再对它做弱波增强。
- 新增「阶数 N」参数(1~10,滑块输入),语义与均值滤波的阶数 N 一致 ——
  把同一处理重复应用 N 次,每阶以上一阶为输入:
  一阶时改定量严格等于「等级」对应的目标值;多阶会让相邻弱波互相抬高彼此的
  基准,从而把较宽的弱波区逐步恢复(实测三连弱波的中间峰 550→575→598.4)。
  某一阶若不再产生改动会提前结束迭代。
  `ComputeWeakWaveBoost(values, level, order, out)`;
  `Lane::weakBoostOrder`(默认 1)随 LaneCarry / SplitLane / 引用重映射同步,
  并进入 SceneContentHash;曲线缓存键变为「信号 + 等级 + 阶数」。
- 浮动面板同步新增一行「阶数 N」滑块(新拖拽模式 BOOST_ORDER、
  EdgePanelLayout::sliderOrder);「构建为新信号」命名带上阶数
  (形如 `<原信号> (弱波增强 60%×2阶)`)。
- 修复:选区放大时鼠标被捕获到绘图区之外(工具栏 / 信号面板 / 时间轴)会把
  选区块画到绘图区之外,而拖拽期间只失效绘图区 → 留下无法擦除的墨迹。
  现在拖拽时把选区夹在绘图区内,PaintRubberBand 再对 m_plotRect 求交一次。
- 修复:浮动面板的 ✕ 位于标题栏矩形内部,按下后会继续落到「标题栏 → 拖动面板」
  分支,表现为「按住 ✕ 却把面板拖走了」;现在按下 ✕ 直接消费该次点击(抬起时
  仍按原语义确认关闭),并把 ✕ 的光标改为手型,与其它关闭按钮一致。
- 修复:✕ / 滑块 / 底部按钮的悬停高亮依赖鼠标坐标,但从同一网格的波形移到面板上
  时悬停状态毫无变化 → OnMouseMove 返回 false → 宿主不重绘 → 高亮不出现。
  现在「进入 / 离开 / 在面板内移动」都会请求重绘。
- 离屏验证(窗口隐藏,不占用鼠标/键盘/屏幕):345 项检查全部通过,含
  阶数扫描(N=1 只改外侧弱峰、N=2 传导到中间弱峰、高 N 逼近健康幅值且不越界、
  健康峰在任何阶数下逐位不变)、两个滑块的按压/拖拽/钳制、选区越界零墨迹
  (绘图区外像素差 0)、面板 ✕ 悬停高亮与按下不拖动、光标拖拽始终在视界内,
  以及真实 20K 电机纹波录波(信号范围保持不变、20%+ 采样被调整)。
2026-10-10 19:20:09 +08:00
DeepSeek V4.1 Flash 67f659ad23 实验性功能:移除「差异放大」、新增「弱波增强」;修复放大后拖拽光标越出视界
- 移除差异放大:ComputeDiffAmplify、EdgePanelKind::DIFF_AMP 面板、DIFF_AMP_*
  编辑目标、菜单项与相关缓存,并删除仅供它使用的 SlidingMax / SlidingExtrema /
  float 版滑动平均。
- 新增弱波增强 ComputeWeakWaveBoost(values, level, out)(O(n)):
  1) 对轻度平滑(5 点滑动平均)后的信号扫描单调段,方向翻转处即为波峰/波谷;
  2) 波峰低于左右两个波峰均值(波谷高于左右两个波谷均值)即判为弱波;
  3) 波峰目标 = 较小波峰 + 等级×(较大−较小);
     波谷目标 = 较大波谷 − 等级×(较大−较小);
  4) 极值点取目标值,两侧数据点在相邻极值点的偏移量之间用平滑步进过渡,
     因此健康周期逐位不变、数据端点原样保留。
- 弱波增强面板:逐信号复选框 + 「弱波增强等级」滑块(0–100%,整个网格共用)
  + 「构建为新信号」按钮;构建名形如「<原信号> (弱波增强 M%)」。
  等级进 SceneContentHash,改动即触发重绘;Lane 新增
  weakBoost/weakBoostLevel/weakBoostItems,并在 LaneCarry、SplitLane、
  RemapAfterSignalInsert/Removal 中同步。
- 修复:放大到一定程度后左右拖拽时间光标(尤其抓取较宽的读数标签、抓取偏移较大时)
  会把光标时间推到视界之外;现在 CURSOR_MOVE 与 CURSOR_SPAN_MOVE 结束后
  按可见区间夹取(视图变化仍不移动光标,保留贴边读数与方向三角)。
- 离屏验证(窗口隐藏,不占用鼠标/键盘/屏幕):295 项检查全部通过,
  含等级 0/50/100% 的目标值与健康区逐位不变、滑块拖拽与左右钳制、
  合成纹波端到端恢复(弱周期峰峰值 100→160,健康周期 200 不变)、
  光标拖拽始终落在可见区间内。
2026-10-10 18:46:01 +08:00
DeepSeek V4.1 Flash d4206a8d67 实验性功能新增「差异放大」,并修正「构建为新信号」按钮的间距
1. 新增「实验性功能 → 差异放大」(与其它实验功能一样是带勾选的开关)
   - 用途:纹波类信号某个周期(甚至半个周期)的 M 形下凹明显偏弱时,
     把这段下凹按比例拉回周边振幅,恢复正常周期的对比度,便于看出波形异常。
   - 算法(全 O(n),不额外占用与信号长度成正比以外的内存):
     以半径约半个纹波周期的滑动平均作为纹波中心线,用邻域内「交流分量的最大值」
     作为局部纹波振幅,取全信号振幅的 75 分位作为目标振幅,
     逐点增益 = 目标振幅 / 局部振幅(夹在 1 到放大倍数之间),
     输出 = 中心线 + 增益 × 交流分量,再夹在周边包络内。
   - 关键性质(均已用合成正弦逐点验证):
     * 增益下界恒为 1,因此**只有被判定为"偏弱"的采样点会改变**,
       其余采样点输出与原值逐位相同 —— 实测逐周期表格中只有一个周期发生变化;
     * 放大结果夹在周边包络内,因此**任何一点都不超出原有的振幅范围**,
       整体值域与其它周期的峰峰值都不变;
     * 端点自动收敛到不放大,避免记录首尾被整片抬升。
   - 参数「窗口点数 X」(窗口长度,建议略大于纹波周期的一半)与
     「放大倍数 N」(增益上限)都可在浮动面板内按信号编辑。

2. 浮动面板
   - 与「均值滤波」完全同一套排版:自上而下逐信号条目,
     第一排信号名与复选框、第二排两个参数输入框;取消勾选即不显示该信号的参数与预览曲线;
     启用时默认只勾选网格内第一个可见信号。
   - 新增「构建为新信号」按钮,按各信号自己的参数把结果插入到源信号下方,
     与「均值滤波」的构建机制完全一致(统一走同一套请求与插入流程)。

3. 光标交互
   - 纵向光标额外标注差异放大曲线在该时刻的取值,配色与原始信号一致,
     数值尾部括号内容为「差异化」,双光标时同样带增量。

4. 修复「构建为新信号」按钮与面板下边界的间距
   - 原按钮行直接贴着面板下边框,与面板左右内边距及内容间距都不协调;
     现在按钮上方与下方各保留一个与左右一致的内边距(均值滤波与差异放大同时生效)。

测试:离屏验证套件新增两组检查(合成正弦上算法只改动一个周期、放大不越界、
参数上限生效、面板排版与按钮间距;再写一份合成纹波文件真正加载渲染并核对曲线数值),
合计 289 项检查全部通过;验证过程不显示窗口、不移动鼠标键盘、不抓屏。
2026-10-10 17:54:27 +08:00
DeepSeek V4.1 Flash 8801c8f019 修复缩放视界下拖拽与改色卡顿、加载字节进度、光标越界三角与中心轴均值滤波统一
1. 修复选区放大后的拖拽/改色卡顿(先实测再修,不猜)
   - 用离屏探针量化:缩放视界下一帧要画约 250 条网格线,GDI+ DrawLine 每条 0.1~0.19ms,
     整帧 26.4ms;而包络带填充本身只要 0.36ms,真正的瓶颈是逐条直线调用。
   - 网格线、时间轴刻度、绘图区边框、网格分隔线全部改为 GDI 批量 1px 直线绘制
     (一次 SaveDC/IntersectClipRect/创建画笔,逐段 MoveToEx/LineTo);
     纵轴数值胶囊改为把所有圆角矩形合并成一个路径、只调用一次填充。
   - 半透明网格线颜色先用底色预混成不透明色,否则 GDI 无法绘制透明度;
     GDI 绘制不受 GDI+ 裁剪约束,批量绘制一律显式设置裁剪矩形。
   - 实测:缩放视界下场景缓存失效帧 26.4 -> 8.25ms,改色应用 7.1 -> 3.15ms,
     缓存命中帧 2.06 -> 0.30ms。

2. 读取文件时显示"已读取 / 总大小 百分比"
   - 解析进度回调扩展为携带真实字节数(已读字节、文件总字节);
     列重组等没有字节可计的阶段只显示百分比。
   - 新增字节数格式化:单位在 GB / MB / KB 之间自适应,只输出数字与单位;
     已读大小随进度自动切换单位。
   - 进度浮层按"已读取 / 文件总大小  百分比"显示,两个大小与百分比都保留两位小数,
     完全取代原来的整数百分比。

3. 网格编号拖拽重排的绘制修复
   - GX 编号悬停时保持普通箭头光标(不再变成四向箭头),按下拖拽时才使用上下箭头。
   - 拖拽时先把整幅静态场景(含主时间轴)贴回,再把目标槽位高亮、被拖网格的轮廓与
     投影裁剪在绘图区内,因此拖到工具栏甚至更上方、或拖到时间轴及下方都不再出现
     残留与错乱。

4. 网格 Y 轴数值只在完全移出可视区时才不绘制
   - 原来只要碰到边界就整条不画;现在按可见范围裁剪胶囊与数值,
     部分可见时绘制未被遮挡的部分。

5. 边沿计数横向光标的读数与越界指示
   - 幅值读数右移,让开横线左端的三角把手,不再遮挡。
   - 幅值超出视界时(横线贴边显示)在读数上方/下方绘制方向三角,
     并且与读数水平居中对齐。

6. 常规光标读数越界与双光标叠放
   - 光标滞留在视界之外时,时间读数同样绘制方向三角。
   - 双光标读数重叠时按时间值排序:小值在上、大值在下(原来固定把第二个上移,
     左右光标交换后会显示成大的在上)。
   - 双光标同时越界到同一侧时,两条时间读数与时间差值读数在同一列垂直对齐,
     并为差值读数绘制方向三角;叠放间距按三角深度放宽,三角不会再压在相邻读数上。

7. 中心轴边沿计数与均值滤波统一
   - 参数由单一的"平滑点数 N"改为按信号的"均值点数 X + 阶数 N",与实验性功能中的
     均值滤波完全同构(同样的命名、同样的作用、同样的曲线实现),
     两条曲线逐位一致,光标处的取值标注规则也统一。
   - 浮动面板改为自上而下的逐信号条目,每个条目三排:
     第一排信号名与复选框,第二排均值点数与阶数输入框,第三排该信号的上升沿/下降沿统计;
     取消勾选即不显示该信号的参数编辑与统计结果,启用时默认只勾选第一个可见信号。
   - 网格重建继承、拆分网格、信号插入/删除的下标修正与场景缓存指纹都同步覆盖新条目。

测试:离屏自动验证套件新增一组检查(字节数格式化、解析进度字节、编号悬停/拖拽光标、
双光标读数排序与对齐、中心轴三排布局与参数、横向光标越界三角、加载浮层渲染等),
合计 241 项检查全部通过;验证过程不显示窗口、不移动鼠标键盘、不抓屏。
2026-10-10 16:47:05 +08:00
DeepSeek V4.1 Flash bc8db72f18 修复色域拖拽回弹、网格 GX 拖拽重排、均值滤波多阶与逐信号条目
1. 自定义颜色面板:拖动时鼠标移出控件不再"弹回去"
   - 根因是选点位置每帧都从 RGB 反推:色相 1 与 0 是同一个颜色(红),拖到色相条底部
     下一帧反推回 0,指示条弹到顶部;拖到色域方块右下角之外时明度为 0(黑色),
     黑色的饱和度无定义,反推得 0,选点弹到最左边。
   - 现在把"选点位置(饱和度/明度)与色相"作为独立状态保存,只由对应控件与外部改色维护;
     越界一律夹取到最近边界,因此鼠标离开控件后选点停在边界上。
   - 统一色域方块、色相条、预览色块与色号框的圆角;RGB 滑块适当加粗;
     色域选点去掉外圈深色描边(只保留白色描边),色相指示器改为白色描边的圆角长方条、
     底色取该位置的颜色;色相条改用分段线性渐变绘制。

2. 网格 GX 编号支持拖拽重排
   - 按住网格图例左侧的 GX 徽标即可上下拖动,整块网格(连同波形与标尺)跟随鼠标移动;
     途经的网格保持自身大小、整体让出一格,目标槽位有吸附高亮提示。
   - 松开后真正重排并从下到上/从上到下重新编号,信号列表徽标、图例徽标、菜单与浮动面板
     中所有 GX 编号同步更新;手动排布后切换为自定义划分,后续重建网格不会打乱次序。
   - 拖动期间复用静态场景缓存,按网格条带平移贴图,因此大文件下依然流畅。

3. 均值滤波升级为"均值点数 X + 阶数 N"
   - 原"均值点数 N"更名"均值点数 X",新增"阶数 N":预览曲线以 X 点均值滤波的结果为蓝本,
     再重复同样的滤波共 N 阶(1 阶即与原来的单次滤波逐位一致)。
   - 浮动面板改为逐信号条目:第一排是信号名与复选框,第二排是均值点数与阶数输入;
     只有勾选的信号才绘制预览曲线,未勾选时不显示第二排;启用功能时默认只勾选第一个信号。
   - 参数按信号保存(同一网格内不同信号可用不同参数),「构建为新信号」按各自参数构建。
2026-10-10 15:33:45 +08:00
DeepSeek V4.1 Flash 2d029fb09b 修复合并网格后的新增信号、适应视图联动、调色面板排版与左右越界三角
1. 合并网格后新增信号不再挤进合并网格
   - 分组复选框与「全部显示」按钮此前只更新可见性,没有像单信号勾选那样把划分策略
     切到自定义,于是合并网格把新增信号一并吞掉。
   - 现在两者在确有信号由不可见变可见时同样切换到自定义划分,
     新增信号各自独占一个网格并追加在列表最下方,原合并网格保持不变。

2. 适应视图不再取消「选区放大」模式与「选区 Y 轴自适应」
   - 此前适应视图会把缩放模式复位为无,并把全部网格的 autoRange 置真;
     而自动适应区间只由 autoRange 决定,置真等于把已经算好的时间段幅值丢掉,
     表现为"点一下适应视图,Y 轴自适应就失效了"。
   - 现在保留缩放模式;开启了「选区 Y 轴自适应」的网格改为按新的时间视图重新匹配,
     其余网格才恢复整段自适应。

3. 「按网格时间轴展开」联动其它网格
   - 时间视图是全局的,展开后其余开启了「选区 Y 轴自适应」的网格同样重新匹配 Y 轴,
     不再只有被展开的那一个网格量程合适。

4. 自定义颜色面板排版重做
   - R/G/B 的标签、滑块与数值改为同属右侧一列并共用同一行,标签紧贴各自的滑块;
     预览色块与色号移到左列下方并与色域方块同宽,色号编辑框不再超出面板边界;
     面板高度按内容重新计算,底部不再留空。
   - 色域方块上的选点去掉外圈深色描边,改为"中心为所选颜色 + 白色描边"。
   - 色相指示器由黑色横条改为白色描边的圆角长方条,底色取该位置的颜色;
     色相条本身改用分段线性渐变绘制。

5. 修复光标数据点向左/向右越界时的三角
   - 三角沿朝向伸出的深度大于贴边时距边界的距离,导致有一大半画在网格绘制区之外,
     裁剪后只剩残缺一角、描边也因此不完整。
   - 现在左右越界时把锚点向内推一个三角深度,三角完整落在绘制区内;
     同时四方向越界都让三角与显示的数值纵向居中对齐。
2026-10-10 14:38:54 +08:00
DeepSeek V4.1 Flash a1e30985b8 修复输入框全选高亮溢出、标签页重命名无法失焦、新增信号行删除按钮
1. 内联输入框全选高亮越界(组名/标签页名/信号名编辑)
   UiFillRect 在不透明且面积 >= 20000 时走 GDI FillRect 快路径,而 GDI 填充不受
   GDI+ SetClip 约束;长文本全选时高亮宽度可达上千像素,于是画到输入框之外。
   UiDrawEditField 现在先把高亮矩形与裁剪区求交再填充。

2. 标签页重命名处于编辑态时,点击输入框之外的任何位置都不退出编辑
   Application 只在点击落在标签栏内时才把点击交给 TabBar。现在 WM_LBUTTONDOWN
   会先检查 m_tabBar.IsEditing(),是则提交(OnEditKey + OnTabBarResult)并退出编辑态,
   覆盖绘图区、信号面板、工具栏、分隔条等位置,且不会丢失新名字。

3. 信号选择区域每个信号新增 ✕ 删除按钮
   - 位置与所在组复选框同一列(垂直对齐),悬停显示手型光标并高亮。
   - 点击后面板向宿主发送 WM_APP+2;Application::RemoveSignal 会重映射所有标签页的
     可见性与网格引用、修正当前选中项,再真正从 DataSet 中删除该信号并释放采样内存;
     删除组内最后一个信号时退化为移除整个文件分组。
   - DataSet::RemoveSignal 采用移动填充 + shrink_to_fit,保证缓冲区内即刻析构。
2026-10-10 10:54:50 +08:00
DeepSeek V4.1 Flash 350538c634 命名审查与垃圾代码清理(纯重命名 / 死代码删除,无行为变更)
前提:加载完成后全部采样都已驻留内存,程序此后与源文件再无联系。
据此修正了一批会让人误以为"仍在读写文件"的命名:

- SampleFileAt → SampleSignalAt(取的是内存信号在给定时刻的采样值)。
- DataSet::AddPreparedFile → AddDataFile。
- PlotView::InvalidatePolylineCache → InvalidateDerivedCaches
  (它同时清空折线、边沿统计、中心平均值曲线、静态场景缓存与悬停引用)。
- PlotView::CursorColor(int which) → CursorColor()(两条光标同色,参数从未使用)。
- UiEllipsize(g,…) → UiEllipsize(…):纯测量不绘制,删掉被忽略的绘图上下文参数;
  同时删除与 UiMeasureTextWidth 完全重复的 UiTextWidth,调用点统一到 UiMeasureTextWidth。

清理残留参数((void)xxx;):
- TabConfig 的可见性/网格族(SetVisible / ToggleVisible / SetFileVisible / SetAllVisible /
  SoloSignal / SetMode / SyncLanes / FileHasVisible / FileAllVisible)去掉从未使用的
  const DataSet& 参数(仅 SyncToDataSet 真正需要数据层,保留)。
- PlotView::OnLButtonUp(int y)、OnMouseWheel(int delta, bool shift);PainterSignalHalo 去掉未用的 ref。
- BuildDataFile 中未使用的局部 rowCount。

删除无人调用的死函数:
  DataSet::Clear / AddFromTable;SignalColorCount;WideToUtf8 / StartsWith;
  PlotView::ViewMinTime / ViewMaxTime / EdgePanelRect / EdgePanelCloseRect /
  EdgeCenterPanelRect / ScaleLaneRange / BeginLaneValueEdit / LaneContentHeight;
  SignalPanel::NeedsScrollBar / IsFilterEditing / FilterText / ContentHeight;
  PopupMenu::EditingItemId;TabBar::IsDragging;TextEdit::PlaceCaret。

删除只写不读的死字段:CsvTable::sourceRowCount(与 rowCount 等义)与 skippedRowCount。

以 VERY_BIG_DATA.CSV 回归验证:加载与勾选、筛选框(含"无匹配的筛选信号")、
样式区线宽文案省略、选区放大(横向与纵向)、双光标读数与 Δt、右键菜单(Y 轴数值与
实验性功能子菜单)、合并/拆分网格、标签与信号重命名省略号,行为均与改动前一致;
make clean && make all 无任何警告。
2026-10-09 21:52:46 +08:00
DeepSeek V4.1 Flash f5028b1e18 实验性功能新增「均值滤波」+ 构建为新信号
- 「实验性功能」二级菜单新增带勾选的「均值滤波」:开启后为本网格每条信号叠加绘制
  一条 N 点滑动平均曲线,算法与「边沿计数(中心轴)」的中心平均值曲线**完全一致**
  (同一实现 ComputeMovingAverage),配色同样由信号色派生为高对比度颜色、透明度一致。
- 新增均值滤波浮动面板:标题栏可拖拽、✕ 关闭,面板内列出被处理的信号名、
  「均值点数 N」内联编辑行,以及底部的「构建为新信号」按钮(悬停高亮 + 手型光标)。
- 「构建为新信号」:把滤波后的曲线作为新信号插入,命名为「<原信号名称> (N点均值)」,
  归属到原信号所属组的原信号位置**下方**,成为独立的新信号;其所在网格也移动到
  原信号网格的下方。合并网格时一次按钮为该网格内每条可见信号各构建一条。
  为此新增 DataSet::InsertDerivedSignal / TabConfig::RemapAfterSignalInsert /
  TabConfig::MoveLaneOfSignalBelow / TabConfig::RenameLanes(插入位置之后的信号引用
  与可见性列同步重映射)。
- 光标交互与「边沿计数(中心轴)」同构:光标处标注均值滤波曲线的取值
  与双光标增量,文案为「值(均值滤波)」/「值(+增量 均值滤波)」;
  两条派生曲线的取值胶囊已抽成同一段绘制逻辑。
- 浮动面板种类由 bool centerAxis 改为 EdgePanelKind{COUNT,CENTER,MEAN},
  布局/宽度/命中测试/绘制统一走同一套几何。
- 以 VERY_BIG_DATA.CSV 验证:曲线预览、N 编辑、双光标取值标注、
  单信号与合并网格两种情况下的新信号命名与插入位置均正确。
2026-10-09 21:00:38 +08:00
DeepSeek V4.1 Flash 82a29362eb 网格管理增强:新信号置底、拆分当前网格、中键自由平移、选区模式图例可用、面板悬停高亮、中心轴样式与越界三角
- 新勾选的信号所在网格固定出现在**最下方**:
  原先 PER_SIGNAL 模式按 visibleRefs(文件/列序)重建网格,新勾选的信号会按其列序插到
  中间,位置看起来"不确定"。现在先按「原有网格位置」排序(已分配过网格的信号保持相对次序),
  再把尚未分配网格(新勾选)的信号统一追加到末尾。

- 网格右键菜单在「实验性功能」上方新增「拆分当前网格」(`PLOT_CMD_LANE_SPLIT`):
  把该网格内的信号按个拆分成独立网格,新网格插入到原网格的**下方依次排列**,
  原网格下方的网格顺次后移。网格编号(GX)完全由位置推导,因此左侧列表徽标、图例徽标、
  面板标题、菜单标题等所有使用该编号的地方会同步更新,不会错位。
  新增 `TabConfig::SplitLane()` / `PlotView::SplitLane()` / `PlotView::LaneSignalCount()`
  (仅 1 条信号时菜单项置灰)。拆分出来的网格继承原网格的网格自身状态
  (Y 轴自适应、边沿计数、面板位置等)。

- 鼠标**中键**按下拖拽也可自由查看区域(水平平移时间轴 + 纵向偏移当前网格幅值):
  新增 `PlotView::OnMButtonDown/OnMButtonUp` 与 `Application::WM_MBUTTONDOWN/UP`,
  **任何缩放模式下都可用**(不改变当前模式)。拖动期间 `WM_MOUSEMOVE` 的按键掩码
  加入 `MK_MBUTTON`,光标刷新为抓握图标。

- 选区放大模式下不再阻断图例交互:把「点击图例条目 → 选中信号」的判定移到选区放大分支
  **之前**,并让图例悬停(半高亮)在选区放大模式下同样生效(该模式只应改变拖拽语义)。
  同时选区放大模式下也可用中键拖拽平移。

- 实验性功能浮动面板悬停时高亮其所属网格(与鼠标直接停在网格上一致):
  `OnMouseMove` 中若鼠标落在面板上则把 `m_hoverLane` 置为该面板所属网格。

- 「边沿计数(中心轴)」:
  * 中心平均值曲线的颜色样式改为与光标一致(`CursorColor(1)`,即「边沿计数」横向光标
    与中心值胶囊的颜色),曲线与其取值标注、光标形成统一的视觉语言。
  * 中心值标注形式改为「数值(中心轴)」(数值在前、尾缀在后);
    双光标模式下由右侧光标额外显示增量,形如「数值(+0.0008 中心轴)」,
    与常规信号的增量显示保持一致(无尖头括号)。
  * 修复:光标处于当前显示区域之外(贴边显示)时,常规数据点会变成三角指示方向,
    而中心轴数据点仍是圆点。现在中心轴数据点复用同一分支,越界时同样绘制三角。

验证(TestData/VERY_BIG_DATA.CSV,125%、1725x996):
- 置底:先勾选第 5 个信号(电流钳采集(原始))→ G1,再勾选第 1 个信号(编码器A相)→ G2,
  新勾选的信号确实出现在最下方。
- 拆分:G1(编码器A相) / G2(飞线IO+编码器B相) / G3(电流钳(原始)) 时拆分 G2,
  得到 G1 / G2(飞线IO) / G3(编码器B相) / G4(电流钳(原始)),
  原本在中间的电流钳顺延为 G4,左侧徽标、图例徽标全部同步。
- 中键:常规模式与选区放大模式下中键拖拽均能把时间轴平移到 80~160(截图核对)。
- 选区放大模式:悬停图例条目显示半高亮;点击图例条目可切换选中信号(左侧高亮随之切换)。
- 面板悬停:鼠标停在 G1 的「边沿计数」面板上时 G1 区域被高亮(与悬停 G1、G2 两种情形
  做区域哈希对比,确认高亮归属正确)。
- 中心轴:曲线为光标橙 `#CB4B16`;面板标题「中心轴边沿计数」、底部「平滑点数 N = 5」;
  单光标显示 `4.9417` + `4.94199(中心轴)`;
  双光标(标题带「(光标区间内)」,计数 341959/341957)右侧光标显示
  `4.9425 (+0.000…)` + `4.94214(+0.00… 中心轴)`,左侧光标无增量;
  把 N 改为 4000 后曲线与计数同步更新(2333700/2333700);
  用选区放大把光标推到视野外后,中心轴数据点在与信号相同的贴边位置绘制为**橙色三角**
  (像素扫描 x=479 处得到 6px 高的 `#CB4B16` 三角,而非常规圆点)。
- 回归:[1].CSV 上「边沿计数」面板正常(上升沿 2 / 下降沿 2),中键平移正常。
- make clean && make all 无警告无错误。
2026-10-09 15:21:10 +08:00
DeepSeek V4.1 Flash 5182bd8aa3 实验性功能完善:面板交互修正 + 新增「边沿计数(中心轴)」
一、实验性功能浮动面板的交互修正(「边沿计数」与「边沿计数(中心轴)」共用)
- 面板只有**标题栏**可以拖拽:鼠标在标题栏显示抓握光标(IDC_SIZEALL),
  在面板主体(含统计行与底部编辑行)保持原始箭头,按下主体也不再拖动面板(仅消费点击,
  不会穿透到底层的平移/选区/信号拖拽)。
- ✕ 关闭按钮:鼠标悬停时高亮(danger 色底 + danger 色叉),但**不改变鼠标光标样式**。
- 为此新增 `EdgePanelLayout`(panel / title / close / edit / rows)与
  `EdgePanelLayoutFor(laneIndex, centerAxis)`,`QueryCursor`、`OnMouseMove`、`OnLButtonDown`
  与绘制统一按该布局判定。

二、新增「实验性功能 → 边沿计数(中心轴)」(带 √ 的切换项,按网格独立)
- 开启后为网格内**每条信号**叠加绘制一条"中心平均值曲线":
  每个数据点 = 自身与左右各 N 个数据点(共 2N+1 点,边界处按实际窗口)的平均值。
  用滑动窗口求和构建,整体 O(n),不额外占用前缀和内存;结果按 (信号, N) 缓存
  (deque 保证引用有效),数据层变化或 N 改变时清空。
- 该曲线只是叠加显示,**不会**加入左侧信号列表;
  为与波形区分,颜色按背景明暗把信号色向黑/白方向拉远(浅色主题加深、深色主题提亮),
  线宽略粗于原信号。
- 纵向光标仍会标注这条曲线的取值:在原取值胶囊之外额外绘制一个「中 <值>」胶囊
  (与曲线同色、半透明),并复用统一的避让逻辑(PlaceCursorLabel,已抽成函数)。
- 统计规则:**信号从下往上越过中心平均值曲线 → 上升沿;从上往下穿过 → 下降沿**
  (比较 `signal[i] - center[i]` 的符号变化,NaN 视为断点)。
- 浮动面板标题为「中心轴边沿计数」,样式与「边沿计数」面板一致(GX 徽标 + 标题 + ✕ +
  每信号一行名称与「上升沿 N / 下降沿 M」,数字完整不省略、面板宽度按文本实测自适应);
  面板**底部固定一行「平滑点数 N」内联编辑设置**(新增 EditFilter::NUMBER 编辑目标
  PlotEditTarget::EDGE_CENTER_SMOOTH,夹在 0–1000000),始终位于面板最下方。
- 与双光标模式联动:双光标时标题追加「(光标区间内)」,只统计左右光标之间的区间;
  区间端点恒取两光标时间的 min/max,因此把任一光标拖到另一侧(左右交换)后依然正确。
- ✕ 关闭面板的同时关闭该网格的「边沿计数(中心轴)」功能(面板与曲线一并消失)。

验证(TestData/VERY_BIG_DATA.CSV,编码器A相,125%、1725x996):
- 面板光标形态探测:主体 = ARROW、标题栏 = SIZEALL、✕ = ARROW;
  从主体拖动面板不发生位移(截图核对)。
- ✕ 悬停高亮可见。
- 「边沿计数(中心轴)」:面板标题「中心轴边沿计数」、底部「平滑点数 N = 5」;
  中心平均值曲线(深蓝)清晰可见;把 N 改为 3000 后计数同步更新。
  用独立脚本 .preflight/centerprobe.ps1 按同一规则复算,与界面**逐位一致**:
  N=5 → 上升沿 2712920 / 下降沿 2712913;N=1000 → 2373176 / 2373176。
- 双光标联动:区间 [48.0211, 64.4051](面板标题带「(光标区间内)」)→ 349220 / 349220;
  把光标 1 的时间改到 100(越过光标 2 的 64.4051)后,区间变为 [64.4051, 100],
  计数 778085 / 778084,与按该区间复算的结果一致(±2 为光标时间显示值取整导致的边界差)。
- 纵向光标读数:右光标显示 `4.9417 (-0.071945)` + `中 4.94199`,
  左光标显示 `中 2.9165`(中心曲线取值单独标注)。
- 左侧信号列表仍只有原信号,未新增曲线条目。
- 回归:[1].CSV 上「边沿计数(光标区间内)」正常(Δt:151ms 200us);
  「边沿计数(中心轴)」在 [1].CSV 上曲线清晰可见(上升沿 199 / 下降沿 199)。
- make clean && make all 无警告无错误。
2026-10-09 11:23:15 +08:00
DeepSeek V4.1 Flash cd6e0ed058 界面增强:网格图例 GX 编号、工具栏状态修复、增量括号、实验性边沿计数
- 每个网格图例左侧新增当前网格的 “GX” 编号徽标,与左侧信号列表行末的 G1/G2 徽标
  使用完全一致的样式(同宽高、同圆角、同配色、同字体),并纳入图例底板范围。

- 修复工具栏 toggle 状态被重置的缺陷:Toolbar::Layout() 会重建全部按钮,
  原先会把 checked 全部清零。因此当「光标」按钮因为模式变化(光标x2 → 光标)
  触发文本变更与 Relayout 时,同帧刚设置好的「Y 轴自适应」「选区放大」勾选态被清掉,
  表现为切换光标模式时前面两个开关被一并取消。现在 Layout() 会按 action 继承既有
  checked 状态,重建后状态保持不变。

- 双光标右侧光标的增量显示去掉逗号,改为包裹在圆括号中:`4.9425 (+0.0008)`。

- 网格右键菜单在分隔横线上方新增「实验性功能」(带二级子菜单指示箭头):
  鼠标悬停即向右展开二级菜单,其中包含「边沿计数」切换项(带 √)。
  为此为 PopupMenu 增加了完整的二级子菜单支持:子菜单排版(贴主菜单右缘、
  右侧空间不足时翻到左侧、限制在宿主窗口内)、悬停展开/移开收起、
  点击父项不下发命令、子菜单内按下/抬起配对提交、键盘(← 收起 / → 展开 /
  ↑↓ 在子菜单内移动 / Enter 提交 / Esc 先收起子菜单再关菜单)、
  独立的投影与绘制、ContainsPoint 覆盖子菜单区域、Relayout 后子菜单位置重建。

- 「边沿计数」开启后(按网格独立,状态随 RebuildLanes 按信号继承):
  * 在该网格绘制一条横向光标,风格与纵向时间光标一致(同色同线宽),
    左右两端各带一个尖端朝内的三角把手。
  * 左端显示当前光标的 Y 轴值,读数胶囊纵向居中于横线、靠网格左侧。
  * 横向光标不绘制任何数据点取值标注(与纵向光标的行为不同)。
  * 横向光标可上下拖动改变幅值,拖动时显示上下箭头光标。
  * 生成带 ✕ 关闭按钮的浮动面板:标题栏显示 “GX” 徽标 + “边沿计数”,
    下方按信号列出名称(信号色)与「上升沿 N / 下降沿 M」。
    面板可在整个绘图区内拖动(限制在绘图区内),✕ 仅收起面板、保留横向光标,
    重新勾选菜单项可再次展开。
  * 边沿判定阈值为信号幅值的 (min+max)/2 中点穿越,NaN 视为断点;
    统计结果按 (文件, 信号) 缓存,数据层变化时随折线缓存一并失效。

验证(TestData/VERY_BIG_DATA.CSV,编码器A/B相密集方波,125%、1725x996):
- 图例编号:G1 / G2 徽标与左侧列表徽标样式一致。
- 工具栏:开启「Y 轴自适应」+「选区放大」后,光标由 光标x2 切回 光标,
  两个开关仍保持勾选(截图核对)。
- 增量:右光标显示 `4.9425 (+0.0008)`。
- 二级菜单:悬停「实验性功能」展开「边沿计数」,箭头与子菜单位置正确。
- 边沿计数:横向光标 + 左端读数 `2.54415` + 面板
  `G1 边沿计数 / 编码器A相 / 上升沿 1333422 下降沿 1333421`;
  上下拖动后横线上移到 4.13602(与 Y 轴刻度一致);面板拖到绘图区左下并保持在内;
  点击 ✕ 后面板收起而横向光标保留;
  光标形态探测:横线悬停 SIZENS、面板悬停 SIZEALL。
- 合并网格后面板同时列出网格内两条信号(编码器A相 / 编码器B相)。
- 回归:[1].CSV 双光标正常(光标x2),Δt:151ms 200us;
  make clean && make all 无警告无错误。
- 修复过程中发现:静态场景缓存命中路径(贴图快路径)与整幅重绘路径是两处独立的
  叠加层绘制入口,新增的随鼠标变化内容必须同时加在两边。
2026-10-09 09:30:30 +08:00
DeepSeek V4.1 Flash 0fffb3ed09 feat(ui): 修复预设色块误跳自定义色、选区 Y 轴自适应改为切换开关、菜单项改名移位
1) 修复样式区"点预设色块直接跳到自定义色块"
- 根因:加载时 customColor 被赋成信号自身的预设色,而样式区按
  "color == customColor 即视为在用自定义色" 判定高亮,于是点自身的预设色时
  高亮立刻跳到自定义色块上(第 N 个信号点第 N 个预设色必然复现)
- customColor 初值改为调色板中"本信号预设色向后递进一格"的颜色
  (palette[(slot + 1) % count]),自定义色块因此显示与预设色块排布连续的下一色
- 同时收紧高亮判定:仅当当前颜色"不属于任何可见预设色"时才认为在用自定义色。
  这样即使自定义色恰好等于某个预设色,点击该预设色也始终高亮预设色块,
  彻底消除"高亮乱跳";用拾色器选出的非预设色仍正常高亮自定义色块

2)「选区 Y 轴自适应」改为切换开关(原为一次性操作)
- Lane 用单一布尔量 fitYToSelection 表示(删除 viewAutoRange/viewAutoMin/viewAutoMax)
- 开启后每次时间轴选区放大(ApplyTimeSelection → ApplySelectionAutoFit)
  都会把该网格 Y 轴匹配到新的可见时间区间
- 任何手动幅值调整(Y 轴选区放大、纵向平移、缩放、直接输入上下限)都会关闭对应网格的开关
- RebuildLanes 按信号继承该开关:勾选/取消勾选信号不再把用户刚打开的开关悄悄清掉

3) 菜单「恢复 Y 轴自适应」移除,原位置新增「选区 Y 轴自适应(全局)」
- 全局项为切换状态:选中即把全部网格的开关置为开,取消即全部置为关;
  任意网格单独关掉后,全局项立即变为未勾选(= AllLanesAutoFitToSelection)
- 工具栏在「适应视图」之后新增「Y 轴自适应」切换按钮,与全局项是同一个开关,
  每帧同步选中态
- 删除了 PLOT_CMD_LANE_AUTO / PlotView::LaneRangeIsAuto / ResetLaneRange 等已无用的接口

4)「时间轴自适应(匹配本网格)」改名为「按网格时间轴展开」并移到分隔线上方
- 新顺序:网格 N / Y 轴最大值 / Y 轴最小值 / 选区 Y 轴自适应 / 按网格时间轴展开 /
  --- / 选区 Y 轴自适应(全局)/ 全部自适应

验证(TestData/[1].CSV 11 信号,窗口 1725x996,125% DPI):
- 颜色:初始高亮在预设色块 1;点预设 1 与预设 2(等于自定义色初值)均保持点中的色块高亮;
  用拾色器改成非预设色后高亮正确落在自定义色块
- 逐网格:菜单项勾选/取消即时反映;开启的网格做时间轴选区放大后 Y 轴自动匹配
  (仅该网格变化,其它网格保持整段范围)
- 全局:工具栏按钮与菜单全局项互相联动;单独取消一个网格后两者都变为未勾选;
  隐藏/显示信号后开关保持
- 「按网格时间轴展开」能把缩放后的时间轴展开回该网格信号范围;「全部自适应」仍正常
- 超大文件回归(VERY_BIG_DATA 1.77GB)菜单/悬停正常;空闲 CPU 0.00%

构建: make clean; make all 无警告无错误
2026-10-07 13:57:46 +08:00
DeepSeek V4.1 Flash dd48cdd2e1 feat(ui): 工具栏"选区"改名、菜单对勾右置与边距修正、选区自适应勾选、悬停/选区拖拽性能
1) 工具栏文案:"时间轴缩放"/"Y 轴缩放" -> "时间轴选区"/"Y 轴选区"
- Toolbar.cpp 按钮标签、Toolbar.hpp 枚举注释、Application 状态提示语同步更新

2) 网格右键菜单:对勾从左侧移到右侧,并修正菜单内各元素边距
- 文本列统一为 kPadH + kItemPad(5 + 8),三类条目(HEADER/NORMAL/EDIT)共用;
  原先左侧预留 22px 标记列,导致"网格 N"、"Y 轴最大值"、"选区 Y 轴自适应"等
  所有文本的左边距被整体推右(用户报告的"文本左边距过大")
- 对勾改画在条目右侧的 kMarkerColumn(18) 列内,文本宽度相应预留,不会与文字重叠
- EDIT 行输入框改为右对齐到条目内容区右边界,宽度由 NaturalEditFieldWidth() 统一计算,
  空间不足时为左侧说明文字保留自然宽度(避免被菜单宽度上限挤成省略号)
- 分隔线、色块行同样改用 kItemPad 内缩;kRightPad 已删除

3) "选区 Y 轴自适应"增加与"Y 轴自适应"一致的勾选标记
- Lane 新增 viewAutoRange / viewAutoMin / viewAutoMax,记录应用该操作时的视图时间区间
- 新增 PlotView::LaneRangeIsAutoToView():只有未被任何手动幅值改动且时间选区未变化时才为 true
- 所有手动改动路径(ApplyValueSelection/ScaleLaneRange/ShiftLaneRange/ApplyLaneValueText/
  EndEdit/ResetLaneRange/MoveSignalToLane)都会清除该状态;
  时间选区变化后 viewAutoMin/Max 与当前视图不符,勾选自动消失
- RefreshPlotMenuValues() 同步刷新该项状态

4) 修复大文件(VERY_BIG_DATA 1.77GB / 5 信号)下悬停与选区缩放的严重卡顿
- 根因:任何悬停态变化(左侧信号列表、网格内命中曲线提示)或选区拖拽都会触发整幅重绘,
  其中波形绘制约 80ms/帧,因此交互帧率只有 ~10fps
- 静态场景缓存从"仅拖拽信号/光标"推广为"只要场景键一致就复用",缓存区域由整个客户区
  收敛为仅绘图区:工具栏/标签栏/面板各自带悬停态必须每帧绘制(约 10.5ms),
  而真正昂贵的波形改为直接贴图(约 1ms)
- 场景键新增 contentHash(FNV-1a 折叠网格几何/幅值、每条信号的引用/可见性/
  颜色/透明度/线宽/样式/显示名与所属文件名):改样式、重命名、增删信号都会自动失效
- 随鼠标变化的内容全部移出缓存:新增 PaintHoverHighlight() 在贴图之后绘制
  悬停网格底色(半透明叠加)与悬停信号光晕(PaintSignalHalo());
  PaintLane 内只绘制拖拽中的信号光晕(key 中记录 haloFile/haloSignal)
- EnsureSceneCache 改为要求位图尺寸与当前区域严格相等(原 >= 复用会在窗口缩小后
  把旧像素画到绘图区之外)
- Application::Render 移除 reuseScene 分支,统一每帧绘制界面框架

实测(VERY_BIG_DATA 5 信号,Release):
- 整幅重绘 ~80ms -> 命中缓存贴图 ~1ms
- 悬停左侧信号列表:~95ms -> ~14ms/帧
- 悬停网格内信号(含光晕高亮):~95ms -> ~28~32ms/帧
- 时间轴 / Y 轴选区拖拽:~95~105ms -> ~19~22ms/帧
- 非拖拽静止帧 ~118ms 维持不变;空闲 CPU 0.00%

构建: make clean; make all 无警告无错误
2026-10-07 11:26:43 +08:00
DeepSeek V4.1 Flash a3e638fa58 fix(plot): 默认线宽 1.0px、菜单文本左对齐、散点白边修复与大文件拖拽性能优化
1) 默认线宽改为 1.0px
- SignalStyle::lineWidth 初值 1.6f -> 1.0f (DataModel.hpp / DataModel.cpp)
- 新增 LaneScroll() const 重载,供 const 的 MakeSceneCacheKey() 读取

2) 网格右键菜单文本左对齐
- PopupMenu 的 HEADER / NORMAL / EDIT 三类条目统一使用 kMarkerColumn(22.0f)
  作为文本列,替换原先写死的 8.0f,使 "网格 N"、"Y 轴最大值"、
  "Y 轴最小值"、"选区 Y 轴自适应" 等所有条目左边缘严格对齐

3) 修复散点/点线模式下数据点重叠处的白色缝隙
- 根因: GDI+ GraphicsPath 默认 FillModeAlternate(奇偶填充),重叠圆的交叠区域
  被反向填充,视觉上表现为白色缺口/白边
- 主绘制与拖拽 ghost 的 GraphicsPath 均显式 SetFillMode(FillModeWinding)
- ghost 由逐点 FillEllipse 改为单个 GraphicsPath 一次 FillPath(批量绘制)

4) 大文件拖拽流畅性优化 (VERY_BIG_DATA.CSV 1.77GB / 5 信号)
- 新增拖拽静态场景缓存: 在 MOVE_SIGNAL / CURSOR_MOVE 期间把整个客户区
  (绘图区 + 标签页 + 工具栏 + 信号面板) 捕快到 m_sceneDc 位图,后续帧直接
  BitBlt,仅在 SceneCacheKey(dragMode/viewMin/viewMax/laneScroll/laneCount/
  区域/scale) 变化时重绘。Application::Render 在复用场景时跳过窗口背景与
  各子控件绘制,缓存位图由 ~PlotView() 释放
- 失效点: SetContext / SetScale / Layout / InvalidatePolylineCache
- 光标数值读数从 PaintLane 抽出为 PaintLaneReadouts(),在缓存 blit 之后绘制,
  避免读数被缓存导致拖动时显示旧值
- 拖拽 ghost 复用已有 PolylineCacheEntry,改用 TranslateTransform 偏移,
  不再重复构造折线顶点
- 实测: 拖拽帧耗时 134-146ms -> 22-25ms;散点模式拖拽约 24.6ms;
  非拖拽重绘维持约 118ms;空闲 CPU 0.00%

构建: make clean; make all 无警告无错误
2026-10-07 10:22:57 +08:00
DeepSeek V4.1 Flash 04e98ee041 Esc 退出缩放模式、修复拖拽时波形变模糊、加速超大文件的模式切换
Esc 行为(用户要求):
- 网格内按 Esc 在取消拖拽选区的同时,退出全部缩放模式(时间轴缩放 / Y 轴缩放),
  工具栏两个缩放按钮随之回到未选中态;时间光标按钮不受影响。
- 新增 PlotView::ExitZoomModes(),由 Application 的 VK_ESCAPE 分支与 CancelDrag 一起调用。

修复拖拽时波形变模糊(用户报告):
- 上一轮为提升拖拽帧率引入了"交互降级":拖拽期间关闭抗锯齿 + 顶点预算减半 +
  每列只扫 32 个采样点。实测这会让包络丢掉峰值、线条失去抗锯齿,
  在选区放大 / 拖拽信号 / 拖拽光标时明显变"糊"。现已**全部移除**,
  任何交互期间都按全质量绘制。
- 用"粗粒度包络层"替代降级来保证交互帧率:
  SignalData 新增 coarseMin/coarseMax/coarseStride(每 256 个采样一组存 min/max,
  额外内存约为采样数据的 0.8%),在 BuildDataFile 统计 min/max 的同一个循环里顺带构建
  (不额外扫数据)。折线包络改为读取"每列覆盖到的分组",
  数据读取量从 O(可见采样数) 降到 O(像素列数 × 少量分组),**绘制结果与全量扫描完全一致**。
- 实测(VERY_BIG_DATA.CSV = 1.77GB、2580 万行 × 5 信号,全选显示):
  视图变化时的包络构建由 176~196ms 降到 ≈0ms;平移拖拽整帧由约 336ms 降到 90~120ms。
- 注意:包络路径按分组判断无效值(整组无有效值才断线),
  因此密集视图中孤立的 NaN 不再把波形切成两段(原先会),视觉上更干净。

加速超大文件的显示模式切换(用户报告):
- 散点绘制由逐点 FillEllipse 改为把全部散点合并进一条 GraphicsPath 后一次 FillPath:
  实测 2500 点由 63ms 降到 7ms(基准),程序内单条密集信号由约 51ms 降到约 22ms,
  仍是抗锯齿圆形,观感与逐点绘制一致。
- 线段/散点/点线切换时不再有卡顿感;空闲 CPU 仍为 0.00%。

验证:
- Esc:分别启用时间轴缩放 / Y 轴缩放后按 Esc,两个按钮均回到未选中(截图对比),
  时间光标按钮保持选中;框选拖拽中按 Esc 时间轴保持 0.2~1.2 不变。
- 清晰度:光标拖拽中与静止时对同一区域做像素哈希,结果完全一致;
  框选拖拽同样一致;信号拖拽中间态截图中源波形与虚影均为抗锯齿全质量。
- 超大文件:线段/散点/点线切换与拖拽的正常渲染(截图),1.77GB 文件加载过渡动画正常。
- 回归:菜单内联编辑 Y 轴上下限、选区 Y 轴自适应、图例点击选中、面板改名均正常。
- 内存:BIG_DATA 全选 122MB(粗粒度层约 +1MB);VERY_BIG 全选 1224MB(理论下限 1.25GB)。
- make clean && make all 零警告零错误。
2026-09-30 19:34:52 +08:00
DeepSeek V4.1 Flash 45b44eae57 网格菜单重构、大文件异步加载与内存/解析优化、修复应用图标
网格右键菜单:
- 菜单顺序改为: 网格 N / Y 轴最大值 / Y 轴最小值 / 选区 Y 轴自适应 / --分隔线-- /
  Y 轴自适应 / 时间轴自适应 / 全部自适应
  (恢复自适应移到分隔线以下、时间轴自适应上方)
- Y 轴最大值/最小值改为菜单内联输入框:点击就地编辑、回车提交,菜单不关闭,
  处理方式与拾色器的 RGB 内联编辑一致;提交后按真实夹取结果回写菜单显示值,
  并同步刷新自适应项的文案/对勾/可用状态
- 新增"选区 Y 轴自适应":只按当前显示时间段内的数据做幅值自适应
  (时间单调时二分定位区间,非单调时全扫并按区间过滤)

大文件加载:
- 加载改为工作线程执行(解析 + 按列重组),主线程抽送消息并播放过渡动画
  (旋转弧线 + 进度条 + 文件名 + 百分比 + 按 Esc 取消),界面不再整块卡死
- 加载完成后主线程只做一次 O(1) 的移动入队,不会产生可见卡顿
- 新增 DataModel::BuildDataFile / DataSet::AddPreparedFile:不依赖 DataSet,
  因此可以安全地在线程上运行

内存与解析效率:
- CsvTable 由"行优先二维数组"改为"列优先":百万行文件原先会产生上百万次独立堆分配
  (每行还有 vector 控制块与容量对齐开销),现在每列一整块连续内存
- 解析改为流式分块读取(4MB),不再把整个文件读入内存,也没有体积上限
  (原先超过 512MB 直接拒绝);实测 51MB 文件峰值内存约 126MB(数据本身 113MB)
- BuildDataFile 直接把整列移动进 SignalData(零拷贝),不再逐元素复制
- TryParseDouble 增加十进制快速路径:ucrt strtod 实测约 335ns/次,手写路径约 13ns
  (快 25 倍);非十进制写法(十六进制浮点、inf/nan、带尾部杂字符)原样交回 strtod,
  输入接受语义完全不变(实测与 strtod 的差异不超过 1 ULP)
  → 640MB 测试文件加载时间由约 40s 降到 2s 以内

交互流畅性:
- 拖拽(平移/框选/拖动信号)期间关闭波形抗锯齿并压缩顶点预算(2 像素一列包络),
  松开后立即恢复全质量绘制;实测 BIG_DATA 10 信号全显示的帧耗时由
  105~168ms 降到 75~90ms(其中折线绘制 55ms→23ms)
- 折线包络抽稀改为"列边界单调推进"的二分,避免每列在全区间二分造成缓存缺失
- 未对波形构建引入多线程:构建已由几何键缓存消除,且拖拽降级后仅约 1~2ms/帧,
  并行化收益不足以抵消线程与同步的复杂度(加载路径的多线程收益明确,故只在该处引入)

图标:
- 窗口类与 WM_SETICON 原先使用系统默认图标 IDI_APPLICATION,导致标题栏、
  任务栏与 Alt+Tab 缩略图都显示成通用应用图标;改为按 SM_CXICON/SM_CXSMICON
  从应用的 IDI_APP_ICON 资源加载(多尺寸 ICO 会挑选最接近的一帧)

其他:
- PopupMenu 新增 EDIT 项类型(菜单内联输入框)与 UpdateItemValue/UpdateItemLabel
2026-09-30 18:46:56 +08:00
DeepSeek V4.1 Flash 12b3531485 输入框鼠标编辑、图例省略、信号跨视图共享选择与网格菜单布局修复
- 输入框:支持鼠标左键点击定位插入符、拖拽框选区域,并且不再限制字符长度
- 输入框:长文本使用 ETO_CLIPPED 裁剪绘制,避免字符溢出到编辑区域之外
- 图例:信号名称超过 200px 时省略号截断,不再挤压标尺区域
- 选中状态从 TabConfig 迁移到 DataSet,切换视图后信号选中状态保持一致
- 网格右键菜单:Y 轴最大值/最小值直接显示当前值,点击后原位置弹出内联编辑框
- 标尺数值改为绘制在图例下层,不再因避让图例而隐藏
- 移除已无用的 LegendBandRect,新增共享的编辑框布局与命中检测工具
- .gitignore 忽略 TestData 测试数据目录
2026-09-30 17:10:23 +08:00
DeepSeek V4.1 Flash e3744f3eff fix: 统一输入框编辑行为、外观跨视图同步并优化标尺与网格可读性
输入框(TextEdit,全组件共用):
- 修复退格一次删除两个字符:WM_CHAR 与 WM_KEYDOWN 重复处理了退格/删除,
  现统一由 OnEditKey 处理,WM_CHAR 忽略全部控制字符。
- 进入编辑(整段选中)后按右键:取消全选并把插入符移到文本最右侧。
- 存在选区时松开 Shift 再按左右方向键,插入符收拢到选区的左/右端。
- 修复整段选中后按 Home/End 不收拢选区的问题。

标签页:
- 按加粗字体测量宽度,避免激活页长名称被提前省略(预览过短)。
- 重命名过程中按正在输入的文本测量并加宽上限(320px),标签随输入增长,
  解决长内容绘制错误;输入溢出时整体等比收缩,保证「+」始终可见。

信号显示外观跨标签页同步:
- 外观(颜色/自定义色记忆/透明度/线宽/样式)从 TabConfig 上移到 DataSet
  的 SignalData,成为信号的全局属性;可见性仍按标签页独立保存。
- 因此任一视图中修改某信号的颜色/线宽/透明度/样式,其它视图自动一致。

工具栏:
- 移除「全选信号」按钮;「清空勾选」改为「清空网格」,
  「拆分信号网格」改为「拆分网格」。

自适应:
- 无可见信号(未勾选/全部取消/清空网格)时复位 ViewInitialized,
  下次勾选第一个信号会重新自适应,而不是停留在旧视图范围。

绘图区标尺与网格:
- 幅值刻度密度按网格高度自适应(3-8 档),各网格刻度数量一致;
  网格较矮时同步收紧标签行距,提高可读密度。
- 网格线与五等分估读线加深,与网格边界(蓝灰)保持明显区分。
- 时间轴列名补上单位,显示为 time (s)。
2026-09-30 15:16:53 +08:00
DeepSeek V4.1 Flash 53768b8b25 fix: 统一输入框编辑能力、修复拖拽合并网格并支持光标吸附数据点
统一文本输入(新增 Utilities/Inc/TextEdit.hpp + TextEdit.cpp)
- 一个共享的编辑模型,提供光标/选区/过滤/限长,接入全部输入框:
  样式区数值与信号名/分组名、波形图例改名、视图标签页改名、
  拾色器 R/G/B 与色号、光标时间与网格上下限。
- 新增能力:Ctrl+A/C/X/V(含剪贴板清洗)、Shift+方向键与 Home/End 选区、
  退格与删除清除选区、代理对安全的光标步进。
- 渲染改为选区高亮 + 插入符,文本超出框宽时水平滚动并让插入符始终可见;
  初始态为整段选中,首字符键入即整体替换(保持"登录框"式交互)。
- 新增 Utf8Util::PasteTextFromClipboard(换行/制表符折叠为空格)。

修复网格合并(Utilities/Src/DataModel.cpp)
- 拖拽信号到其它网格时先固定目标网格的锚信号,再移除源信号并按引用找回目标,
  避免空网格回收导致下标错位,从"与原网格交换位置"改为真正合并。
- 自定义划分下未分配网格的可见信号改为各自独占一个新网格,
  修复"拖拽合并后再勾选新信号被并入该合并网格"的问题。

绘图区(Components/PlotView)
- 网格右键菜单新增"时间轴自适应(匹配本网格)",把时间轴对齐到该网格信号范围。
- 时间轴放大到采样点在屏幕上可分辨(>=6 逻辑像素)时,拖动光标吸附到最近数据点;
  缩小到无法分辨时保持自由移动,避免光标"跳格"。

验证:真实输入脚本逐项核对——拖拽合并后单网格含两条曲线、拖拽合并再勾选新信号得 G2 独立网格、
Shift 选区 + Delete 清除、Ctrl+A/C/V 复制粘贴、46 字符文本水平滚动、拾色器色号 1E90FF、
标签页改名 A1、光标时间框复制粘贴、全视图拖动得 0.522213(不吸附)而放大后得 0.28125(= 225 × 0.00125,已吸附)。
2026-09-30 13:40:58 +08:00
DeepSeek V4.1 Flash 4e295a2a7d fix: 修复图例改名不同步、细化网格标尺并支持标签页重排与曲线实色跟随拖拽
- 图例跟随重命名:绘图区图例文本改用信号当前显示名(Title),
  左侧列表改名后网格图例立即同步。
- 标签页重排与改名:新增拖拽排序(按住标签左右拖动并显示插入指示条,
  重排后保持原激活页)与双击内联改名,新增 MoveTab 正确处理激活下标。
  修复改名后未重新布局导致标签页整条消失的问题(SetTabs 会重置标签矩形)。
  双击判定改为自行按双击时间识别,不再依赖系统 WM_LBUTTONDBLCLK。
- 信号拖拽:虚影改用原信号颜色与线宽(不再画成虚线),保持原有线段/散点样式;
  横向与纵向均自由跟随鼠标位移;拖拽首帧位移为零,虚影始终贴合在鼠标下方。
- 网格与标尺细化:时间轴与幅值轴期望刻度数提高,并在相邻主刻度之间
  补绘 5 等分细线,便于目视估读。
- 图例定位与交互:图例移到各网格左上角,与标尺数字冲突时优先显示图例
  (标尺数值主动避让);图例条目支持单击选中信号(与左侧列表联动、
  样式区随之切换目标)与双击重命名信号。
- 网格划分:合并网格后新勾选的信号不再被并入那个唯一的合并网格,
  而是自动切换为自定义划分并独占一个新网格。
- 工具栏:「每信号一格」改名为「拆分信号网格」。
- 清理:移除已无引用的 UiDrawArrowIcon 与 m_styleContentRect。
2026-09-30 11:02:09 +08:00
DeepSeek V4.1 Flash 261b8ac07d fix: 修正滑块填充残留、数值内联输入与信号/分组重命名,拖拽虚影跟随鼠标
- 滑块最小值时不再有超出圆钮的填充残留,三处滑块统一为共享实现
- 透明度/RGB/色号支持点击或双击直接输入,整段高亮、首次键入替换、回车提交、Ctrl+C 复制
- 双击信号行或分组名进入重命名编辑;分组竖线改为绘制而非字符
- 拖拽信号时曲线虚影跟随鼠标纵向位移
- 数据层新增展示名覆盖,面板改为持有可写数据集合
2026-09-30 09:38:22 +08:00
DeepSeek V4.1 Flash cba62c8218 fix: 修正样式区对齐与线宽输入交互,分组标题改为“组X|文件名”并支持同文件重复加载
样式编辑区:
- 标签列与内容列改为靠左对齐(原为整体居中),拉宽左侧面板时不再向中间偏移。
- 颜色行不再居中,与样式、透明度、线宽三行共用同一左边界与同一宽度上限
  (260 逻辑像素),实测四行均为 89-413px,右侧留 93px 空白。

线宽输入:
- 双击数值框后数值整体居中并高亮(外框与数值呈选中态),首次键入即整体覆盖原值,
  之后显示插入符;回车确认、Esc 取消、点击其它区域确认,交互与常见登录输入框一致。

散点绘制:
- 散点半径改为随线宽线性增长(0.5-10px 映射到 1.6-12px,系数 1.5),
  修复此前半径被上限 4px 过早截断、线宽较大时数据点不再放大的问题。

透明度描边:
- 新增统一色块绘制入口 UiDrawSwatch:按不透明度填充,且仅在不透明度低于 45% 时
  补一圈描边;可见时不绘制描边。
- 预设色块、自定义色块、信号行色块与波形图例色块统一走该入口,
  修复透明度过低时完全不可见的问题。

文件分组:
- 分组标题改为“组X|<文件名>”,序号使用强调色;序号按当前位置连续编号,
  关闭某个分组后其余分组自动重新编号。
- 移除按路径查重的限制,同一文件可多次加载并分别归入不同分组。
- 关闭分组改为“移至末位后弹出 + 收缩容量”,使该文件的时间轴与全部信号缓冲区
  在本次调用内立即析构归还系统。
- 确认加载后不再依赖原始文件:读取阶段即关闭句柄并整份载入内存,
  已实测删除源文件后仍可正常勾选与绘制波形。

验证:make clean && make all(Release+Debug)零错误零警告;
逐项以真实/合成鼠标与像素扫描核对以上行为。
2026-09-29 18:40:17 +08:00
DeepSeek V4.1 Flash 729494d1ec fix: 修复网格徽标菜单与标签页编号,重构样式区并新增透明度与浮动拾色器
信号列表
- 网格徽标(G1/G2)改为在左键抬起时弹出菜单,修复此前「按住才显示、松手即消失」的问题。
- 文件分组行新增关闭按钮(✕),可直接从工作区移除文件,与右键菜单「关闭该文件」等价。
- 信号名改为完整保留文件内的列名原文,不再剥离 "[n]" 序号前缀与括号内容。

标签页
- 新建标签页改用「当前未被占用的最小编号」,关闭标签页后编号可被复用,
  修复「开 3 关 2 再新建会变成视图 4」的问题。

样式编辑区(统一为固定四行网格布局,面板缩放时不再错位)
- 移除顶部「样式 · 信号名 · 文件名」标题行,选中信号即为编辑对象。
- 绘制方式取消「阶梯」,标签由「方式」改为「样式」,仅保留线段 / 散点 / 点线。
- 线宽仅保留最细与最粗两个预设,中间改为带左右箭头的数值旋钮,单位为 px;
  支持单击或双击数值框直接键入(首次键入替换原值,回车提交、Esc 取消、越界钳制到 0.5-6.0)。
- 颜色预设后新增与预设色块完全同尺寸、同外框样式的「加号」小方格,
  点击后弹出浮动拾色面板(与 G1/G2 菜单同风格的浮动窗口),支持 RGB 三通道滑块、
  实时预览与十六进制显示;点击面板外部即收起,取色实时应用到当前信号。
- 移除样式区末尾的网格选择控件,该功能统一由信号行的 G 徽标承载。
- 新增透明度滑块,默认 100%,可在 0-100% 之间调节,并实时反映到波形、
  图例色块与信号行色块的显示效果。

其他
- 信号面板默认宽度与行内间距微调,使较长的列名可以完整显示。
- 失焦时提交线宽输入并收起浮动拾色器与弹出菜单。
2026-09-29 17:14:27 +08:00
DeepSeek V4.1 Flash eb868b2679 feat: 重构信号样式区并统一主题化弹出菜单
样式编辑区:
- 移除顶部「样式 + 信号名 + 文件名」标题行,选中信号即代表编辑目标。
- 绘制方式取消阶梯选项,仅保留线段/散点/点线,标签由「方式」改为「样式」。
- 线宽改为「最细预设 + 数值旋钮 + 最粗预设」:中间为带左右增减箭头的输入框,
  步进 0.2px,取值范围 0.5-6.0px,并标注单位为 px。
- 颜色在 10 个预设色块后新增带加号图标的方格,点击展开 RGB 三通道滑块面板,
  可实时预览并显示十六进制值;点击面板外任意位置收起。
- 移除网格归属下拉框,改由每条信号行末尾的 G 徽标承载,点击弹出网格归属菜单。

信号面板与菜单:
- 文件分组行新增关闭按钮,可直接从工作区移除该文件,与整体风格保持一致。
- 新增 PopupMenu 组件:绘制在窗口后备缓冲区内的自绘菜单,含圆角、投影、悬停高亮、
  单选对勾、色块行与分组标题,彻底替换系统默认弹出菜单;
  菜单打开期间接管鼠标与键盘(Esc / 上下键 / 回车),失焦或在菜单外释放时自动关闭。
- 信号、文件、网格、标签页四类右键菜单全部改用该组件。

其他修复:
- 信号名称不再保留尾部单位括号,避免名称后再重复显示单位。
- 数据模型移除 DrawMode::STEP 枚举。
- 标签栏与信号面板弹出菜单后补充重绘请求,修复菜单不显示的问题。
2026-09-29 16:30:48 +08:00
DeepSeek V4.1 Flash 9c6c374cce feat: 支持多视图标签页、按文件分组的多文件信号管理与网格随勾选自动收敛
数据层与视图配置解耦:新增 DataSet(多文件只读数据层)与 TabConfig(每标签页独立配置),
以 SignalRef{fileIndex,signalIndex} 标识全局信号,替换原有单文件 SignalSet。

- 标签页:新增 TabBar 组件,支持新建/切换/关闭标签页;每页独立保存信号勾选、
  颜色/线宽/显示方式、网格划分、视图范围与时间光标,互不影响。
- 网格收敛:可见性变更统一经 TabConfig 的 Set*Visible 接口并同步重算网格,
  取消勾选后对应的空网格立即回收(修复此前留下空轨道的问题)。
- 多文件分组:左侧面板改为「文件分组 + 信号」树形列表,分组可折叠、可整组勾选,
  分组复选框支持全选/部分/未选三态;新加载文件的信号默认未勾选,由用户自行选择。
- 来源标识:信号行、样式编辑区标题、波形图例与光标读数在跨文件时标注来源文件名。
- 交互补充:面板滚动条支持点击跳转与拖拽,切换标签页自动滚动到已选信号。
- 工具栏精简为「打开 CSV/适应视图/放大/缩小/合并网格/每信号一格/全选信号/清空勾选」,
  按钮宽度改为按实际文本像素测量;打开对话框支持多选文件,拖放支持批量载入。
- 新增 TestData/[2].CSV 作为跨文件对比测试数据。
2026-09-29 15:48:04 +08:00