新增主题配色(4 套)+ 信号右键菜单精简与「克隆该信号」+ 布局边界层级根治 + 单点信号吸附修复
## 为什么
用户 2026-10-29 报告/要求五件事:
1. 派生信号的「时间轴偏移保留在样式上、其它调整烘值」维持现状(确认无需改动);
2. 信号名右键菜单里很多功能已被下方样式自定义区覆盖 ⇒ 只保留「仅显示该信号」,
并在它**上方**新增「克隆该信号」;
3. 设置菜单新增「主题配色」二级菜单(带 √ 状态),顺序 Light / Solarised Light /
Dark / Solarised Dark,默认主题维持现状;
4. 布局边界:中键平移视界时浮动面板上的边界**闪烁**;光标取值胶囊的**文字**框会**穿透**
到浮动面板上;并请核对网格内固定构件(图例 / Y 轴标尺 / GX 标签 / 回到最上方 /
浮动面板)的层级关系;
5. 单数据点信号在拖动光标时的**吸附**功能消失。
## 根因
### 布局边界层级(两个都很隐蔽)
- **文本层号写死**:文本是在绘制过程中由 `UiTextRectSink` 收集的,而宿主把所有文本都记在
固定层 2;组件几何层却是"组件表下标"(`PlotView` = 0)。面板层 = PlotView 层 + 1 = 1,
**低于**文本层 2 ⇒ 面板的遮挡矩形挖不到文本 ⇒ 胶囊文字画在面板表面。
- **面板像素缓存**:面板"先画进图层、命中缓存就贴图",贴图那一帧不画字 ⇒ 文本框凭空消失
⇒ 面板上的边界闪烁。
- 顺带发现 `PlotView::BuildBoxes` 用 `PushLayer()` 却**从不复位**,会把宿主后续所有组件的
层号整体推高。
### 单点信号吸附
`MinorCellSparse` 在"把判定范围收窄到数据实际时间跨度"的分支里有
`if (!(dataMax > dataMin)) return false;`。单个有效采样点时 `dataMax == dataMin`,
于是被判定成"不稀疏" ⇒ 不吸附。
## 改了什么
### 1. 布局边界层级
- `UiTextRectSink` 新增 `OnTextLayer(int)` / `TextLayer()`;新增 `UiSetTextLayer` /
`UiGetTextLayer`;`UiBoxTable` 实现为改 `m_layer`,并暴露 `Layer()`。
- `Application::Render` 在绘制每个组件前下发 `UiSetTextLayer(ComponentLayer(&component))`,
浮层用 `OverlayLayer(1/2)`;新增 `ComponentLayer()` / `OverlayLayer()` /
`kLayersPerComponent = 3`,与 `PaintLayoutBounds` 的层号**完全同源**。
- `PaintLayoutBounds` 改为**显式** `SetLayer(下标 × 3)`(不再依赖 `PushLayer` 累加)。
- `PlotView`:`BuildBoxes` 用 `baseLayer + 1` 放浮动面板(并登记遮挡)、
`baseLayer + 2` 放绘制在面板之上的滚动条 / 回到最上方 / 输入框,结束**复位**层号;
`paintOverlays` 同步分两次抬高文本层。
- 面板像素图层新增 `PanelSlot::textRects` + 转发型收集器 `PanelTextCollector`:
渲染时存文本框,命中缓存贴图时回放 ⇒ 几何与缓存命中无关(消除闪烁)。
### 2. 信号右键菜单 + 克隆
- 菜单只剩:标题、**克隆该信号**、**仅显示该信号**;删除显示/隐藏、显示全部/隐藏全部、
预设色块行、样式三项,以及对应的 `CMD_SIGNAL_TOGGLE/SHOW_ALL/HIDE_ALL`、
`CMD_COLOR_BASE`、`CMD_MODE_BASE` 及其分支(死代码)。
- 新增 `CMD_SIGNAL_CLONE`(post `WM_APP + 5`)→ `Application::CloneSignal`:
把「调整」(系数 / 绝对值 / 镜像 / Y 偏移)烘进采样值、**时间轴偏移保留在样式上**,
名称前置 `*`,插入到源信号**正下方**,并**保留原外观**(颜色/透明度/线宽/绘制样式)。
- 抽出 `Application::InsertSignalBelowSource(...)` 供派生与克隆共用。
### 3. 主题配色
- `ThemeKind{LIGHT, SOLARIZED_LIGHT, DARK, SOLARIZED_DARK}` + `ThemeFor()` / `ThemeName()`;
Light 取 VS Code 2026 默认浅色、Dark 取 Dark+、Solarized Dark 取 VS Code solarized dark。
**默认仍是 Solarised Light**。
- 新增 `CurrentTheme()` / `SetCurrentTheme()`:宿主交出自己的 `m_theme` 地址,
切换主题只改内容;`UiControls` 里没有 `Theme` 形参的原语改用它(原来硬编码
`SolarizedLight()`,换主题不生效)。
- `Application::ApplyTheme()`:改配色 → `PlotView::OnThemeChanged()`(作废场景/宽基底/
装饰/光晕/面板图层)+ `SignalPanel::OnThemeChanged()`(作废行位图)→ 整窗重绘。
- 菜单用 `SUBMENU` + 4 个 `keepOpen` 子项;新增 `PopupMenu::UpdateSubmenuItemLabel()`
回写勾选,并让子菜单分支尊重 `keepOpen`(原为无条件关闭)。
### 4. 单点信号吸附
`MinorCellSparse` 改为只在 `dataMax < dataMin` 时放弃;相等时按"那一个小格"判定
(`need = 5 > finiteCount = 1` ⇒ 稀疏 ⇒ 吸附恢复)。
### 5. 审计
`Makefile` 的 `LAYOUT_BOUNDS` / `JDI_LAYOUT_BOUNDS` **从未被任何 `#if` 引用**
(`LAYOUT_BOUNDS=0` 产物字节数完全相同),属名实不符的死开关 ⇒ 删除并注明原因。
## 怎么验证
新增两支离屏探针(不占鼠标 / 键盘 / 屏幕):
```
.preflight/round15check 28 passed, 0 failed
单点吸附 7 条(含"远处不吸附")、面板层级 5 条、面板文本框跨帧与中键平移稳定 2 条、
克隆 14 条(烘值逐点比对 / 名称前缀 / 偏移与外观保留 / 调整复位)
.preflight/themecheck 17 passed, 0 failed
4 套主题可读性与可区分、默认 = Solarised Light、逐主题换色且无旧底色残留、
切回默认逐像素还原(diff = 0)、子菜单 4 项 / 顺序 / 唯一勾选 / 命令切换 / 菜单保持打开
```
回归全绿:
```
uicheck 69/69 lbcheck 21/21 lbresid 5/5 lbzorder 4/4
lbcovr 7/7 lbpanel 10/10 derivecheck 16/16
rendercheck: 8 个场景哈希与上一轮逐一相同 + FUNC 7/7, exit=0
A FAED59DF284153DB B E6443BFE4E3955F8 C 96A0AA8C402F1729 D E3D5DBD998E43720
E DA0583CB13C26A6F F FFB822159F604D1D G 19F8DE8FE3A8DF18 H DBBDDE4CB2C97C92
```
`make release` / `make debug` 零 error / 零 warning;产物 **791,552 B**
(单一 exe,未拆 DLL,未改 `-Oz`;离 1MB 预警线约 250 KB)。
This commit is contained in:
1 parent
71c6ff91cb
commit
71195c4c48
21 files changed
+907
-151
No files matched your search
@@ -8500,3 +8500,114 @@ rendercheck: A FAED59DF284153DB / B E6443BFE4E3955F8 / C 96A0AA8C402F1729 / D E3
|
||||
派生信号如果源自一个"带时间轴偏移"的信号,它的「调整」面板里「时间轴」会显示该偏移值
|
||||
(不再像以前那样强行"默认值")。这是**刻意**的:时间偏移无法无损地写进采样值,
|
||||
把偏移诚实显示出来比"面板是默认值但数据被裁掉/变空"要好。
|
||||
|
||||
## 2026-10-29 第十五轮(本机):主题配色 + 信号右键菜单精简/克隆 + 布局边界层级根治 + 单点吸附
|
||||
|
||||
> 用户本轮五件事:① 派生信号"时间轴偏移保留、其它调整烘值"维持现状(已确认无需改动);
|
||||
> ② 信号名右键菜单精简为「克隆该信号 / 仅显示该信号」;③ 设置菜单新增「主题配色」二级菜单(4 套);
|
||||
> ④ 修复布局边界在浮动面板上的**闪烁**与**取值胶囊文字穿透**,并审计网格内各元素的层级;
|
||||
> ⑤ 修复**单数据点信号**的光标吸附。
|
||||
|
||||
### 1. ⚠️ 布局边界层级:根因是"文本层号写死"
|
||||
|
||||
**症状**:中键平移视界时浮动面板上的边界闪烁;光标取值胶囊的**文字**框穿透到浮动面板之上。
|
||||
|
||||
**根因(两条,都很隐蔽)**
|
||||
1. 文本是在**绘制过程中**由 `UiTextRectSink` 收集的,而宿主把所有文本都记在**固定层 2**;
|
||||
组件几何层却是"组件表下标"(PlotView = 0)。于是
|
||||
* 面板层(= PlotView 层 + 1 = 1)**低于**文本层 2 ⇒ 遮挡矩形挖不到文本 ⇒ 文字画在面板表面;
|
||||
* 面板自己的文字也被算在层 2,与面板几何层不一致。
|
||||
2. 浮动面板"先画进像素图层、命中缓存就贴图":贴图那一帧**不画字** ⇒ 文本框凭空消失
|
||||
⇒ 观感就是"面板上的边界闪烁"。
|
||||
|
||||
**修法(三条)**
|
||||
1. `UiTextRectSink` 增加 `OnTextLayer(int)` / `TextLayer()`,并新增自由函数
|
||||
`UiSetTextLayer(int)` / `UiGetTextLayer()`;`UiBoxTable` 实现为改 `m_layer`。
|
||||
宿主 `Render` 在绘制每个组件前 `UiSetTextLayer(ComponentLayer(&component))`,
|
||||
浮层用 `OverlayLayer(1/2)` —— **与 `PaintLayoutBounds` 分配几何层号完全同源**。
|
||||
2. `PlotView::BuildBoxes` / `paintOverlays` 里把层号继续细分(见下"层号约定")。
|
||||
顺手修掉一个真缺陷:`BuildBoxes` 原来用 `PushLayer()` 却**从不复位**,
|
||||
会把宿主后面所有组件的层号整体推高。
|
||||
3. 面板像素图层新增 `PanelSlot::textRects`:渲染面板时用**转发型收集器**
|
||||
(`PanelTextCollector`,一边转发给外层、一边存一份)把文本框存进 slot,
|
||||
命中缓存贴图时**回放**给外层收集器 ⇒ 几何与是否命中缓存无关。
|
||||
|
||||
**层号约定(现行,务必按此)**
|
||||
```
|
||||
layer = 组件表下标 × 3 + { 0 = 基层, 1 = 组件内部不透明浮层, 2 = 浮层之上的叠加层 }
|
||||
PlotView:0 = 网格/图例/Y轴标尺/GX/时间轴/光标读数与取值胶囊
|
||||
1 = 实验性功能浮动面板(同时登记为 occluder)
|
||||
2 = 滚动条 / 「回到最上方」/ 内联输入框(绘制在面板之上)
|
||||
浮层:OverlayLayer(0)=分隔条、1=菜单、2=拾色器
|
||||
```
|
||||
|
||||
### 2. 单数据点信号吸附失效(回归)
|
||||
|
||||
`MinorCellSparse` 在原"把判定范围收窄到数据实际时间跨度"的分支里有
|
||||
`if (!(dataMax > dataMin)) return false;` —— **只有一个有效采样点时 `dataMax == dataMin`**,
|
||||
于是被判定成"不稀疏"⇒ 不吸附。
|
||||
改为只在 `dataMax < dataMin` 时放弃;相等时继续走"那一个小格"的路径:
|
||||
`firstCell == lastCell`、`need = 5`,而 `finiteCount == 1 < 5` ⇒ 判为稀疏 ⇒ 吸附恢复
|
||||
(并且 `LocalSampleSpacing` 对 `finiteCount <= 1` 返回 0 = 不额外收窄半径,行为自洽)。
|
||||
|
||||
### 3. 信号右键菜单精简 + 「克隆该信号」
|
||||
|
||||
* 菜单只剩:标题(信号名)、**克隆该信号**、**仅显示该信号**(用户 2026-10-29 要求)。
|
||||
删掉的条目:显示/隐藏该信号、显示全部、隐藏全部、预设色块行、样式(线段/散点/点线)
|
||||
—— 它们都已被下方**样式自定义区**与**分组右键菜单**覆盖。
|
||||
同时删除 `CMD_SIGNAL_TOGGLE/SHOW_ALL/HIDE_ALL`、`CMD_COLOR_BASE`、`CMD_MODE_BASE`
|
||||
及它们的分支(死代码)。
|
||||
* 新增 `CMD_SIGNAL_CLONE`(post `WM_APP + 5`,注意 `WM_APP+3` 已被
|
||||
`kMessagePlotDerivedReady`、`+4` 已被 `kMessagePlotLowMemory` 占用)→
|
||||
`Application::CloneSignal(ref)`:把「调整」(系数/绝对值/镜像/Y 偏移)烘进采样值、
|
||||
**时间轴偏移保留在样式上**,名称前置 `*`,插入到源信号**正下方**。
|
||||
克隆**保留原外观**(颜色/透明度/线宽/绘制样式),与"构建为新信号"(外观走调色板)不同。
|
||||
* 抽出 `Application::InsertSignalBelowSource(...)`:插入 → 各标签页下标重映射 →
|
||||
勾选 + 把新网格挪到源网格下方(**不做** `SyncTabsToDataSet`,让调用方先改外观)。
|
||||
|
||||
### 4. 主题配色(设置菜单 → 主题配色 → 二级菜单,带 √)
|
||||
|
||||
* `ThemeKind{LIGHT, SOLARIZED_LIGHT, DARK, SOLARIZED_DARK}`(顺序即菜单顺序);
|
||||
`ThemeFor(kind)` / `ThemeName(kind)`。**默认仍是 Solarised Light**(用户要求默认不变)。
|
||||
* 新增 `CurrentTheme()` / `SetCurrentTheme(const Theme*)`:宿主把自己的 `m_theme` 实例地址
|
||||
交给全局指针 ⇒ 切换主题只改 `m_theme` 内容,所有持有 `const Theme*` 的组件自动跟随;
|
||||
`UiControls` 里那些**没有 Theme 形参**的原语(`UiDrawCheckBox` / 色块描边等)改用
|
||||
`CurrentTheme()`(原来硬编码 `SolarizedLight()`,换主题不生效)。
|
||||
* `Application::ApplyTheme(kind)`:改 `m_theme` → `m_plot.OnThemeChanged()` +
|
||||
`m_panel.OnThemeChanged()`(作废场景/宽基底/装饰/光晕/面板图层与行位图缓存)→ 整窗重绘。
|
||||
⚠️ 只作废场景缓存是不够的:**宽基底图层、装饰层、面板层、信号列表行位图**里都烘着主题色。
|
||||
* 菜单:`MenuItemKind::SUBMENU` + 4 个 `NORMAL` 子项(`keepOpen = true`);
|
||||
选中后宿主用**新接口 `PopupMenu::UpdateSubmenuItemLabel()`** 回写勾选(子菜单是
|
||||
`parent.submenu` 的快照,只改 `m_items` 不重建布局不会生效)。
|
||||
同时让 `PopupMenu::OnLButtonUp` 的子菜单分支尊重 `item.keepOpen`
|
||||
(原来无条件 `Close()`)⇒ 可以连续预览几种配色,勾选会实时挪动。
|
||||
|
||||
### 5. 审计:删掉名实不符的 `LAYOUT_BOUNDS` 开关
|
||||
|
||||
`Makefile` 里 `LAYOUT_BOUNDS` / `JDI_LAYOUT_BOUNDS` **从未被任何 `#if` 引用**,
|
||||
是个只声明不生效的死开关(`LAYOUT_BOUNDS=0` 产物字节数完全相同)。
|
||||
已删除并在 Makefile 注明原因:「显示布局边界」现在是**正式功能**,
|
||||
真要可剔除需要给每个组件的 `BuildBoxes` 重载都加 `#if`,代价远大于十几 KB。
|
||||
|
||||
### 6. 验证
|
||||
|
||||
新增两支离屏探针(不占鼠标/键盘/屏幕):
|
||||
|
||||
```
|
||||
.preflight/round15check 28/28
|
||||
单点吸附 7 条(含"远处不吸附")、面板层级 5 条、面板文本框跨帧/平移稳定 2 条、克隆 14 条
|
||||
.preflight/themecheck 17/17
|
||||
4 套主题可读性/可区分、默认= Solarised Light、逐主题换色且无旧底色残留、
|
||||
切回默认逐像素还原(diff=0)、子菜单 4 项/顺序/唯一勾选/命令切换/菜单保持打开
|
||||
```
|
||||
|
||||
回归全绿:`uicheck` 69、`lbcheck` 21、`lbresid` 5、`lbzorder` 4、`lbcovr` 7、`lbpanel` 10、
|
||||
`derivecheck` 16;`rendercheck` 8 场景哈希**与上一轮逐一相同** + FUNC 7/7;release/debug 零 warning;
|
||||
产物 **791,552 B**(单一 exe,未拆 DLL,未改 `-Oz`,离 1MB 预警线约 250 KB)。
|
||||
|
||||
### 7. 探针坑(新增)
|
||||
|
||||
* 验证"取值胶囊穿透"必须挑一个**该时刻真的有采样**的网格(单数据点信号的网格上没有胶囊);
|
||||
并把面板位置改到胶囊上方(`lane.freeMarkerPanel.x/y`)。
|
||||
* `lbpanel` 的 "layer 1 只能是面板内容" 断言会随层号约定变化而失效:现在滚动条/回到最上方
|
||||
在 `base + 2`,因此各组件必须按 `kLayersPerComponent = 3` 取层。
|
||||
Reference in new issue
Block a user