## 一、UI 交互修复(用户报告) ① 分组折起热区(用户要求):点分组**名称**不再折起,只有**折叠三角**或**「组X」标签** 才折起。RowPart 新增 GROUP_TITLE;RowHitPart() 为分组行判出三角 / 复选框 / 关闭 ✕ / 「组X」标签矩形 / 其余 BODY;OnLButtonDown 只在这两个热区调用 ToggleGroupFromRow()。 附带:双击「组X」不再进入改名(该区域现为折起热区),双击分组名仍可改名。 ② 分组改名输入框不再吞掉「N 项」:RowNameRect() 对分组行的右边界改为「项数左边缘 − 6*scale」; 新增 GroupLabelText()/GroupStatsText() 作为文本与宽度的唯一来源(PaintGroupRow 与 RowNameRect 共用),避免名称可用宽度与实际绘制文本漂移。 ## 二、数据模型去冗余(用户指出的重点) - SignalData / SignalGroup **只保留一个名称字段** name:删除 displayName、删除 Title() (31 处调用点改为直接用 name);DataSet::SetSignalDisplayName / SetGroupDisplayName → RenameSignal / RenameGroup,且**空串 / 纯空白一律拒绝**(名称不再有回退值)。 依据:信号靠 SignalRef 下标定位、从不按名字匹配 ⇒ 两个字段是同一语义的两份副本。 收益:每条信号 / 每个分组少一个 std::wstring(24B + 堆分配)与一条 Title() 分支。 - 删除 Application::m_loadingBytes(全仓既不读也不写的死成员,注释却称“用于展示体积”)。 ## 三、新增 Components/Shared 组件(通用 UI 控件) - 从 Utilities/PaintUtil.* 迁出全部「控件类」绘制/命中:图标(+ / ✕ / 三角)、复选框、 滑块(UiSliderRatioFromX / UiDrawSlider)、内联输入框(UiDrawEditField / UiDrawEditFieldContent / UiEditTextLeft / UiEditOffsetAt / UiEditFieldMouseDown / UiEditFieldMouseMove)、颜色样块(UiDrawSwatch / UiSwatchNeedsOutline)、 取值胶囊配色(UiInk / UiColorLuminance / UiContrastInk)。 - PaintUtil.* 只保留低层绘制原语(矩形 / 圆角 / 直线 / 批量实线 / 颜色混合 / 文本与测量)。 - 依赖方向固定:Components/* → Components/Shared → Utilities(不得反向,Utilities 不再含控件)。 - Makefile 与 .preflight/perf/build.ps1 已登记新目录;调用方改 include "UiControls.hpp"。 ## 四、过时注释 / 命名批量修正(承接上一轮未做完的部分) - 注释:文件下标→分组下标、文件内信号下标→组内信号下标、所属文件下标→所属分组下标; 措辞统一 文件分组→分组、移除该文件→移除该分组、打开 CSV 文件→打开数据文件 等一批。 - 文不对题的形参名:VisibleIndexRange(const TimeAxis& file,…) → axis; Application::LoadFileAsync(…, SignalGroup& file,…) → group。 - 函数名里的 File 语义(上一轮只改了 RowKind::FILE):PaintFileRow→PaintGroupRow、 FileCloseRect→GroupCloseRect、OpenFileMenu→OpenGroupMenu、FileGroupLabelWidth→GroupLabelWidth、 StyleEditField::FILE_NAME→GROUP_TITLE;局部变量 fileRow/fileHeight/isFile → groupRow/groupHeight/isGroup。 - 修复 DataModel.hpp 两处被压扁的注释块(/**<TAB><TAB>* @brief …)与 Application::NewTab 上方重复的文档块。 - ⚠️ 踩坑:GROUP_NAME 撞上 nb30.h(windows.h 引入)的 #define GROUP_NAME 0x80, 导致枚举编译失败,改名 GROUP_TITLE 解决。 ## 五、二进制瘦身:1 013 248 → 754 176 B(−25.6%,省 259 KB) - 真因不是 PlotView.cpp,而是 Resources/JustDataInspector.ico 里 **256×256@32bpp 以未压缩 BMP 存储的条目(270 376 B,占整包 27%)**。改为 PNG 存储(Vista+ 标准做法,观感零变化) ⇒ 该条目 270 376 → 11 280 B、整个 ico 302 430 → 43 334 B(小尺寸仍保留 BMP)。 - 实测结论:“拆分大文件 ⇒ 瘦身”不成立(同一批机器码仍要进二进制); -ffunction-sections/-fdata-sections/-Wl,--gc-sections 在本工程反而 +9 216 B(已回退)。 - ⚠️ .o 体积受节对齐/重定位表主导,判断“代码搬去哪了”要用 nm,不要看 .o 字节数。 ## 六、验证(全部离屏:SW_HIDE + 不注入真实输入 + 进程/线程 BELOW_NORMAL) - panelanim 156/156(连跑 5 次稳定;新增/更新:点分组名不折起也不滚动、扫掠定位「组X」热区、 筛选态与普通态折叠三角逐像素一致、改名输入框右边界早于项数文本);verify 49/49; datacheck 69/69(含“重命名写入唯一名称字段且空名被拒”);edgecheck 46/46。 - A/B:回退两处 UI 修复 ⇒ 10 项如实失败;恢复后全绿。 - make release / make debug 零警告。 ## 七、本轮未完成(已在报告与 agent_mem.md 中如实记录) - PlotView.cpp(13 695 行 / 544 KB)按功能拆分为多个协作文件:未执行。 前置改造是把第 13–888 行的匿名命名空间(~870 行常量与工具函数)改成具名命名空间并逐个 inline,再逐个文件搬移并反复验证;时间不足以安全完成,故主动不做(附可执行方案)。 - SignalPanel.cpp / Application.cpp / DataModel.cpp 的多文件化、Lane 抽出 LanePanelState、 SetStatusMessage 模态阻塞解耦:均未执行。 ## 八、文档 - 新增 Documents/refactor_report_2026-10-16.md(本轮详细报告); 删除 Documents/refactor_report_2026-10-15.md(有效内容已并入 agent_mem.md 与本报告)。 - Documents/agent_mem.md 新增 §9.37 与 §11.2 第 85–90 条;更新数据层架构摘要(单一名称字段); §12 历史附录加“时效声明”。
217 lines
8.5 KiB
C++
217 lines
8.5 KiB
C++
#ifndef __UI_CONTROLS_HPP__
|
|
#define __UI_CONTROLS_HPP__
|
|
|
|
#include <windows.h>
|
|
#include <objidl.h>
|
|
#include <gdiplus.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
#include "PaintUtil.hpp"
|
|
#include "TextEdit.hpp"
|
|
|
|
namespace jdi
|
|
{
|
|
|
|
/**
|
|
* @brief 通用 UI 控件(属于 `Components/Shared`)。
|
|
*
|
|
* 这些控件的绘制 / 命中逻辑被**多个功能组件复用**(信号面板的行与样式区、绘图区的
|
|
* 浮动面板与取值胶囊、工具栏、标签栏、弹出菜单、拾色器),因此在共享组件中集中实现,
|
|
* 而不是散落在各自的实现文件里。
|
|
*
|
|
* 依赖方向:`Components/Shared` → `Utilities`(只使用 `PaintUtil` 提供的低层绘制原语),
|
|
* 绝不反向依赖任何功能组件。
|
|
*/
|
|
|
|
/**
|
|
* @brief 在矩形中心绘制一个加号图标。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 图标布局矩形。
|
|
* @param [IN] argb 线条颜色。
|
|
* @param [IN] strokeWidth 线条宽度。
|
|
*/
|
|
void UiDrawPlusIcon(gd::Graphics& g, const gd::RectF& rect, std::uint32_t argb, float strokeWidth);
|
|
|
|
/**
|
|
* @brief 在矩形中心绘制一个叉号(关闭)图标。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 图标布局矩形。
|
|
* @param [IN] argb 线条颜色。
|
|
* @param [IN] strokeWidth 线条宽度。
|
|
*/
|
|
void UiDrawCrossIcon(gd::Graphics& g, const gd::RectF& rect, std::uint32_t argb, float strokeWidth);
|
|
|
|
/**
|
|
* @brief 在矩形中心绘制一个实心三角形指示器。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 图标布局矩形。
|
|
* @param [IN] argb 填充颜色。
|
|
* @param [IN] direction 三角形朝向。
|
|
*/
|
|
void UiDrawTriangleIcon(gd::Graphics& g, const gd::RectF& rect, std::uint32_t argb, IconDirection direction);
|
|
|
|
/**
|
|
* @brief 颜色的相对亮度(0-1,逐通道线性加权)。
|
|
* @param [IN] color 0xAARRGGBB 颜色值。
|
|
* @return 相对亮度。
|
|
*/
|
|
double UiColorLuminance(std::uint32_t color);
|
|
|
|
/**
|
|
* @brief 取值胶囊底色上的高对比度文字色与描边色。
|
|
*/
|
|
struct UiInk
|
|
{
|
|
std::uint32_t text = 0xFF073642u; /**< 文字色(不透明)。 */
|
|
std::uint32_t outline = 0x99FDF6E3u; /**< 描边色(半透明,恒与文字色反相)。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 依据胶囊底色求高对比度的文字色与描边色(对底色配色作线性响应)。
|
|
*
|
|
* 求值分两步:
|
|
* 1. **亮度**:按"取最大对比"的一侧选定亮文字或暗文字。这是唯一的阈值判断,但它
|
|
* 本身就是"任意底色下都保持高对比"的必要条件 —— 任何连续的亮度取值都会在中性灰
|
|
* 附近同时远离两侧极值,对比度必然塌陷。
|
|
* 2. **配色**:把该侧的极值色与**底色的互补色**按固定比例线性混合。互补色的相对亮度
|
|
* 恰为 `1 - 底色亮度`,因此文字/描边的亮度是底色亮度的**线性**函数,色相也随信号
|
|
* 配色连续变化(不再是固定的黑/白两色)。
|
|
*
|
|
* 描边色取相反的一侧,保证"描边—文字—底色"三段式对比。
|
|
*
|
|
* @param [IN] background 胶囊底色(0xAARRGGBB)。
|
|
* @return 文字色与描边色。
|
|
*/
|
|
UiInk UiContrastInk(std::uint32_t background);
|
|
|
|
/**
|
|
* @brief 将滑块轨道上的横坐标换算为取值比例。
|
|
* @param [IN] trackRect 轨道矩形。
|
|
* @param [IN] x 横坐标。
|
|
* @return 取值比例,范围 0-1。
|
|
*/
|
|
double UiSliderRatioFromX(const gd::RectF& trackRect, float x);
|
|
|
|
/**
|
|
* @brief 绘制水平滑块(轨道 + 已填充部分 + 圆钮)。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] track 轨道矩形。
|
|
* @param [IN] ratio 当前值比例(0-1)。
|
|
* @param [IN] fillColor 已填充部分颜色。
|
|
* @param [IN] active 是否处于悬停或拖拽状态(影响圆钮半径)。
|
|
* @param [IN] scale DPI 缩放比例。
|
|
*/
|
|
void UiDrawSlider(gd::Graphics& g, const gd::RectF& track, double ratio, std::uint32_t fillColor,
|
|
bool active, float scale);
|
|
|
|
/**
|
|
* @brief 绘制一个带边框的复选框。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 复选框矩形。
|
|
* @param [IN] state 选中状态:0 未选,1 全选,2 部分选。
|
|
* @param [IN] radius 圆角半径。
|
|
*/
|
|
void UiDrawCheckBox(gd::Graphics& g, const gd::RectF& rect, int state, float radius);
|
|
|
|
/**
|
|
* @brief 计算输入框文本的绘制起点(已考虑超出框宽时的水平滚动)。
|
|
* @param [IN] rect 输入框矩形。
|
|
* @param [IN] edit 编辑模型。
|
|
* @param [IN] font 字体句柄。
|
|
* @param [IN] scale 缩放比例。
|
|
* @param [OUT] innerWidth 框内可用宽度输出。
|
|
* @return 文本绘制起点横坐标。
|
|
*/
|
|
float UiEditTextLeft(const gd::RectF& rect, const TextEdit& edit, HFONT font, float scale,
|
|
float& innerWidth);
|
|
|
|
/**
|
|
* @brief 把输入框内的横坐标换算为字符偏移(就近取整,用于鼠标定位插入符)。
|
|
* @param [IN] font 字体句柄。
|
|
* @param [IN] text 当前文本。
|
|
* @param [IN] localX 相对文本起点的横坐标(可超出 [0, 文本宽度])。
|
|
* @return 字符偏移。
|
|
*/
|
|
std::size_t UiEditOffsetAt(HFONT font, const std::wstring& text, float localX);
|
|
|
|
/**
|
|
* @brief 绘制单行内联输入框(含选区高亮、插入符与水平滚动)。
|
|
*
|
|
* 初始状态为“整体选中”时以强调色底衬显示全部内容,首字符键入即整体替换,
|
|
* 交互观感与常见登录界面的账号/密码输入框一致;文本超出框宽时自动横向滚动,
|
|
* 保证插入符始终可见。
|
|
*
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 输入框矩形。
|
|
* @param [IN] edit 输入框编辑模型。
|
|
* @param [IN] font 文本字体。
|
|
* @param [IN] scale DPI 缩放比例。
|
|
*/
|
|
void UiDrawEditField(gd::Graphics& g, const gd::RectF& rect, const TextEdit& edit, HFONT font,
|
|
float scale);
|
|
|
|
/**
|
|
* @brief 只绘制输入框的**内容**(选区高亮 / 文本 / 插入符),不绘制底板与边框。
|
|
*
|
|
* 用于"宿主已经画好了外框"的场景(例如信号面板的「筛选信号」输入框):若直接调用
|
|
* UiDrawEditField,会在外框内部再套一个带边框的圆角框,形成一圈多余的内圈。
|
|
*
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 输入框矩形(内容区,几何与 UiDrawEditField 完全一致)。
|
|
* @param [IN] edit 输入框编辑模型。
|
|
* @param [IN] font 文本字体。
|
|
* @param [IN] scale DPI 缩放比例。
|
|
*/
|
|
void UiDrawEditFieldContent(gd::Graphics& g, const gd::RectF& rect, const TextEdit& edit, HFONT font,
|
|
float scale);
|
|
|
|
/**
|
|
* @brief 处理输入框内的鼠标按下:命中则把插入符定位到最近的字符边界并开始拖拽框选。
|
|
* @param [IN] font 字体句柄。
|
|
* @param [IN] rect 输入框矩形。
|
|
* @param [IN,OUT] edit 编辑模型。
|
|
* @param [IN] scale 缩放比例。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 命中输入框并开始拖拽返回 true。
|
|
*/
|
|
bool UiEditFieldMouseDown(HFONT font, const gd::RectF& rect, TextEdit& edit, float scale, int x, int y);
|
|
|
|
/**
|
|
* @brief 处理输入框内的鼠标拖拽移动(扩展选区)。
|
|
* @param [IN] font 字体句柄。
|
|
* @param [IN] rect 输入框矩形。
|
|
* @param [IN,OUT] edit 编辑模型。
|
|
* @param [IN] scale 缩放比例。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @return 选区发生变化返回 true。
|
|
*/
|
|
bool UiEditFieldMouseMove(HFONT font, const gd::RectF& rect, TextEdit& edit, float scale, int x);
|
|
|
|
/**
|
|
* @brief 判断给定不透明度是否低到需要为样块补充描边。
|
|
* @param [IN] opacity 不透明度(0-1)。
|
|
* @return 需要描边返回 true。
|
|
*/
|
|
bool UiSwatchNeedsOutline(float opacity);
|
|
|
|
/**
|
|
* @brief 绘制颜色样块:叠加不透明度填充,透明度过低时补充描边以保证可辨识。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] rect 样块矩形。
|
|
* @param [IN] color 基础颜色(0xAARRGGBB,其 Alpha 通道会被不透明度覆盖)。
|
|
* @param [IN] opacity 不透明度(0-1)。
|
|
* @param [IN] radius 圆角半径。
|
|
* @param [IN] scale DPI 缩放比例,用于推导描边粗细。
|
|
* @return 实际填充颜色的 0xAARRGGBB 值(供需要同步其他元素的调用方使用)。
|
|
*/
|
|
std::uint32_t UiDrawSwatch(gd::Graphics& g, const gd::RectF& rect, std::uint32_t color, float opacity,
|
|
float radius, float scale);
|
|
|
|
} // namespace jdi
|
|
|
|
#endif // __UI_CONTROLS_HPP__
|