fix: 修复网格徽标菜单与标签页编号,重构样式区并新增透明度与浮动拾色器

信号列表
- 网格徽标(G1/G2)改为在左键抬起时弹出菜单,修复此前「按住才显示、松手即消失」的问题。
- 文件分组行新增关闭按钮(✕),可直接从工作区移除文件,与右键菜单「关闭该文件」等价。
- 信号名改为完整保留文件内的列名原文,不再剥离 "[n]" 序号前缀与括号内容。

标签页
- 新建标签页改用「当前未被占用的最小编号」,关闭标签页后编号可被复用,
  修复「开 3 关 2 再新建会变成视图 4」的问题。

样式编辑区(统一为固定四行网格布局,面板缩放时不再错位)
- 移除顶部「样式 · 信号名 · 文件名」标题行,选中信号即为编辑对象。
- 绘制方式取消「阶梯」,标签由「方式」改为「样式」,仅保留线段 / 散点 / 点线。
- 线宽仅保留最细与最粗两个预设,中间改为带左右箭头的数值旋钮,单位为 px;
  支持单击或双击数值框直接键入(首次键入替换原值,回车提交、Esc 取消、越界钳制到 0.5-6.0)。
- 颜色预设后新增与预设色块完全同尺寸、同外框样式的「加号」小方格,
  点击后弹出浮动拾色面板(与 G1/G2 菜单同风格的浮动窗口),支持 RGB 三通道滑块、
  实时预览与十六进制显示;点击面板外部即收起,取色实时应用到当前信号。
- 移除样式区末尾的网格选择控件,该功能统一由信号行的 G 徽标承载。
- 新增透明度滑块,默认 100%,可在 0-100% 之间调节,并实时反映到波形、
  图例色块与信号行色块的显示效果。

其他
- 信号面板默认宽度与行内间距微调,使较长的列名可以完整显示。
- 失焦时提交线宽输入并收起浮动拾色器与弹出菜单。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-09-29 17:14:27 +08:00
1 parent eb868b2679
commit 729494d1ec
9 files changed
+1254 -471

No files matched your search

