feat: 重构信号样式区并统一主题化弹出菜单
样式编辑区: - 移除顶部「样式 + 信号名 + 文件名」标题行,选中信号即代表编辑目标。 - 绘制方式取消阶梯选项,仅保留线段/散点/点线,标签由「方式」改为「样式」。 - 线宽改为「最细预设 + 数值旋钮 + 最粗预设」:中间为带左右增减箭头的输入框, 步进 0.2px,取值范围 0.5-6.0px,并标注单位为 px。 - 颜色在 10 个预设色块后新增带加号图标的方格,点击展开 RGB 三通道滑块面板, 可实时预览并显示十六进制值;点击面板外任意位置收起。 - 移除网格归属下拉框,改由每条信号行末尾的 G 徽标承载,点击弹出网格归属菜单。 信号面板与菜单: - 文件分组行新增关闭按钮,可直接从工作区移除该文件,与整体风格保持一致。 - 新增 PopupMenu 组件:绘制在窗口后备缓冲区内的自绘菜单,含圆角、投影、悬停高亮、 单选对勾、色块行与分组标题,彻底替换系统默认弹出菜单; 菜单打开期间接管鼠标与键盘(Esc / 上下键 / 回车),失焦或在菜单外释放时自动关闭。 - 信号、文件、网格、标签页四类右键菜单全部改用该组件。 其他修复: - 信号名称不再保留尾部单位括号,避免名称后再重复显示单位。 - 数据模型移除 DrawMode::STEP 枚举。 - 标签栏与信号面板弹出菜单后补充重绘请求,修复菜单不显示的问题。
This commit is contained in:
1 parent
9c6c374cce
commit
eb868b2679
12 files changed
+2148
-531
No files matched your search
@@ -18,8 +18,7 @@ namespace jdi
|
||||
{
|
||||
LINE = 0, /**< 相邻采样点之间以插值直线连接。 */
|
||||
SCATTER = 1, /**< 仅绘制采样点散点。 */
|
||||
LINE_SCATTER = 2, /**< 同时绘制插值直线与采样点散点。 */
|
||||
STEP = 3 /**< 阶梯保持(零阶保持)连线。 */
|
||||
LINE_SCATTER = 2 /**< 同时绘制插值直线与采样点散点。 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,17 @@ namespace jdi
|
||||
RIGHT = 2 /**< 右对齐。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 图标朝向。
|
||||
*/
|
||||
enum class IconDirection : int
|
||||
{
|
||||
LEFT = 0, /**< 指向左侧。 */
|
||||
RIGHT = 1, /**< 指向右侧。 */
|
||||
UP = 2, /**< 指向上方。 */
|
||||
DOWN = 3 /**< 指向下方。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 按 DPI 创建并缓存整套界面字体(GDI 字体句柄)。
|
||||
*/
|
||||
@@ -166,6 +177,61 @@ namespace jdi
|
||||
*/
|
||||
std::wstring UiEllipsize(gd::Graphics& g, const std::wstring& text, HFONT font, float maxWidth);
|
||||
|
||||
/**
|
||||
* @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] strokeWidth 线条宽度。
|
||||
* @param [IN] direction 箭头朝向。
|
||||
*/
|
||||
void UiDrawArrowIcon(gd::Graphics& g, const gd::RectF& rect, std::uint32_t argb, float strokeWidth,
|
||||
IconDirection direction);
|
||||
|
||||
/**
|
||||
* @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 将滑块轨道上的横坐标换算为取值比例。
|
||||
* @param [IN] trackRect 轨道矩形。
|
||||
* @param [IN] x 横坐标。
|
||||
* @return 取值比例,范围 0-1。
|
||||
*/
|
||||
double UiSliderRatioFromX(const gd::RectF& trackRect, float x);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
} // namespace jdi
|
||||
|
||||
#endif // __PAINT_UTIL_HPP__
|
||||
@@ -0,0 +1,222 @@
|
||||
#ifndef __POPUP_MENU_HPP__
|
||||
#define __POPUP_MENU_HPP__
|
||||
|
||||
#include <windows.h>
|
||||
#include <objidl.h>
|
||||
#include <gdiplus.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "PaintUtil.hpp"
|
||||
#include "Theme.hpp"
|
||||
|
||||
namespace jdi
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief 弹出菜单的打开来源,用于把选择结果派发回正确的组件。
|
||||
*/
|
||||
enum class MenuScope : int
|
||||
{
|
||||
NONE = 0, /**< 无来源。 */
|
||||
SIGNAL_PANEL = 1, /**< 信号面板。 */
|
||||
TAB_BAR = 2 /**< 标签栏。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 弹出菜单项的显示类型。
|
||||
*/
|
||||
enum class MenuItemKind : int
|
||||
{
|
||||
NORMAL = 0, /**< 普通可点击项。 */
|
||||
SEPARATOR = 1, /**< 分隔线。 */
|
||||
HEADER = 2, /**< 分组标题(不可点击)。 */
|
||||
SWATCHES = 3 /**< 颜色色块行。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 单个弹出菜单项。
|
||||
*/
|
||||
struct MenuItem
|
||||
{
|
||||
MenuItemKind kind = MenuItemKind::NORMAL; /**< 项目类型。 */
|
||||
std::wstring label; /**< 显示文本。 */
|
||||
int id = 0; /**< 命令标识。 */
|
||||
bool enabled = true; /**< 是否可用。 */
|
||||
bool checked = false; /**< 是否处于选中(单选)状态。 */
|
||||
int swatchCount = 0; /**< 色块数量(仅色块行有效)。 */
|
||||
std::uint32_t swatches[16] = {}; /**< 色块颜色。 */
|
||||
int checkedSwatch = -1; /**< 被选中的色块下标。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 菜单选择结果。
|
||||
*/
|
||||
struct MenuResult
|
||||
{
|
||||
bool valid = false; /**< 是否产生了有效选择。 */
|
||||
MenuScope scope = MenuScope::NONE; /**< 来源组件。 */
|
||||
int id = 0; /**< 被选中项的命令标识。 */
|
||||
int swatchIndex = -1; /**< 被选中的色块下标(非色块行为 -1)。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 与界面主题一致的自绘弹出菜单。
|
||||
*
|
||||
* 菜单不创建独立窗口,而是作为宿主窗口绘制流程的最上层内容直接绘制到后备缓冲区,
|
||||
* 因此外观与主界面完全统一,不会出现系统默认菜单样式。
|
||||
*/
|
||||
class PopupMenu
|
||||
{
|
||||
public:
|
||||
PopupMenu();
|
||||
|
||||
/**
|
||||
* @brief 绑定字体与主题资源。
|
||||
* @param [IN] fonts 字体集合,需在菜单生命周期内保持有效。
|
||||
* @param [IN] theme 主题配色,需在菜单生命周期内保持有效。
|
||||
*/
|
||||
void Setup(const UiFonts* fonts, const Theme* theme);
|
||||
|
||||
/**
|
||||
* @brief 设置 DPI 缩放比例。
|
||||
* @param [IN] scale 缩放比例(1.0 对应 96 DPI)。
|
||||
*/
|
||||
void SetScale(float scale);
|
||||
|
||||
/**
|
||||
* @brief 在指定位置打开菜单。
|
||||
* @param [IN] scope 来源组件标识。
|
||||
* @param [IN] bounds 宿主客户区矩形,用于把菜单限制在窗口内。
|
||||
* @param [IN] x 锚点横坐标(客户区坐标)。
|
||||
* @param [IN] y 锚点纵坐标(客户区坐标)。
|
||||
* @param [IN] items 菜单项集合。
|
||||
*/
|
||||
void Open(MenuScope scope, const gd::RectF& bounds, int x, int y, const std::vector<MenuItem>& items);
|
||||
|
||||
/**
|
||||
* @brief 关闭菜单。
|
||||
*/
|
||||
void Close();
|
||||
|
||||
/**
|
||||
* @brief 判断菜单是否处于打开状态。
|
||||
* @return 打开返回 true。
|
||||
*/
|
||||
bool IsOpen() const { return m_open; }
|
||||
|
||||
/**
|
||||
* @brief 获取当前菜单的来源组件标识。
|
||||
* @return 来源标识。
|
||||
*/
|
||||
MenuScope Scope() const { return m_scope; }
|
||||
|
||||
/**
|
||||
* @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 客户区纵坐标。
|
||||
* @param [OUT] result 在菜单外按下时返回被取消的选择结果。
|
||||
* @return 事件已被菜单消费返回 true。
|
||||
*/
|
||||
bool OnLButtonDown(int x, int y, MenuResult& result);
|
||||
|
||||
/**
|
||||
* @brief 处理鼠标左键抬起。
|
||||
* @param [IN] x 客户区横坐标。
|
||||
* @param [IN] y 客户区纵坐标。
|
||||
* @param [OUT] result 选择结果。
|
||||
* @return 事件已被菜单消费返回 true。
|
||||
*/
|
||||
bool OnLButtonUp(int x, int y, MenuResult& result);
|
||||
|
||||
/**
|
||||
* @brief 处理键盘按键。
|
||||
* @param [IN] key 虚拟键码。
|
||||
* @param [OUT] result 选择结果。
|
||||
* @return 事件已被菜单消费返回 true。
|
||||
*/
|
||||
bool OnKeyDown(WPARAM key, MenuResult& result);
|
||||
|
||||
/**
|
||||
* @brief 判断坐标是否落在菜单内部。
|
||||
* @param [IN] x 客户区横坐标。
|
||||
* @param [IN] y 客户区纵坐标。
|
||||
* @return 落在菜单内返回 true。
|
||||
*/
|
||||
bool ContainsPoint(int x, int y) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 计算单个菜单项的纵向高度。
|
||||
* @param [IN] item 菜单项。
|
||||
* @return 高度(像素)。
|
||||
*/
|
||||
float ItemHeight(const MenuItem& item) const;
|
||||
|
||||
/**
|
||||
* @brief 依据当前项目集合计算整体矩形与各项矩形。
|
||||
* @param [IN] bounds 宿主客户区矩形。
|
||||
* @param [IN] x 锚点横坐标。
|
||||
* @param [IN] y 锚点纵坐标。
|
||||
*/
|
||||
void BuildLayout(const gd::RectF& bounds, int x, int y);
|
||||
|
||||
/**
|
||||
* @brief 查询坐标命中的菜单项下标。
|
||||
* @param [IN] x 客户区横坐标。
|
||||
* @param [IN] y 客户区纵坐标。
|
||||
* @param [OUT] swatchIndex 命中的色块下标(非色块行为 -1)。
|
||||
* @return 项目下标,未命中返回 -1。
|
||||
*/
|
||||
int ItemAtPoint(int x, int y, int& swatchIndex) const;
|
||||
|
||||
/**
|
||||
* @brief 将悬停项移动到下一个可用项。
|
||||
* @param [IN] step 步进(+1 向下,-1 向上)。
|
||||
*/
|
||||
void MoveHover(int step);
|
||||
|
||||
/**
|
||||
* @brief 确认当前悬停项并生成结果。
|
||||
* @param [OUT] result 选择结果。
|
||||
* @return 生成了有效选择返回 true。
|
||||
*/
|
||||
bool CommitHover(MenuResult& result);
|
||||
|
||||
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
|
||||
const Theme* m_theme = nullptr; /**< 主题资源。 */
|
||||
float m_scale = 1.0f; /**< DPI 缩放比例。 */
|
||||
|
||||
bool m_open = false; /**< 是否处于打开状态。 */
|
||||
MenuScope m_scope = MenuScope::NONE; /**< 来源组件标识。 */
|
||||
std::vector<MenuItem> m_items; /**< 菜单项集合。 */
|
||||
|
||||
gd::RectF m_rect; /**< 菜单整体矩形。 */
|
||||
std::vector<gd::RectF> m_itemRects; /**< 各项矩形。 */
|
||||
std::vector<std::vector<gd::RectF>> m_swatchRects; /**< 各项内的色块矩形。 */
|
||||
|
||||
int m_hoverIndex = -1; /**< 当前悬停项。 */
|
||||
int m_hoverSwatch = -1; /**< 当前悬停色块。 */
|
||||
int m_pressedIndex = -1; /**< 按下时的项目下标。 */
|
||||
int m_pressedSwatch = -1; /**< 按下时的色块下标。 */
|
||||
};
|
||||
|
||||
} // namespace jdi
|
||||
|
||||
#endif // __POPUP_MENU_HPP__
|
||||
Reference in new issue
Block a user