一、功能修正 - 修复「光标数据点在上下视界外不绘制」的问题,并让上下越界与左右越界一样用三角表示: 新增 `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 无警告无错误。
644 lines
20 KiB
C++
644 lines
20 KiB
C++
#ifndef __SIGNAL_PANEL_HPP__
|
|
#define __SIGNAL_PANEL_HPP__
|
|
|
|
#include <windows.h>
|
|
#include <objidl.h>
|
|
#include <gdiplus.h>
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "ColorPickerPopup.hpp"
|
|
#include "DataModel.hpp"
|
|
#include "PaintUtil.hpp"
|
|
#include "PopupMenu.hpp"
|
|
#include "Theme.hpp"
|
|
|
|
namespace jdi
|
|
{
|
|
|
|
/**
|
|
* @brief 信号面板弹出菜单的命令标识。
|
|
*/
|
|
enum MenuCommand : int
|
|
{
|
|
CMD_SIGNAL_TOGGLE = 1, /**< 切换该信号可见性。 */
|
|
CMD_SIGNAL_SOLO = 2, /**< 仅显示该信号。 */
|
|
CMD_SIGNAL_SHOW_ALL = 3, /**< 显示全部信号。 */
|
|
CMD_SIGNAL_HIDE_ALL = 4, /**< 隐藏全部信号。 */
|
|
CMD_FILE_SHOW_ALL = 10, /**< 选中该文件全部信号。 */
|
|
CMD_FILE_HIDE_ALL = 11, /**< 取消该文件全部信号。 */
|
|
CMD_FILE_REMOVE = 12, /**< 从工作区移除该文件。 */
|
|
CMD_COLOR_BASE = 100, /**< 预设颜色基准(配合色块下标)。 */
|
|
CMD_MODE_BASE = 200, /**< 绘制样式基准(配合下标)。 */
|
|
CMD_LANE_BASE = 300, /**< 网格归属基准(配合下标)。 */
|
|
CMD_LANE_NEW = 400 /**< 新建网格。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 左侧信号面板:按文件分组的信号树、可见性勾选与样式编辑。
|
|
*
|
|
* 面板只读取数据层(DataSet),全部显示配置读写均落在当前标签页(TabConfig)上,
|
|
* 因此不同标签页的信号勾选与样式互不影响。所有弹出菜单与拾色器均使用主题化自绘
|
|
* 浮动面板,不出现系统默认菜单样式。
|
|
*/
|
|
class SignalPanel
|
|
{
|
|
public:
|
|
SignalPanel();
|
|
|
|
/**
|
|
* @brief 绑定宿主窗口、字体、主题与共用浮动控件。
|
|
* @param [IN] host 宿主窗口句柄。
|
|
* @param [IN] fonts 字体集合,需在面板生命周期内保持有效。
|
|
* @param [IN] theme 主题配色,需在面板生命周期内保持有效。
|
|
* @param [IN] menu 共用的主题化弹出菜单,需在面板生命周期内保持有效。
|
|
* @param [IN] colorPicker 共用的浮动拾色器,需在面板生命周期内保持有效。
|
|
*/
|
|
void Setup(HWND host, const UiFonts* fonts, const Theme* theme, PopupMenu* menu,
|
|
ColorPickerPopup* colorPicker);
|
|
|
|
/**
|
|
* @brief 绑定数据层与当前标签页配置。
|
|
* @param [IN] dataSet 数据集合(可写,用于重命名信号与分组)。
|
|
* @param [IN] tab 当前标签页配置,允许为空。
|
|
*/
|
|
void SetContext(DataSet* dataSet, TabConfig* tab);
|
|
|
|
/**
|
|
* @brief 设置宿主客户区矩形(用于约束浮动面板位置)。
|
|
* @param [IN] bounds 客户区矩形。
|
|
*/
|
|
void SetClientBounds(const gd::RectF& bounds) { m_clientBounds = bounds; }
|
|
|
|
/**
|
|
* @brief 标记列表结构失效(数据或折叠状态变化后调用)。
|
|
*/
|
|
void InvalidateRows() { m_rowsDirty = true; }
|
|
|
|
/**
|
|
* @brief 判断列表内容是否需要纵向滚动。
|
|
* @return 内容超出可视区域返回 true。
|
|
*/
|
|
bool NeedsScrollBar() const { return m_contentHeight > m_listRect.Height + 0.5f; }
|
|
|
|
/**
|
|
* @brief 设置 DPI 缩放比例。
|
|
* @param [IN] scale 缩放比例(1.0 对应 96 DPI)。
|
|
*/
|
|
void SetScale(float scale);
|
|
|
|
/**
|
|
* @brief 按给定区域重新排布面板内容。
|
|
* @param [IN] area 面板可用区域。
|
|
*/
|
|
void Layout(const gd::RectF& area);
|
|
|
|
/**
|
|
* @brief 绘制面板。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
*/
|
|
void Paint(gd::Graphics& g);
|
|
|
|
/**
|
|
* @brief 处理鼠标移动。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 悬停状态发生变化返回 true。
|
|
*/
|
|
bool OnMouseMove(int x, int y);
|
|
|
|
/**
|
|
* @brief 处理鼠标左键按下。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 需要重绘返回 true。
|
|
*/
|
|
bool OnLButtonDown(int x, int y);
|
|
|
|
/**
|
|
* @brief 处理鼠标左键抬起(网格徽标与自定义颜色入口在此刻触发展开)。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 视觉状态发生变化返回 true。
|
|
*/
|
|
bool OnLButtonUp(int x, int y);
|
|
|
|
/**
|
|
* @brief 处理鼠标左键双击(线宽数值进入输入状态,其余行切换可见性)。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 需要重绘返回 true。
|
|
*/
|
|
bool OnDoubleClick(int x, int y);
|
|
|
|
/**
|
|
* @brief 处理鼠标右键按下(弹出上下文菜单)。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 需要重绘返回 true。
|
|
*/
|
|
bool OnRButtonDown(int x, int y);
|
|
|
|
/**
|
|
* @brief 处理滚轮滚动(列表纵向滚动)。
|
|
* @param [IN] delta 滚轮增量。
|
|
* @return 需要重绘返回 true。
|
|
*/
|
|
bool OnMouseWheel(int delta);
|
|
|
|
/**
|
|
* @brief 处理鼠标离开面板。
|
|
* @return 视觉状态发生变化返回 true。
|
|
*/
|
|
bool OnMouseLeave();
|
|
|
|
/**
|
|
* @brief 处理弹出菜单的选择结果。
|
|
* @param [IN] result 菜单选择结果。
|
|
* @return 需要重新布局返回 true。
|
|
*/
|
|
bool OnMenuCommand(const MenuResult& result);
|
|
|
|
/**
|
|
* @brief 判断面板是否处于内联文本输入状态。
|
|
* @return 正在输入返回 true。
|
|
*/
|
|
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 向当前输入框送入一个字符。
|
|
* @param [IN] character 输入字符('\r' 提交、'\b' 退格、0x03 复制)。
|
|
* @return 界面状态发生变化返回 true。
|
|
*/
|
|
bool OnEditChar(wchar_t character);
|
|
|
|
/**
|
|
* @brief 向当前输入框送入一个按键。
|
|
* @param [IN] key 虚拟键码。
|
|
* @return 界面状态发生变化返回 true。
|
|
*/
|
|
bool OnEditKey(WPARAM key);
|
|
|
|
/**
|
|
* @brief 编辑态下按下鼠标右键:取消选区并把插入符移到文本末尾。
|
|
* @return 发生改变返回 true;不在编辑态返回 false。
|
|
*/
|
|
bool CollapseEditSelectionToEnd();
|
|
|
|
/**
|
|
* @brief 编辑态下在输入框内按下鼠标左键:定位插入符并开始拖拽框选。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 命中输入框返回 true。
|
|
*/
|
|
bool OnEditMouseDown(int x, int y);
|
|
|
|
/**
|
|
* @brief 编辑态下拖拽鼠标:扩展选区。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @return 选区发生变化返回 true。
|
|
*/
|
|
bool OnEditMouseMove(int x);
|
|
|
|
/**
|
|
* @brief 编辑态下松开鼠标左键:结束拖拽框选。
|
|
* @return 之前处于拖拽中返回 true。
|
|
*/
|
|
bool OnEditMouseUp();
|
|
|
|
/**
|
|
* @brief 获取指定信号的显示外观(只读,全局共享)。
|
|
* @param [IN] ref 信号引用。
|
|
* @return 外观指针,引用无效时返回 nullptr。
|
|
*/
|
|
const SignalStyle* StyleOf(const SignalRef& ref) const;
|
|
|
|
/**
|
|
* @brief 获取指定信号的显示外观(可写,全局共享)。
|
|
* @param [IN] ref 信号引用。
|
|
* @return 外观指针,引用无效时返回 nullptr。
|
|
*/
|
|
SignalStyle* StyleOf(const SignalRef& ref);
|
|
|
|
/**
|
|
* @brief 获取当前选中信号(跨标签页共享,因此切换视图后选中项保持一致)。
|
|
* @return 信号引用。
|
|
*/
|
|
const SignalRef& SelectedRef() const;
|
|
|
|
/**
|
|
* @brief 设置当前选中信号(跨标签页共享)。
|
|
* @param [IN] ref 信号引用。
|
|
*/
|
|
void SelectSignal(const SignalRef& ref);
|
|
|
|
/**
|
|
* @brief 将浮动拾色器的取色结果应用到当前选中信号。
|
|
* @param [IN] color 0xAARRGGBB 颜色值。
|
|
* @return 应用成功返回 true。
|
|
*/
|
|
bool ApplyColor(std::uint32_t color);
|
|
|
|
/**
|
|
* @brief 关闭自定义颜色面板与线宽输入状态。
|
|
* @return 界面状态发生变化返回 true。
|
|
*/
|
|
bool CloseTransientUi();
|
|
|
|
/**
|
|
* @brief 取出并清除“需要重新布局”标记。
|
|
* @return 需要重新布局返回 true。
|
|
*/
|
|
bool TakeLayoutDirty();
|
|
|
|
/**
|
|
* @brief 判断坐标是否落在面板区域内。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 落在区域内返回 true。
|
|
*/
|
|
bool HitTest(int x, int y) const;
|
|
|
|
/**
|
|
* @brief 将列表滚动到指定信号所在位置。
|
|
* @param [IN] ref 目标信号引用。
|
|
*/
|
|
void ScrollToSignal(const SignalRef& ref);
|
|
|
|
private:
|
|
/**
|
|
* @brief 样式区与列表行中可进行内联文本编辑的字段。
|
|
*/
|
|
enum class StyleEditField : int
|
|
{
|
|
NONE = 0, /**< 未处于编辑状态。 */
|
|
WIDTH = 1, /**< 线宽数值。 */
|
|
OPACITY = 2, /**< 不透明度数值(百分比)。 */
|
|
SIGNAL_NAME = 3, /**< 信号显示名称(列表行内)。 */
|
|
FILE_NAME = 4 /**< 分组显示名称(列表行内)。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 列表行的类型。
|
|
*/
|
|
enum class RowKind : int
|
|
{
|
|
FILE = 0, /**< 文件分组标题行。 */
|
|
SIGNAL = 1 /**< 信号行。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 行的可交互区域。
|
|
*/
|
|
enum class RowPart : int
|
|
{
|
|
NONE = 0, /**< 未命中。 */
|
|
DISCLOSURE, /**< 折叠三角。 */
|
|
CHECK, /**< 复选框。 */
|
|
BODY, /**< 行主体。 */
|
|
CLOSE, /**< 文件行的关闭按钮。 */
|
|
LANE_BADGE /**< 信号行的网格徽标。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 样式编辑区中的可交互条目类型。
|
|
*/
|
|
enum class StyleHit : int
|
|
{
|
|
NONE = 0, /**< 未命中。 */
|
|
COLOR, /**< 预设颜色色块。 */
|
|
CUSTOM_CHIP, /**< 自定义颜色入口。 */
|
|
MODE, /**< 绘制样式按钮。 */
|
|
OPACITY_SLIDER, /**< 不透明度滑块。 */
|
|
OPACITY_VALUE, /**< 不透明度数值框(可点击输入)。 */
|
|
WIDTH_SLIDER, /**< 线宽滑块。 */
|
|
WIDTH_VALUE, /**< 线宽数值框(可点击输入)。 */
|
|
TOGGLE_ALL /**< 全部显示/隐藏按钮。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 列表中的一行(文件分组或信号)。
|
|
*/
|
|
struct ListRow
|
|
{
|
|
RowKind kind = RowKind::SIGNAL; /**< 行类型。 */
|
|
int fileIndex = -1; /**< 所属文件下标。 */
|
|
int signalIndex = -1; /**< 信号下标(仅信号行有效)。 */
|
|
float height = 0.0f; /**< 行高(像素)。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 重新构建列表行集合。
|
|
*/
|
|
void BuildRows();
|
|
|
|
/**
|
|
* @brief 在需要时重建列表行集合。
|
|
*/
|
|
void EnsureRows();
|
|
|
|
/**
|
|
* @brief 依据内容高度重算滚动条可见性与列表可用宽度。
|
|
*/
|
|
void RefreshScrollBar();
|
|
|
|
/**
|
|
* @brief 计算列表内容总高度。
|
|
* @return 内容高度(像素)。
|
|
*/
|
|
float ContentHeight() const;
|
|
|
|
/**
|
|
* @brief 限制滚动偏移量到合法范围。
|
|
*/
|
|
void ClampScroll();
|
|
|
|
/**
|
|
* @brief 查询坐标命中的行下标与行内区域。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @param [OUT] part 行内区域类型。
|
|
* @return 行下标,未命中返回 -1。
|
|
*/
|
|
int HitRow(int x, int y, RowPart& part);
|
|
|
|
/**
|
|
* @brief 计算行的纵向矩形。
|
|
* @param [IN] row 行下标。
|
|
* @return 行矩形。
|
|
*/
|
|
gd::RectF RowRect(int row) const;
|
|
|
|
/**
|
|
* @brief 计算文件行关闭按钮矩形。
|
|
* @param [IN] row 行下标。
|
|
* @return 关闭按钮矩形。
|
|
*/
|
|
gd::RectF FileCloseRect(int row) const;
|
|
|
|
/**
|
|
* @brief 计算信号行网格徽标矩形。
|
|
* @param [IN] row 行下标。
|
|
* @return 徽标矩形。
|
|
*/
|
|
gd::RectF SignalBadgeRect(int row) const;
|
|
|
|
/**
|
|
* @brief 绘制文件分组标题行。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] row 行下标。
|
|
*/
|
|
void PaintFileRow(gd::Graphics& g, int row);
|
|
|
|
/**
|
|
* @brief 绘制信号行。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
* @param [IN] row 行下标。
|
|
*/
|
|
void PaintSignalRow(gd::Graphics& g, int row);
|
|
|
|
/**
|
|
* @brief 绘制样式编辑区(固定四行:颜色 / 线宽 / 样式 / 透明度)。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
*/
|
|
void PaintStyleSection(gd::Graphics& g);
|
|
|
|
/**
|
|
* @brief 绘制列表滚动条。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
*/
|
|
void PaintScrollBar(gd::Graphics& g);
|
|
|
|
/**
|
|
* @brief 计算滚动条滑块矩形。
|
|
* @return 滑块矩形,无需滚动时返回空矩形。
|
|
*/
|
|
gd::RectF ScrollThumbRect() const;
|
|
|
|
/**
|
|
* @brief 布置样式编辑区内各控件的矩形。
|
|
*/
|
|
void LayoutStyleControls();
|
|
|
|
/**
|
|
* @brief 取得样式编辑区固定所需高度。
|
|
* @return 逻辑高度(未乘缩放比例)。
|
|
*/
|
|
float DesiredStyleHeight() const;
|
|
|
|
/**
|
|
* @brief 弹出信号右键菜单。
|
|
* @param [IN] ref 目标信号引用。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
*/
|
|
void OpenSignalMenu(const SignalRef& ref, int x, int y);
|
|
|
|
/**
|
|
* @brief 弹出文件分组右键菜单。
|
|
* @param [IN] fileIndex 目标文件下标。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
*/
|
|
void OpenFileMenu(int fileIndex, int x, int y);
|
|
|
|
/**
|
|
* @brief 弹出网格归属菜单(由信号行的网格徽标触发)。
|
|
* @param [IN] ref 目标信号引用。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
*/
|
|
void OpenLaneMenu(const SignalRef& ref, int x, int y);
|
|
|
|
/**
|
|
* @brief 打开浮动拾色器(由自定义颜色入口触发)。
|
|
* @param [IN] style 当前信号样式。
|
|
* @return 打开成功返回 true。
|
|
*/
|
|
bool OpenColorPickerPopup(const SignalStyle& style);
|
|
|
|
/**
|
|
* @brief 判断当前标签页中全部信号是否均为可见状态。
|
|
* @return 全部可见且至少有一条信号返回 true。
|
|
*/
|
|
bool AreAllSignalsVisible() const;
|
|
|
|
/**
|
|
* @brief 统计全部信号数量。
|
|
* @return 信号总数。
|
|
*/
|
|
int TotalSignalCount() const;
|
|
|
|
/**
|
|
* @brief 进入指定字段的内联输入状态。
|
|
* @param [IN] field 目标字段。
|
|
* @param [IN] row 列表行下标(仅行内字段有效)。
|
|
* @return 状态发生变化返回 true。
|
|
*/
|
|
bool BeginEdit(StyleEditField field, int row = -1);
|
|
|
|
/**
|
|
* @brief 结束内联输入状态。
|
|
* @param [IN] commit 是否提交输入值。
|
|
* @return 状态或取值发生变化返回 true。
|
|
*/
|
|
bool EndEdit(bool commit);
|
|
|
|
/**
|
|
* @brief 计算当前输入框的矩形。
|
|
* @return 输入框矩形,未处于编辑状态时返回空矩形。
|
|
*/
|
|
gd::RectF EditFieldRect() const;
|
|
|
|
/**
|
|
* @brief 计算「筛选信号」输入框的内容矩形(编辑与显示共用,保证不跳动)。
|
|
* @return 内容矩形。
|
|
*/
|
|
gd::RectF FilterFieldRect() const;
|
|
|
|
/**
|
|
* @brief 计算指定行中名称区域的矩形(列表行内联编辑使用)。
|
|
* @param [IN] row 行下标。
|
|
* @return 名称区域矩形。
|
|
*/
|
|
gd::RectF RowNameRect(int row) const;
|
|
|
|
/**
|
|
* @brief 计算分组行中“组X”标签的像素宽度。
|
|
* @param [IN] row 行下标。
|
|
* @return 标签宽度。
|
|
*/
|
|
float FileGroupLabelWidth(int row) const;
|
|
|
|
/**
|
|
* @brief 调整当前信号不透明度。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @return 取值发生变化返回 true。
|
|
*/
|
|
bool ApplyOpacityFromX(float x);
|
|
|
|
/**
|
|
* @brief 依据线宽滑块横坐标调整当前信号线宽。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @return 取值发生变化返回 true。
|
|
*/
|
|
bool ApplyWidthFromX(float x);
|
|
|
|
HWND m_host = nullptr; /**< 宿主窗口句柄。 */
|
|
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
|
|
const Theme* m_theme = nullptr; /**< 主题资源。 */
|
|
PopupMenu* m_menu = nullptr; /**< 共用弹出菜单。 */
|
|
ColorPickerPopup* m_colorPicker = nullptr; /**< 共用浮动拾色器。 */
|
|
const DataSet* m_dataSet = nullptr; /**< 数据集合(只读访问)。 */
|
|
DataSet* m_dataSetWritable = nullptr; /**< 数据集合(重命名等写入操作)。 */
|
|
TabConfig* m_tab = nullptr; /**< 当前标签页配置。 */
|
|
float m_scale = 1.0f; /**< DPI 缩放比例。 */
|
|
gd::RectF m_clientBounds; /**< 宿主客户区矩形。 */
|
|
|
|
gd::RectF m_area; /**< 面板整体区域。 */
|
|
gd::RectF m_headerRect; /**< 标题区域。 */
|
|
gd::RectF m_filterRect; /**< 列表上方的「筛选信号」输入框区域。 */
|
|
gd::RectF m_listRect; /**< 列表区域。 */
|
|
gd::RectF m_styleRect; /**< 样式编辑区域。 */
|
|
gd::RectF m_toggleAllRect; /**< 全部显示/隐藏按钮。 */
|
|
gd::RectF m_scrollBarRect; /**< 滚动条区域。 */
|
|
|
|
std::array<gd::RectF, 12> m_colorRects; /**< 预设颜色色块矩形。 */
|
|
int m_colorCount = 0; /**< 实际可用的预设颜色数量。 */
|
|
gd::RectF m_customChipRect; /**< 自定义颜色入口矩形(与预设色块同尺寸)。 */
|
|
|
|
std::array<gd::RectF, 3> m_modeRects; /**< 绘制样式按钮矩形。 */
|
|
|
|
// 样式区固定四行:颜色 / 样式 / 透明度 / 线宽。各行控件共用同一内容列宽度与左边界。
|
|
std::array<gd::RectF, 4> m_styleRowRects; /**< 四行整体矩形(含标签列)。 */
|
|
|
|
gd::RectF m_opacityTrackRect; /**< 不透明度滑块轨道矩形。 */
|
|
gd::RectF m_opacityValueRect; /**< 不透明度数值文本矩形。 */
|
|
gd::RectF m_widthTrackRect; /**< 线宽滑块轨道矩形。 */
|
|
gd::RectF m_widthValueRect; /**< 线宽数值文本矩形(双击可输入)。 */
|
|
|
|
std::vector<ListRow> m_rows; /**< 列表行集合(惰性缓存)。 */
|
|
bool m_rowsDirty = true; /**< 列表行集合是否需要重建。 */
|
|
float m_contentHeight = 0.0f; /**< 列表内容总高度。 */
|
|
float m_listFullWidth = 0.0f; /**< 列表区不含滚动条的完整宽度。 */
|
|
bool m_scrollBarVisible = false; /**< 是否需要显示滚动条。 */
|
|
|
|
float m_scrollOffset = 0.0f; /**< 列表滚动偏移量。 */
|
|
bool m_draggingScrollBar = false; /**< 是否正在拖拽滚动条。 */
|
|
int m_scrollGrabOffset = 0; /**< 拖拽时鼠标相对滑块顶部的偏移。 */
|
|
bool m_draggingOpacity = false; /**< 是否正在拖拽不透明度滑块。 */
|
|
bool m_draggingWidth = false; /**< 是否正在拖拽线宽滑块。 */
|
|
int m_hoverRow = -1; /**< 当前悬停行。 */
|
|
RowPart m_hoverPart = RowPart::NONE; /**< 当前悬停的行内区域。 */
|
|
StyleHit m_hoverStyle = StyleHit::NONE; /**< 当前悬停的样式条目类型。 */
|
|
int m_hoverStyleIndex = -1; /**< 当前悬停的样式条目下标。 */
|
|
|
|
StyleEditField m_editField = StyleEditField::NONE; /**< 当前处于输入状态的字段。 */
|
|
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; /**< 左键抬起时是否弹出拾色器。 */
|
|
|
|
bool m_layoutDirty = false; /**< 是否需要重新布局。 */
|
|
|
|
SignalRef m_menuTargetSignal; /**< 菜单操作的目标信号。 */
|
|
int m_menuTargetFile = -1; /**< 菜单操作的目标文件。 */
|
|
};
|
|
|
|
} // namespace jdi
|
|
|
|
#endif // __SIGNAL_PANEL_HPP__
|