修复列表内联编辑(组名/信号名)看不到插入符与选区;把 UI 基础层迁入 Components/Shared
1) 行位图缓存键漏了插入符与选区:信号列表整行走 PaintRowCached,RowCacheKey
在编辑态只混合“是否编辑 + 文本” ⇒ 左右方向键与鼠标框选虽然改变了 TextEdit
状态(caret/anchor),键却不变 ⇒ 贴回旧位图。表现就是“无法部分选择、
鼠标框选无反应、光标不动”,而绘图区的光标时间输入(无行缓存)一直正常。
修法:GROUP_TITLE / SIGNAL_NAME 两个分支编辑态把 Caret / SelectionBegin /
SelectionEnd 一并 mix 进键;新增 SignalPanel::EditFieldFont() 统一
绘制(uiSmall / ui)与鼠标命中、插入符换算所用字体。
2) Theme / PaintUtil / TextEdit / PopupMenu / ColorPickerPopup 由
Utilities/{Inc,Src} git mv 到 Components/Shared/{Inc,Src}:
Utilities 只保留纯数据/逻辑模块(DataModel、DataTable、各 *Loader、MatH5、
Utf8Util),Shared 成为自洽的 UI 基础层(Theme → PaintUtil → UiControls →
PopupMenu / ColorPickerPopup)。依赖方向仍是 Components → Shared → Utilities;
PaintUtil 一并迁移是因为它依赖 Theme(否则构成 Utilities → Shared 反向依赖)。
Makefile 无需改动(include 平铺,两个目录都已在搜索路径),但需清理 Build/*
里对应的旧 .o/.d。
验证(全部离屏,不占用鼠标/键盘/屏幕):
- 新增 .preflight/editcheck 20/20;A/B 修复前 6 项如实失败(键不变 + 屏幕不重绘);
- 既有 .preflight/check 137/137;
- make release / make debug 零警告。
This commit is contained in:
1 parent
f44f8021e3
commit
1e50494c41
15 files changed
+93
-4
No files matched your search
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1077,6 +1077,14 @@ namespace jdi
|
|||||||
*/
|
*/
|
||||||
gd::RectF EditFieldRect();
|
gd::RectF EditFieldRect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 当前输入框绘制与命中/插入符换算所使用的字体。
|
||||||
|
* @return 字体句柄(分组名用 `uiSmall`,其余用 `ui`)。
|
||||||
|
* @note ⚠️ 绘制(`PaintGroupRow` / `PaintSignalRow`)与鼠标定位(`UiEditOffsetAt`)
|
||||||
|
* **必须使用同一个字体**,否则点哪儿插入符就落到哪儿这个不变量会被破坏。
|
||||||
|
*/
|
||||||
|
HFONT EditFieldFont() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 计算「筛选信号」输入框的内容矩形(编辑与显示共用,保证不跳动)。
|
* @brief 计算「筛选信号」输入框的内容矩形(编辑与显示共用,保证不跳动)。
|
||||||
* @return 内容矩形。
|
* @return 内容矩形。
|
||||||
|
|||||||
@@ -1186,6 +1186,17 @@ namespace jdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HFONT SignalPanel::EditFieldFont() const
|
||||||
|
{
|
||||||
|
if (m_fonts == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// 分组名的编辑框在行内是用 `uiSmall` 绘制的(分组行字号更小),其余输入框用 `ui`。
|
||||||
|
// 绘制、命中、插入符换算三处必须一致,否则鼠标落点与插入符位置会错开。
|
||||||
|
return (m_editField == StyleEditField::GROUP_TITLE) ? m_fonts->uiSmall : m_fonts->ui;
|
||||||
|
}
|
||||||
|
|
||||||
const SignalStyle* SignalPanel::StyleOf(const SignalRef& ref) const
|
const SignalStyle* SignalPanel::StyleOf(const SignalRef& ref) const
|
||||||
{
|
{
|
||||||
return (m_dataSet != nullptr) ? m_dataSet->Style(ref) : nullptr;
|
return (m_dataSet != nullptr) ? m_dataSet->Style(ref) : nullptr;
|
||||||
|
|||||||
@@ -821,7 +821,7 @@ namespace jdi
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return UiEditFieldMouseDown(m_fonts->ui, EditFieldRect(), m_edit, m_scale, x, y);
|
return UiEditFieldMouseDown(EditFieldFont(), EditFieldRect(), m_edit, m_scale, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignalPanel::OnEditMouseMove(int x)
|
bool SignalPanel::OnEditMouseMove(int x)
|
||||||
@@ -834,7 +834,7 @@ namespace jdi
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return UiEditFieldMouseMove(m_fonts->ui, EditFieldRect(), m_edit, m_scale, x);
|
return UiEditFieldMouseMove(EditFieldFont(), EditFieldRect(), m_edit, m_scale, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignalPanel::OnEditMouseUp(int x, int y)
|
bool SignalPanel::OnEditMouseUp(int x, int y)
|
||||||
|
|||||||
@@ -326,6 +326,13 @@ namespace jdi
|
|||||||
if (editing)
|
if (editing)
|
||||||
{
|
{
|
||||||
mixText(m_edit.Text());
|
mixText(m_edit.Text());
|
||||||
|
// ⚠️ 插入符与选区必须进键:行位图缓存只按“行的可见内容”生效,
|
||||||
|
// 而编辑态下插入符位置 / 选区范围也是可见内容。漏掉它们时,
|
||||||
|
// 方向键与鼠标框选虽然改变了 `TextEdit` 状态,但键不变 ⇒ 贴回的仍是旧位图,
|
||||||
|
// 屏幕上看就是“无法部分选择、光标不动”(用户 2026-10-19 报告)。
|
||||||
|
mix(static_cast<std::uint64_t>(m_edit.Caret()) + 1ull);
|
||||||
|
mix(static_cast<std::uint64_t>(m_edit.SelectionBegin()) + 1ull);
|
||||||
|
mix(static_cast<std::uint64_t>(m_edit.SelectionEnd()) + 1ull);
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@@ -350,6 +357,10 @@ namespace jdi
|
|||||||
if (editing)
|
if (editing)
|
||||||
{
|
{
|
||||||
mixText(m_edit.Text());
|
mixText(m_edit.Text());
|
||||||
|
// 同分组行:插入符 / 选区也是行的可见内容(见 `GROUP_TITLE` 分支的注释)。
|
||||||
|
mix(static_cast<std::uint64_t>(m_edit.Caret()) + 1ull);
|
||||||
|
mix(static_cast<std::uint64_t>(m_edit.SelectionBegin()) + 1ull);
|
||||||
|
mix(static_cast<std::uint64_t>(m_edit.SelectionEnd()) + 1ull);
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-2
@@ -2995,6 +2995,8 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
|||||||
|
|
||||||
| 2026-10-17 | DeepSeek-V4.1-Flash(**本机**) | **多层加载拖拽卡顿根治 + 高亮命中线段中段 / 散点高亮 + 选区放大也高亮 + 自动点线判定与规则修正(详见 §9.45)**。① **拖拽卡顿(39.2→8.2ms 均值、47.9→10.3ms 最坏)**:**(a)** `RenderLaneLayerRegion` 每次补条都调两次 `BuildLaneVisuals()`(O(网格数))⇒ 253 网格时 `RollWideBuffer` 单帧 **26.8ms**;改为快照/拷回 `m_lanes`;**(b)** 横向“重新居中”纯属优化 ⇒ `kLayerRollQuantumX=32` + `kLayerRollsPerFrame=3`;**(c)** 位移过大时旧实现**同步整块重画**(巨型信号 20~130ms)⇒ `kLayerRollMaxShiftPixels=160` 作废图层交给底衬;`RollWideBuffer` 跳过离屏网格;**(d)** 包络带路径也支持补条裁剪(巨型信号一条 32px 竖带 5ms → 亚毫秒)。② **高亮命中**:`HitTestSignal` 横向窗口少算一个顶点 ⇒ 放大后两点**中间的连线**完全点不中(0/11 → 11/11);散点模式新增“数据点高亮环”(不含连线),列表/图例联动同源。③ **选区放大**恢复悬停高亮(仍不可拖信号),提示只显示信号名。④ **自动点线误判**:判定范围未限制在信号有数据的时段 ⇒ 长跨度文件 + 短信号时 MF4 信号默认视图全部误判(248→0);并改为**只对 `DrawMode::LINE` 生效**(SCATTER 不切换、用户手动改过不切换)。验证:新增 `.preflight/perf/hoverdrag_main.cpp` **20/20**;`verify` 49/49、`panelanim` 158/158、`datacheck` 69/69、`edgecheck` 46/46、`errcheck` 19/19、`gridanim` 93/93、`lanescroll` 23/23;`make release`/`make debug` 零警告。⚠️ 探针的绝对毫秒阈值改为**相对基准**(同一基线代码在不同时段可差 2~3 倍)。§11.2 新增第 141–150 条。 |
|
| 2026-10-17 | DeepSeek-V4.1-Flash(**本机**) | **多层加载拖拽卡顿根治 + 高亮命中线段中段 / 散点高亮 + 选区放大也高亮 + 自动点线判定与规则修正(详见 §9.45)**。① **拖拽卡顿(39.2→8.2ms 均值、47.9→10.3ms 最坏)**:**(a)** `RenderLaneLayerRegion` 每次补条都调两次 `BuildLaneVisuals()`(O(网格数))⇒ 253 网格时 `RollWideBuffer` 单帧 **26.8ms**;改为快照/拷回 `m_lanes`;**(b)** 横向“重新居中”纯属优化 ⇒ `kLayerRollQuantumX=32` + `kLayerRollsPerFrame=3`;**(c)** 位移过大时旧实现**同步整块重画**(巨型信号 20~130ms)⇒ `kLayerRollMaxShiftPixels=160` 作废图层交给底衬;`RollWideBuffer` 跳过离屏网格;**(d)** 包络带路径也支持补条裁剪(巨型信号一条 32px 竖带 5ms → 亚毫秒)。② **高亮命中**:`HitTestSignal` 横向窗口少算一个顶点 ⇒ 放大后两点**中间的连线**完全点不中(0/11 → 11/11);散点模式新增“数据点高亮环”(不含连线),列表/图例联动同源。③ **选区放大**恢复悬停高亮(仍不可拖信号),提示只显示信号名。④ **自动点线误判**:判定范围未限制在信号有数据的时段 ⇒ 长跨度文件 + 短信号时 MF4 信号默认视图全部误判(248→0);并改为**只对 `DrawMode::LINE` 生效**(SCATTER 不切换、用户手动改过不切换)。验证:新增 `.preflight/perf/hoverdrag_main.cpp` **20/20**;`verify` 49/49、`panelanim` 158/158、`datacheck` 69/69、`edgecheck` 46/46、`errcheck` 19/19、`gridanim` 93/93、`lanescroll` 23/23;`make release`/`make debug` 零警告。⚠️ 探针的绝对毫秒阈值改为**相对基准**(同一基线代码在不同时段可差 2~3 倍)。§11.2 新增第 141–150 条。 |
|
||||||
|
|
||||||
|
| 2026-10-19 | DeepSeek-V4.1-Flash(**本机**) | **修复列表内联编辑(组名/信号名)看不到插入符与选区 + `Utilities` 的 UI 基础层迁入 `Components/Shared`(详见 §12 末尾「2026-10-19 第二轮」)**。① **根因**:信号列表整行走**行位图缓存**(`SignalPanel::PaintRowCached`),而 `RowCacheKey` 只混合“是否编辑 + 编辑文本”,**没有插入符与选区** ⇒ 左右方向键、鼠标框选虽然改变了 `TextEdit` 状态,键却不变 ⇒ 贴回旧位图 ⇒ 用户看到“无法部分选择、光标不动”(绘图区光标时间输入没有行缓存,所以一直正常)。修法:编辑态把 `Caret/SelectionBegin/SelectionEnd` 混进键(分组行与信号行两处),并新增 `SignalPanel::EditFieldFont()`(分组名用 `uiSmall`、其余 `ui`)统一**绘制 / 命中 / 插入符换算**三处字体。② **目录归类**:`Theme.*` / `PaintUtil.*` / `TextEdit.*` / `PopupMenu.*` / `ColorPickerPopup.*` 由 `Utilities/{Inc,Src}` **`git mv`** 到 `Components/Shared/{Inc,Src}`(`Utilities` 只剩纯数据/逻辑;依赖方向仍 `Components → Shared → Utilities`);Makefile 无需改动,但要清掉 `Build/*` 里对应的旧 `.o/.d`。验证:新增离屏 `.preflight/editcheck`(`SW_HIDE` + 合成消息 + `BELOW_NORMAL`)**20/20**(A/B:修复前 6 项如实失败:键不变、屏幕不重绘);`make release`/`make debug` 零警告。 |
|
||||||
|
|
||||||
## 11. 跨设备协作须知(起源设备视角)
|
## 11. 跨设备协作须知(起源设备视角)
|
||||||
|
|
||||||
> **本文件是唯一权威记忆**。所有设备 / Agent 共用它,**不要再新建 `agent_mem_origin.md` 等旁支记忆文件**。
|
> **本文件是唯一权威记忆**。所有设备 / Agent 共用它,**不要再新建 `agent_mem_origin.md` 等旁支记忆文件**。
|
||||||
@@ -3360,8 +3362,18 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
|||||||
(名称不再有“回退值”)。
|
(名称不再有“回退值”)。
|
||||||
88. ⚠️ **通用 UI 控件属于 `Components/Shared`**(用户 2026-10-16 要求建此组件):
|
88. ⚠️ **通用 UI 控件属于 `Components/Shared`**(用户 2026-10-16 要求建此组件):
|
||||||
图标 / 复选框 / 滑块 / 内联输入框 / 颜色样块 / 取值胶囊配色都在
|
图标 / 复选框 / 滑块 / 内联输入框 / 颜色样块 / 取值胶囊配色都在
|
||||||
`Components/Shared/Inc/UiControls.hpp`;`Utilities/PaintUtil.*` **只保留低层绘制原语**。
|
`Components/Shared/Inc/UiControls.hpp`。
|
||||||
依赖方向固定 `Components/* → Components/Shared → Utilities`,**不得反向**。
|
⚠️ **【2026-10-19 更新:UI 基础层整体迁入 `Shared`】**用户指出 `Utilities` 里那些“会绘制/承载
|
||||||
|
UI”的模块不属于纯粹工具范畴,现全部位于 **`Components/Shared/{Inc,Src}`**:
|
||||||
|
`Theme.*`(调色板与 `ToGdiColor/MakeArgb/WithAlpha/MixColor`)、`PaintUtil.*`(低层绘制原语)、
|
||||||
|
`TextEdit.*`(内联编辑模型)、`PopupMenu.*`、`ColorPickerPopup.*`。
|
||||||
|
⇒ **`Utilities/` 只剩纯数据/逻辑模块**(`DataModel`、`DataTable`、`CsvLoader`、`DataLoader`、
|
||||||
|
`Mf4Loader`、`MatH5`、`MatLoader`、`Utf8Util`),**不得**再往 `Utilities` 放任何包含
|
||||||
|
`gdiplus.h` 的绘制/控件代码。
|
||||||
|
依赖方向仍是单向:**`Components/* → Components/Shared → Utilities`**(`Shared` 可以消费
|
||||||
|
`Utilities` 的 `Utf8Util` 等,反向禁止)。搬移时**只需 `git mv`**:`#include "X.hpp"` 是平铺写法,
|
||||||
|
两个目录都在 `CXX_INCLUDES_PATHS` 里,**Makefile 无需改动**(但要清掉 `Build/*` 里那几个
|
||||||
|
`Theme.o/PaintUtil.o/TextEdit.o/PopupMenu.o/ColorPickerPopup.o` 及其 `.d`,否则旧依赖文件指向旧路径)。
|
||||||
新增组件目录要同时登记 `Makefile`(`CXX_INCLUDES_PATHS` / `CXX_SOURCES_PATHS`)与
|
新增组件目录要同时登记 `Makefile`(`CXX_INCLUDES_PATHS` / `CXX_SOURCES_PATHS`)与
|
||||||
`.preflight/perf/build.ps1`。
|
`.preflight/perf/build.ps1`。
|
||||||
89. ⚠️⚠️ **新增标识符前必须确认不是 Windows 头里的宏**:`windows.h` 会引入 `nb30.h` 的
|
89. ⚠️⚠️ **新增标识符前必须确认不是 Windows 头里的宏**:`windows.h` 会引入 `nb30.h` 的
|
||||||
@@ -6356,3 +6368,50 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
|||||||
用探针从**真实产物** `LoadImageW` 逐尺寸校验,而不是只看文件能编译。
|
用探针从**真实产物** `LoadImageW` 逐尺寸校验,而不是只看文件能编译。
|
||||||
5. **任何"长时间解析"都要按阶段回报进度**(读字节 + 每个解码单元),
|
5. **任何"长时间解析"都要按阶段回报进度**(读字节 + 每个解码单元),
|
||||||
且 `hasBytes` 只在真正有字节可报的阶段置真,否则遮罩层会停在 0%。
|
且 `hasBytes` 只在真正有字节可报的阶段置真,否则遮罩层会停在 0%。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 本轮(2026-10-19 第二轮,本机):列表内联编辑看不到插入符/选区 + UI 基础层迁入 `Components/Shared`
|
||||||
|
|
||||||
|
> 用户报告两件事:① 信号列表里**组名**双击进入编辑后与其它输入框状态不一致 ——
|
||||||
|
> 无法部分选择、鼠标框选无反应、左右方向键也不移动插入符;② `Utilities/{Inc,Src}` 里的
|
||||||
|
> `ColorPickerPopup` / `PopupMenu` / `TextEdit` / `Theme` 等其实是会绘制的 UI 组件,应归到
|
||||||
|
> `Components/Shared`。
|
||||||
|
> 验证:新增离屏 `.preflight/editcheck`(`SW_HIDE` + 合成消息 + `BELOW_NORMAL`)**20/20**;
|
||||||
|
> **A/B:修复前 6 项如实失败**(键不变 + 屏幕不重绘)。`make release` / `make debug` 零警告。
|
||||||
|
|
||||||
|
### A. ① 的根因:行位图缓存的键漏了「插入符与选区」
|
||||||
|
|
||||||
|
- 信号列表为了流畅性把**整行**渲染进离屏 DIB 缓存(`SignalPanel::PaintRowCached`,`24f0bf8` 引入),
|
||||||
|
命中时一次 `BitBlt`。但 `RowCacheKey()` 在编辑态只混合了 **`editing` 标志 + `m_edit.Text()`**。
|
||||||
|
- 于是 **方向键 / 鼠标框选只改变 `TextEdit` 的 `caret / anchor`,文本没变 ⇒ 键没变 ⇒ 贴回旧位图**
|
||||||
|
⇒ 屏幕上插入符与选区完全不动(**输入字符**时才刷新,所以只表现为“不能部分选择/光标不动”)。
|
||||||
|
绘图区的光标时间输入没有行缓存,所以一直正常 —— 这正是用户说的“状态不一致”。
|
||||||
|
⚠️ 信号名编辑走同一套行缓存,同样有此缺陷(只是用户先注意到组名)。
|
||||||
|
- ✓ 修法:两个分支(`GROUP_TITLE` / `SIGNAL_NAME`)在编辑态把
|
||||||
|
`Caret()` / `SelectionBegin()` / `SelectionEnd()` 一并 mix 进键。
|
||||||
|
- ✓ 顺带统一字体:新增 `SignalPanel::EditFieldFont()`(分组名 = `uiSmall`,其余 = `ui`),
|
||||||
|
供 `OnEditMouseDown` / `OnEditMouseMove` 的 `UiEditOffsetAt` 使用 ——
|
||||||
|
绘制(`PaintGroupRow` 用 `uiSmall`、`PaintSignalRow` 用 `ui`)与**插入符换算必须同字体**,
|
||||||
|
否则“点哪儿插入符落在哪儿”这个不变量会被破坏。
|
||||||
|
|
||||||
|
### B. ② 的落地:`Utilities` 只保留纯数据/逻辑
|
||||||
|
|
||||||
|
| 旧位置 | 新位置 |
|
||||||
|
| --- | --- |
|
||||||
|
| `Utilities/Inc/Theme.hpp` + `Utilities/Src/Theme.cpp` | `Components/Shared/{Inc,Src}/Theme.*` |
|
||||||
|
| `Utilities/Inc/PaintUtil.hpp` + `Utilities/Src/PaintUtil.cpp` | `Components/Shared/{Inc,Src}/PaintUtil.*` |
|
||||||
|
| `Utilities/Inc/TextEdit.hpp` + `Utilities/Src/TextEdit.cpp` | `Components/Shared/{Inc,Src}/TextEdit.*` |
|
||||||
|
| `Utilities/Inc/PopupMenu.hpp` + `Utilities/Src/PopupMenu.cpp` | `Components/Shared/{Inc,Src}/PopupMenu.*` |
|
||||||
|
| `Utilities/Inc/ColorPickerPopup.hpp` + `Utilities/Src/ColorPickerPopup.cpp` | `Components/Shared/{Inc,Src}/ColorPickerPopup.*` |
|
||||||
|
|
||||||
|
- **为什么连 `PaintUtil` 一起搬**:`PaintUtil.hpp` 依赖 `Theme.hpp`(`ToGdiColor` 等)。
|
||||||
|
若只搬 `Theme`/`TextEdit`,`Utilities` 反而要包含 `Shared` 的头文件 ⇒ **反向依赖**,
|
||||||
|
违反第 88 条的单向分层。搬完之后 `Shared` 是自洽的“UI 基础层”:
|
||||||
|
`Theme`(设计令牌/颜色)→ `PaintUtil`(低层原语)→ `UiControls`(控件)→ `PopupMenu`/`ColorPickerPopup`。
|
||||||
|
- 依赖方向不变:**`Components/* → Components/Shared → Utilities`**;`Utilities` 现在只剩
|
||||||
|
`DataModel` / `DataTable` / 各 `*Loader` / `MatH5` / `Utf8Util`,**不得**再放 `gdiplus.h` 系代码。
|
||||||
|
- 搬移手法:`git mv`(保留历史)+ **Makefile 无需改动**(`#include "X.hpp"` 平铺,两个目录都已在
|
||||||
|
`CXX_INCLUDES_PATHS/CXX_SOURCES_PATHS`)。⚠️ 必须删掉 `Build/Release|Debug` 里对应的
|
||||||
|
旧 `*.o` / `*.d`(`.d` 里记着旧路径,会让 make 误判/漏依赖)。
|
||||||
|
- 文档里 §11.2 第 88 条已按本表更新(历史章节里出现的 `Utilities/PaintUtil.*` 等仅作历史记录)。
|
||||||
Reference in new issue
Block a user