+92 -47
View File
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
#include "ColorPickerPopup.hpp"
#include "DataModel.hpp"
#include "PaintUtil.hpp"
#include "PopupMenu.hpp"
@@ -40,8 +41,8 @@ namespace jdi
* @brief 左侧信号面板:按文件分组的信号树、可见性勾选与样式编辑。
*
* 面板只读取数据层(DataSet),全部显示配置读写均落在当前标签页(TabConfig)上,
* 因此不同标签页的信号勾选与样式互不影响。所有弹出菜单均使用主题化自绘菜单,
* 不出现系统默认菜单样式。
* 因此不同标签页的信号勾选与样式互不影响。所有弹出菜单与拾色器均使用主题化自绘
* 浮动面板,不出现系统默认菜单样式。
*/
class SignalPanel
{
@@ -49,13 +50,15 @@ namespace jdi
SignalPanel();
/**
* @brief 绑定宿主窗口、字体、主题与共用弹出菜单。
* @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);
void Setup(HWND host, const UiFonts* fonts, const Theme* theme, PopupMenu* menu,
ColorPickerPopup* colorPicker);
/**
* @brief 绑定数据层与当前标签页配置。
@@ -65,7 +68,7 @@ namespace jdi
void SetContext(const DataSet* dataSet, TabConfig* tab);
/**
* @brief 设置宿主客户区矩形(用于约束弹出菜单位置)。
* @brief 设置宿主客户区矩形(用于约束浮动面板位置)。
* @param [IN] bounds 客户区矩形。
*/
void SetClientBounds(const gd::RectF& bounds) { m_clientBounds = bounds; }
@@ -73,19 +76,13 @@ namespace jdi
/**
* @brief 标记列表结构失效(数据或折叠状态变化后调用)。
*/
void InvalidateRows()
{
m_rowsDirty = true;
}
void InvalidateRows() { m_rowsDirty = true; }
/**
* @brief 判断列表内容是否需要纵向滚动。
* @return 内容超出可视区域返回 true。
*/
bool NeedsScrollBar() const
{
return m_contentHeight > m_listRect.Height + 0.5f;
}
bool NeedsScrollBar() const { return m_contentHeight > m_listRect.Height + 0.5f; }
/**
* @brief 设置 DPI 缩放比例。
@@ -122,7 +119,7 @@ namespace jdi
bool OnLButtonDown(int x, int y);
/**
* @brief 处理鼠标左键抬起。
* @brief 处理鼠标左键抬起(网格徽标与自定义颜色入口在此刻触发展开)。
* @param [IN] x 客户区横坐标。
* @param [IN] y 客户区纵坐标。
* @return 视觉状态发生变化返回 true。
@@ -130,7 +127,7 @@ namespace jdi
bool OnLButtonUp(int x, int y);
/**
* @brief 处理鼠标左键双击(切换信号可见性)。
* @brief 处理鼠标左键双击(线宽数值进入输入状态,其余行切换可见性)。
* @param [IN] x 客户区横坐标。
* @param [IN] y 客户区纵坐标。
* @return 需要重绘返回 true。
@@ -166,7 +163,34 @@ namespace jdi
bool OnMenuCommand(const MenuResult& result);
/**
* @brief 关闭自定义颜色面板等临时展开的界面。
* @brief 判断线宽数值框是否处于输入状态。
* @return 正在输入返回 true。
*/
bool IsEditingWidth() const { return m_widthEditing; }
/**
* @brief 向线宽输入框送入一个字符。
* @param [IN] character 输入字符('\r' 提交、'\b' 退格)。
* @return 界面状态发生变化返回 true。
*/
bool OnEditChar(wchar_t character);
/**
* @brief 向线宽输入框送入一个按键。
* @param [IN] key 虚拟键码。
* @return 界面状态发生变化返回 true。
*/
bool OnEditKey(WPARAM key);
/**
* @brief 将浮动拾色器的取色结果应用到当前选中信号。
* @param [IN] color 0xAARRGGBB 颜色值。
* @return 应用成功返回 true。
*/
bool ApplyColor(std::uint32_t color);
/**
* @brief 关闭自定义颜色面板与线宽输入状态。
* @return 界面状态发生变化返回 true。
*/
bool CloseTransientUi();
@@ -215,18 +239,19 @@ namespace jdi
};
/**
* @brief 样式编辑区中的可点击条目类型。
* @brief 样式编辑区中的可交互条目类型。
*/
enum class StyleHit : int
{
NONE = 0, /**< 未命中。 */
COLOR, /**< 预设颜色色块。 */
CUSTOM_CHIP, /**< 自定义颜色入口。 */
WIDTH_PRESET, /**< 线宽预设按钮。 */
WIDTH_PRESET, /**< 线宽预设按钮(细/粗)。 */
WIDTH_MINUS, /**< 线宽减号。 */
WIDTH_PLUS, /**< 线宽加号。 */
WIDTH_VALUE, /**< 线宽数值框。 */
MODE, /**< 绘制样式按钮。 */
SLIDER, /**< 自定义颜色滑块。 */
OPACITY, /**< 不透明度滑块。 */
TOGGLE_ALL /**< 全部显示/隐藏按钮。 */
};
@@ -312,18 +337,11 @@ namespace jdi
void PaintSignalRow(gd::Graphics& g, int row);
/**
* @brief 绘制样式编辑区。
* @brief 绘制样式编辑区(固定四行:颜色 / 线宽 / 样式 / 透明度)。
* @param [IN,OUT] g 绘图上下文。
*/
void PaintStyleSection(gd::Graphics& g);
/**
* @brief 绘制自定义颜色面板。
* @param [IN,OUT] g 绘图上下文。
* @param [IN] style 当前编辑的信号样式。
*/
void PaintColorPicker(gd::Graphics& g, const SignalStyle& style);
/**
* @brief 绘制列表滚动条。
* @param [IN,OUT] g 绘图上下文。
@@ -342,7 +360,7 @@ namespace jdi
void LayoutStyleControls();
/**
* @brief 取得当前样式编辑区所需高度。
* @brief 取得样式编辑区固定所需高度。
* @return 逻辑高度(未乘缩放比例)。
*/
float DesiredStyleHeight() const;
@@ -371,6 +389,13 @@ namespace jdi
*/
void OpenLaneMenu(const SignalRef& ref, int x, int y);
/**
* @brief 打开浮动拾色器(由自定义颜色入口触发)。
* @param [IN] style 当前信号样式。
* @return 打开成功返回 true。
*/
bool OpenColorPickerPopup(const SignalStyle& style);
/**
* @brief 判断当前标签页中全部信号是否均为可见状态。
* @return 全部可见且至少有一条信号返回 true。
@@ -391,20 +416,34 @@ namespace jdi
bool StepLineWidth(float delta);
/**
* @brief 展开自定义颜色面板并同步初始取色。
* @param [IN] style 当前信号样式。
* @return 界面状态发生变化返回 true。
* @brief 进入线宽数值输入状态。
* @return 状态发生变化返回 true。
*/
bool OpenColorPicker(const SignalStyle& style);
bool BeginWidthEdit();
HWND m_host = nullptr; /**< 宿主窗口句柄。 */
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
const Theme* m_theme = nullptr; /**< 主题资源。 */
PopupMenu* m_menu = nullptr; /**< 共用弹出菜单。 */
const DataSet* m_dataSet = nullptr; /**< 数据集合。 */
TabConfig* m_tab = nullptr; /**< 当前标签页配置。 */
float m_scale = 1.0f; /**< DPI 缩放比例。 */
gd::RectF m_clientBounds; /**< 宿主客户区矩形。 */
/**
* @brief 结束线宽数值输入状态。
* @param [IN] commit 是否提交输入值。
* @return 状态或取值发生变化返回 true。
*/
bool EndWidthEdit(bool commit);
/**
* @brief 调整当前信号不透明度。
* @param [IN] x 客户区横坐标。
* @return 取值发生变化返回 true。
*/
bool ApplyOpacityFromX(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; /**< 数据集合。 */
TabConfig* m_tab = nullptr; /**< 当前标签页配置。 */
float m_scale = 1.0f; /**< DPI 缩放比例。 */
gd::RectF m_clientBounds; /**< 宿主客户区矩形。 */
gd::RectF m_area; /**< 面板整体区域。 */
gd::RectF m_headerRect; /**< 标题区域。 */
@@ -415,7 +454,8 @@ namespace jdi
std::array<gd::RectF, 12> m_colorRects; /**< 预设颜色色块矩形。 */
int m_colorCount = 0; /**< 实际可用的预设颜色数量。 */
gd::RectF m_customChipRect; /**< 自定义颜色入口矩形。 */
gd::RectF m_customChipRect; /**< 自定义颜色入口矩形(与预设色块同尺寸)。 */
float m_swatchSize = 18.0f; /**< 颜色色块边长(逻辑像素)。 */
gd::RectF m_widthThinRect; /**< 最细线宽预设矩形。 */
gd::RectF m_widthThickRect; /**< 最粗线宽预设矩形。 */
@@ -426,10 +466,8 @@ namespace jdi
std::array<gd::RectF, 3> m_modeRects; /**< 绘制样式按钮矩形。 */
gd::RectF m_pickerRect; /**< 自定义颜色面板整体矩形。 */
std::array<gd::RectF, 3> m_sliderRects; /**< RGB 滑块轨道矩形。 */
gd::RectF m_pickerPreviewRect; /**< 自定义颜色预览矩形。 */
std::array<double, 3> m_pickerChannels = {0.0, 0.0, 0.0}; /**< 自定义颜色的 RGB 分量(0-1)。 */
gd::RectF m_opacityTrackRect; /**< 不透明度滑块轨道矩形。 */
gd::RectF m_opacityValueRect; /**< 不透明度数值文本矩形。 */
std::vector<ListRow> m_rows; /**< 列表行集合(惰性缓存)。 */
bool m_rowsDirty = true; /**< 列表行集合是否需要重建。 */
@@ -440,13 +478,20 @@ namespace jdi
float m_scrollOffset = 0.0f; /**< 列表滚动偏移量。 */
bool m_draggingScrollBar = false; /**< 是否正在拖拽滚动条。 */
int m_scrollGrabOffset = 0; /**< 拖拽时鼠标相对滑块顶部的偏移。 */
bool m_draggingOpacity = false; /**< 是否正在拖拽不透明度滑块。 */
int m_hoverRow = -1; /**< 当前悬停行。 */
RowPart m_hoverPart = RowPart::NONE; /**< 当前悬停的行内区域。 */
StyleHit m_hoverStyle = StyleHit::NONE; /**< 当前悬停的样式条目类型。 */
int m_hoverStyleIndex = -1; /**< 当前悬停的样式条目下标。 */
bool m_colorPickerOpen = false; /**< 自定义颜色面板是否展开。 */
int m_draggingSlider = -1; /**< 正在拖拽的滑块下标,-1 表示未拖拽。 */
bool m_widthEditing = false; /**< 线宽数值是否处于输入状态。 */
bool m_widthEditFresh = false; /**< 输入缓冲是否仍为初始值(首次键入应整体替换)。 */
std::wstring m_widthEditText; /**< 线宽输入缓冲。 */
bool m_pendingLaneMenu = false; /**< 左键抬起时是否弹出网格归属菜单。 */
SignalRef m_pendingLaneRef; /**< 待弹出菜单的目标信号。 */
bool m_pendingColorPicker = false; /**< 左键抬起时是否弹出拾色器。 */
bool m_layoutDirty = false; /**< 是否需要重新布局。 */
SignalRef m_menuTargetSignal; /**< 菜单操作的目标信号。 */
File diff suppressed because it is too large. Load diff