Files
Just-DataInspector/Documents/agent_mem.md
T
DeepSeek V4.1 Flash 2322e76d8c 修复二级菜单移向途中被误关闭;新增项目记忆文档 agent_mem.md
网格右键菜单「实验性功能」展开二级菜单后,鼠标从父项移向子菜单途中经过内边距窄带会被立即收起。改为子菜单展开期间只要指针仍在主菜单∪子菜单范围内且未落到其它可点击条目即保持展开并高亮父项。
2026-10-11 02:59:41 +08:00

10 KiB
Raw Blame History

Just DataInspector — Agent 记忆与项目须知

本文件是本仓库的权威上下文备忘录,供任何接手的 AI Agent 在动手前阅读。 每次完成任务后必须同步更新本文件(补充新需求、修复记录、约定变更等)。 保持内容精确、明细、简练;多台设备协作时,可将各自的记忆合并到本文件。


1. 项目目标

  • 使用 C++17 + Win32 API(GDI/GDI+) 从零构建的桌面数据查看器,项目名 Just DataInspector。
  • 定位:替代 MATLAB/Simulink 的 Simulink.sdi.view 仿真数据检查器,用于更方便地查看带时间轴的 CSV 仿真数据。
  • 目标数据特征(参考 MathWorks 导入 CSV 的说明):CSV 中存在一个或多个时间轴列,其余列表示各时间点上的信号值。
  • 产物为 GUI 程序(非 CUI)。

