绘图交互完善 + 稠密区域拖拽性能修复(VERY_BIG_DATA 2ms/大格不再卡顿)
一、功能修正 - 修复「光标数据点在上下视界外不绘制」的问题,并让上下越界与左右越界一样用三角表示: 新增 `DataMarker` / `PaintDataMarker()`,统一处理「可视区内画圆点、越界则钉在网格边上 画三角指示方向」的四向情形(左/右/上/下)。光标取值与中心轴取值都改走这一套, 因此纵向被裁掉的数据点不再消失。 - 「边沿计数(中心轴)」的中心平均值曲线改为**跟随原信号的样式**: 与原始信号同色但更透明,线宽同样跟随(lineWidth + 0.6,下限 1.4), 原信号改颜色/线宽/透明度后曲线同步变化(曲线参与场景指纹,样式变化即失效重绘)。 光标显示中心值时的胶囊也改用**原始信号颜色**(一一对应),并**始终按线段模式**着色, 不再使用光标色。 - 「拆分当前网格」在可点击时追加尾缀「(N个信号)」(N = 该网格内信号数), 只有 1 条信号(不可点击)时不加尾缀。 二、新增:左侧信号筛选框 - 信号列表上方新增「筛选信号」输入框:空内容时显示灰色占位提示,单击进入编辑, 点击别处或回车结束编辑;列表内容随输入**实时**变化。 - 支持 `*` 通配符(`*` 等价于"任意字符",因此 `*` 单独出现等价于不过滤),忽略大小写。 - 筛选结果**仍以组为单位**,组默认展开,只显示匹配的信号;组内无匹配信号时整组不显示。 - 复用统一的 `TextEdit` 编辑模型,因此光标/选区/Ctrl+A/C/X/V 等行为与其它输入框一致。 三、性能:修复 VERY_BIG_DATA.CSV 在 2ms/大格密集区域拖拽卡顿 以「显示全部 5 条信号 + 时间轴缩放到 2ms 一大格」为场景逐段打点定位后修复: - **主因:稠密包络的锯齿描边光栅化**。抽稀时每列产生 min/max 两个顶点交替的锯齿, 2000+ 条近乎满幅的斜线段在 GDI+ 抗锯齿下要光栅化几十万像素(实测每网格 14ms, 5 网格约 70ms/帧)。 改为**包络带一次填充**:逐列记录上/下包络,收段时拼成「上包络正向 + 下包络反向」的 闭合多边形,用一条 `GraphicsPath` + `FillPath` 绘制(显式 `FillModeWinding`, 自交包络不会挖洞)。基准测试(1224 列):14.26ms → **1.69ms(约 8.4 倍)**, 且**保留抗锯齿**、静态帧与拖拽帧完全一致(不是"交互降级")。 逐像素对比确认观感等价(墨量覆盖率 90.8% vs 91.3%)。 包络带同时用于静态绘制与 MOVE_SIGNAL 的拖拽虚影。 - **大面积不透明填充改走 GDI**:`UiFillRect` 在面积 ≥ 20000px² 且颜色不透明时使用 `GetHDC + FillRect`(GDI+ FillRectangle 约 2.2ns/像素,整窗背景 1.7M 像素要 0.9ms、 面板背景 1.9ms)。半透明填充仍走 GDI+(GDI 不做 alpha 混色);小面积仍走 GDI+ (避免 GetHDC 固定开销)。顺序安全:GetHDC 会先刷入已排队的 GDI+ 内容。 - **`UiTextWidth` 不再触发 GDI+ 批次刷新**:改为复用 `UiMeasureTextWidth` (`GetDC(nullptr)`),`UiEllipsize` 逐字符回退时的十几次刷新被完全消除。 实测(125% 缩放、1725x996、5 信号、2ms 一大格): 绘图区绘制 47~87ms → **3.6~4.5ms**;整帧最大 196.8ms → **约 17~21ms(≈50~60fps)**, 与空闲帧基本持平,即"拖拽与不拖拽一样流畅"。 验证(VERY_BIG_DATA.CSV;面板行坐标因新增筛选框整体下移,复选框客户区 (61,250) 起、行距 33): - 筛选框:输入 `B` 后只剩「编码器B相」「电流钳采集(ABSx10)」,组仍展开;清空即恢复。 - 拆分:合并 3 条信号后右键显示「拆分当前网格(3个信号)」;单信号网格该项置灰无尾缀。 - 光标/中心轴:竖线光标取值与中心值胶囊均按四向越界正确显示三角/圆点。 - 稠密区域:5 信号全选 + 缩放到 2ms 一大格,左键拖拽信号、左键平移、中键平移均流畅; 渲染观感与修改前等价(叠图对比)。 - make clean && make all 无警告无错误。
This commit is contained in:
1 parent
82a29362eb
commit
fe72afc83c
6 files changed
+721
-126
No files matched your search
@@ -166,7 +166,38 @@ namespace jdi
|
||||
* @brief 判断面板是否处于内联文本输入状态。
|
||||
* @return 正在输入返回 true。
|
||||
*/
|
||||
bool IsEditing() const { return m_editField != StyleEditField::NONE; }
|
||||
bool IsEditing() const { return m_editField != StyleEditField::NONE || m_filterEditing; }
|
||||
|
||||
/**
|
||||
* @brief 判断坐标是否落在列表上方的「筛选信号」输入框内。
|
||||
* @param [IN] x 客户区横坐标。
|
||||
* @param [IN] y 客户区纵坐标。
|
||||
* @return 落在输入框内返回 true。
|
||||
*/
|
||||
bool IsOnFilterBox(int x, int y) const;
|
||||
|
||||
/**
|
||||
* @brief 进入筛选输入框的编辑状态(单击输入框时调用)。
|
||||
*/
|
||||
void BeginFilterEdit();
|
||||
|
||||
/**
|
||||
* @brief 结束筛选输入框的编辑状态(点击别处或回车时调用)。
|
||||
* @return 状态发生变化返回 true。
|
||||
*/
|
||||
bool EndFilterEdit();
|
||||
|
||||
/**
|
||||
* @brief 筛选框是否处于编辑状态。
|
||||
* @return 编辑中返回 true。
|
||||
*/
|
||||
bool IsFilterEditing() const { return m_filterEditing; }
|
||||
|
||||
/**
|
||||
* @brief 获取当前筛选文本。
|
||||
* @return 筛选文本(未输入时为空串)。
|
||||
*/
|
||||
const std::wstring& FilterText() const { return m_filterText; }
|
||||
|
||||
/**
|
||||
* @brief 向当前输入框送入一个字符。
|
||||
@@ -493,6 +524,12 @@ namespace jdi
|
||||
*/
|
||||
gd::RectF EditFieldRect() const;
|
||||
|
||||
/**
|
||||
* @brief 计算「筛选信号」输入框的内容矩形(编辑与显示共用,保证不跳动)。
|
||||
* @return 内容矩形。
|
||||
*/
|
||||
gd::RectF FilterFieldRect() const;
|
||||
|
||||
/**
|
||||
* @brief 计算指定行中名称区域的矩形(列表行内联编辑使用)。
|
||||
* @param [IN] row 行下标。
|
||||
@@ -534,6 +571,7 @@ namespace jdi
|
||||
|
||||
gd::RectF m_area; /**< 面板整体区域。 */
|
||||
gd::RectF m_headerRect; /**< 标题区域。 */
|
||||
gd::RectF m_filterRect; /**< 列表上方的「筛选信号」输入框区域。 */
|
||||
gd::RectF m_listRect; /**< 列表区域。 */
|
||||
gd::RectF m_styleRect; /**< 样式编辑区域。 */
|
||||
gd::RectF m_toggleAllRect; /**< 全部显示/隐藏按钮。 */
|
||||
@@ -573,6 +611,23 @@ namespace jdi
|
||||
int m_editRow = -1; /**< 行内输入所作用的列表行下标。 */
|
||||
TextEdit m_edit; /**< 输入框编辑模型(光标/选区/剪贴板)。 */
|
||||
|
||||
bool m_filterEditing = false; /**< 「筛选信号」输入框是否处于编辑状态。 */
|
||||
std::wstring m_filterText; /**< 当前筛选文本(空串表示不过滤)。 */
|
||||
TextEdit m_filterEdit; /**< 筛选输入框的编辑模型。 */
|
||||
|
||||
/**
|
||||
* @brief 设置筛选文本并立即生效(重建行集合、回到顶部)。
|
||||
* @param [IN] text 新的筛选文本(空串表示不过滤)。
|
||||
*/
|
||||
void ApplyFilterText(const std::wstring& text);
|
||||
|
||||
/**
|
||||
* @brief 判断某信号的显示名是否匹配当前筛选表达式。
|
||||
* @param [IN] signal 信号数据。支持 `*` 通配符,忽略大小写。
|
||||
* @return 匹配(或未设置筛选)返回 true。
|
||||
*/
|
||||
bool FilterMatchesSignal(const SignalData& signal) const;
|
||||
|
||||
bool m_pendingLaneMenu = false; /**< 左键抬起时是否弹出网格归属菜单。 */
|
||||
SignalRef m_pendingLaneRef; /**< 待弹出菜单的目标信号。 */
|
||||
bool m_pendingColorPicker = false; /**< 左键抬起时是否弹出拾色器。 */
|
||||
|
||||
Reference in new issue
Block a user