2. 构建与工具链

  • 工具链:MinGW-w64(x86_64-win32-seh-rev0, MinGW-Builds 16.1.0),可直接用 make。
  • 构建入口:根目录 Makefile(C / C++ / windres 混合构建)。
  • 常用命令:
    • make release → Build/Release/Target.exe(-Os,strip:-s)。
    • make debug → Build/Debug/Target.exe(-O0 -g)。
    • make → 同时构建 Release 与 Debug。
    • make clean → 删除 Build/。
  • 关键编译设置:-std=c++17;-finput-charset=UTF-8 -fexec-charset=GBK -fwide-exec-charset=UTF-16LE;-static;-mwindows(GUI);链接 gdi32 gdiplus comdlg32 d3d11 dwmapi d3dcompiler。
  • 新增组件/工具目录后,必须在 Makefile 的 CXX_INCLUDES_PATHS 与 CXX_SOURCES_PATHS 中登记(源文件按目录通配自动收集)。
  • 构建产物统一在 Build/,已由 .gitignore 忽略;同时忽略 *.o/*.d/*.lst/*.map/*.exe 与 TestData/。

3. 目录结构与约定

Components/     功能组件块(每块 Inc/ 放 .hpp,Src/ 放 .cpp)
  Application/  应用主框架:窗口、布局、消息分发、标签页、绘制合成
  Main/         程序入口(WinMain → Application::Run)
  TabBar/       顶部多标签栏
  Toolbar/      顶部工具栏(导入文件 / 适应视图 / 时间轴自适应 / Y 轴自适应 / 选区放大 / 光标 / 合并·拆分·清空网格)
  SignalPanel/  左侧信号面板:按文件分组的信号树、可见性勾选、样式编辑
  PlotView/     波形绘图区:网格、时间轴、光标、缩放、拖拽、实验性功能面板
Utilities/      工具与辅助模块(Inc/ + Src/)
  Application/  ... (见上)
  CsvTable/     CSV 流式解析(列优先)
  DataModel/    数据层:DataSet / DataFile / SignalData / 显示配置
  PaintUtil/    GDI+ 绘制与文本/控件辅助(含 UiPointInRect、UiMeasureTextWidth 等)
  PopupMenu/    主题化自绘弹出菜单(含二级子菜单、内联编辑)
  ColorPickerPopup/ 浮动拾色器
  TextEdit/     内联文本编辑模型
  Theme/        主题色板(Solarised Light)与波形默认配色
  Utf8Util/     编码转换(UTF-8 ↔ UTF-16 等)
Resources/      图标、清单(.manifest)、版本信息(.rc)、ResourceIds.h
TestData/       本地测试 CSV(**不纳入版本控制**)
Documents/      项目文档(含本文件)
  • 命名硬性约束:源文件/头文件不得含空格,只能字母与下划线组合。
  • 头文件后缀:C 用 .h,C++ 用 .hpp;C 源 .c,C++ 源 .cpp。
  • 防重复包含:每个头文件必须 #ifndef __XXX_XX_HPP__ / #define __XXX_XX_HPP__ / ... / #endif;宏名 = 文件名的双边双下划线 + 全大写。
  • 宏定义与枚举常量必须全大写 + 下划线。
  • 所有对外函数/方法声明用 Doxygen 风格注释:@brief、@param [IN/OUT]、@return(中文说明)。
  • 代码风格统一,强调解耦与清晰的分层。

4. 架构要点

  • 数据层共享、视图配置分标签页:全局 DataSet(已加载文件、信号、时间轴)被所有标签页共享;每个标签页仅持有各自的 TabConfig(信号可见性、配色、分组、网格等),互不影响。
  • Application 是总编排者:创建窗口、Relayout 布局、HandleMessage 分发消息、合成绘制、把菜单/拾色器结果派发回组件。
  • 自定义绘制的浮动控件(PopupMenu、ColorPickerPopup)不创建独立窗口,作为宿主绘制的最上层内容直接画进后备缓冲区,保证外观与主界面统一(不出现系统默认菜单样式)。
  • 消息优先级:菜单打开 > 拾色器打开 > 常规组件交互(见 Application::HandleMessage)。
  • DPI 感知:ApplyDpi 重建字体与布局;浮动控件通过 SetScale 缩放。

数据模型(Utilities/Inc/DataModel.hpp)

  • SignalData:单条信号元数据 + 采样值。
  • DataFile:一个已加载文件及其自有时间轴(timeColumnName / time / minTime / maxTime / timeMonotonic)。
  • DataSet:文件集合与全局时间范围查询(MinTime/MaxTime、最近采样点查找等)。
  • DrawMode:LINE(插值折线) / SCATTER(散点) / LINE_SCATTER(两者)。
  • LaneMode:PER_SIGNAL / MERGED / CUSTOM(网格划分策略)。
  • PlotCursorMode:NONE / SINGLE / DOUBLE(时间光标三态)。
  • 各网格自身状态(Y 轴范围、自适应开关、实验性功能开关等)随信号继承。

CSV 解析(Utilities/Src/DataModel.cpp)

  • 列优先存储(每条信号一整块连续内存):避免百万行级按行存储的堆分配放大,并支持整列移动进 SignalData。
  • 流式分块读取,可携带真实字节进度(CsvProgressInfo),支持取消。
  • 时间列判定 LooksLikeTimeHeader:小写匹配 t / time / timestamp / simulation time,或包含 time / 时间;未命中时回退第 0 列。
  • 缺失值以 NaN 表示;要求时间列有效数值 ≥ 2,否则报错。
  • 分隔符自动探测(默认 ,)。

5. 功能需求清单(来自需求交互,持续补充)

5.1 基础功能(首轮构建目标,已实现)

  • 波形网格(多网格);时间轴。
  • 光标(单/双光标,含差值读数)。
  • 缩放与自适应(适应视图、Y 轴自适应、选区放大)。
  • 导入并加载符合要求(带时间轴列)的 CSV,解析出信号名。
  • 信号样式:修改颜色、粗细、散点/插值线段显示方式(DrawMode)。
  • 信号可绘制到同一网格或不同网格。

5.2 后续扩展(已在代码中实现,供接手参考)

  • 多标签页(新建/关闭/重命名/拖拽排序)。
  • 工具栏:合并网格 / 拆分网格 / 清空网格;时间轴自适应。
  • 信号面板:按文件分组、勾选可见性、仅显示/全部显示/隐藏全部、移除文件。
  • 绘图区拖拽:平移、选区放大(按首个明显位移方向决定横/纵轴)、网格滚动、光标拖拽、把信号曲线拖到其它网格、网格图例 GX 徽标上下重排。
  • 图例:悬停高亮、内联重命名、信号删除按钮。

5.3 「实验性功能」二级菜单(网格右键菜单内,横线上方)

包含且仅包含以下可勾选项(每网格独立状态):

  • 边沿计数
  • 边沿计数(中心轴)
  • 均值滤波
  • 弱波增强

这些功能开关会联动绘图区的浮动参数面板;部分支持「构建为新信号」。

注意:新增/改名实验性功能时,需同步 PlotView.hpp 的 PLOT_CMD_LANE_*、Application.cpp 的菜单构建与派发、PlotView/DataModel 的状态位与面板绘制。


6. UI / 交互设计语言

  • 参考 VS Code 与 WinUI 的设计语言;配色为 VS Code 的 Solarised Light 方案(Theme::SolarizedLight(),强调色 accent)。
  • 全部界面与交互用 Win32 API 自绘,不用系统默认控件样式。
  • 文本对齐、菜单内边距、圆角、阴影等在各浮动控件内保持统一风格。

7. 交付与 Git 规范

  • 工作区由本地 git 管辖。
  • 仅在功能完善(可验证)后才提交;提交信息用简洁中文描述修改内容。
  • 提交时仅对本工作区生效(git config --local),不得影响全局设置:
    • user.name = 当前模型全称。
    • user.email = <>(留空尖括号)。
  • TestData/、Build/ 等不提交(见 .gitignore)。

8. Agent 工作流要求

  1. 接手前先探索工作区/提交历史/代码建立认知(本文件应作为第一参考)。
  2. 完成需求后编译验证(make release 至少成功),必要时用 TestData/ 数据功能验证。
  3. 验证与探索时尽量不占用用户的鼠标/屏幕/键盘(后台构建为主)。
  4. 本地仓库提交完成后,不要在未经指示的情况下继续探索或优化,等待用户下一步指令。
  5. 每次完成任务后更新本文件(需求、修复、约定变更)。

9. 已知问题与修复记录

9.1 网格右键菜单「实验性功能」二级菜单瞬间关闭(已修复)

  • 症状:在网格右键菜单里把鼠标从「实验性功能」移向右侧二级菜单的途中,只要指针短暂离开父项交互区域,二级菜单立即关闭,用户来不及完成选择。旧设备 CPU 较慢、鼠标移动事件稀疏,指针可能"跳"进二级菜单而未暴露该问题;CPU 更快、事件更密集时必然复现。
  • 根因(Utilities/Src/PopupMenu.cpp 的 PopupMenu::OnMouseMove):
    • 子菜单展开后,只要指针不在子菜单矩形内且未命中任何可点击条目,就无条件 CloseSubmenu()。
    • 主菜单条目矩形的右缘为 menu.right - kPadH,而子菜单左缘为 menu.right - kSubOverlap,两者之间存在约 3px 的内边距"死区"(位于主菜单矩形内但落在任何条目之外)。鼠标事件密集时指针必然落入该窄带,从而触发误关闭。
  • 修复:子菜单展开期间,若指针仍位于「主菜单 ∪ 子菜单」矩形范围内、且尚未落到其它可点击条目上(例如掠过内边距窄带、分隔线、禁用项),则保持子菜单展开并维持父项高亮;只有明确移动到其它条目或完全离开上述范围时才收起。

10. 变更日志(本文件维护记录)

日期 设备/模型 摘要
2026-10-11 DeepSeek-V4.1-Flash 新建本文件;记录项目要点与规范;修复「实验性功能」二级菜单瞬间关闭问题。