Files
Just-DataInspector/Utilities/Inc/ColorPickerPopup.hpp
T
DeepSeek V4.1 Flash e3744f3eff fix: 统一输入框编辑行为、外观跨视图同步并优化标尺与网格可读性
输入框(TextEdit,全组件共用):
- 修复退格一次删除两个字符:WM_CHAR 与 WM_KEYDOWN 重复处理了退格/删除,
  现统一由 OnEditKey 处理,WM_CHAR 忽略全部控制字符。
- 进入编辑(整段选中)后按右键:取消全选并把插入符移到文本最右侧。
- 存在选区时松开 Shift 再按左右方向键,插入符收拢到选区的左/右端。
- 修复整段选中后按 Home/End 不收拢选区的问题。

标签页:
- 按加粗字体测量宽度,避免激活页长名称被提前省略(预览过短)。
- 重命名过程中按正在输入的文本测量并加宽上限(320px),标签随输入增长,
  解决长内容绘制错误;输入溢出时整体等比收缩,保证「+」始终可见。

信号显示外观跨标签页同步:
- 外观(颜色/自定义色记忆/透明度/线宽/样式)从 TabConfig 上移到 DataSet
  的 SignalData,成为信号的全局属性;可见性仍按标签页独立保存。
- 因此任一视图中修改某信号的颜色/线宽/透明度/样式,其它视图自动一致。

工具栏:
- 移除「全选信号」按钮;「清空勾选」改为「清空网格」,
  「拆分信号网格」改为「拆分网格」。

自适应:
- 无可见信号(未勾选/全部取消/清空网格)时复位 ViewInitialized,
  下次勾选第一个信号会重新自适应,而不是停留在旧视图范围。

绘图区标尺与网格:
- 幅值刻度密度按网格高度自适应(3-8 档),各网格刻度数量一致;
  网格较矮时同步收紧标签行距,提高可读密度。
- 网格线与五等分估读线加深,与网格边界(蓝灰)保持明显区分。
- 时间轴列名补上单位,显示为 time (s)。
2026-09-30 15:16:53 +08:00

229 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef __COLOR_PICKER_POPUP_HPP__
#define __COLOR_PICKER_POPUP_HPP__
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <array>
#include <cstdint>
#include "PaintUtil.hpp"
#include "Theme.hpp"
namespace jdi
{
/**
* @brief 浮动式 RGB 自定义颜色拾取器。
*
* 与弹出菜单一致,不创建独立窗口,而是作为宿主绘制的最后一步直接画到后备缓冲区,
* 以浮动面板的形式出现在触发控件附近;取值变化实时生效,点击面板外部即收起。
*/
class ColorPickerPopup
{
public:
ColorPickerPopup();
/**
* @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] bounds 宿主客户区矩形,用于把面板限制在窗口内。
* @param [IN] anchor 触发控件矩形(客户区坐标),面板会紧贴其下方或上方展开。
* @param [IN] color 初始颜色(0xAARRGGBB,仅取 RGB 分量)。
*/
void Open(const gd::RectF& bounds, const gd::RectF& anchor, std::uint32_t color);
/**
* @brief 关闭拾色面板。
*/
void Close();
/**
* @brief 判断拾色面板是否处于打开状态。
* @return 打开返回 true。
*/
bool IsOpen() const { return m_open; }
/**
* @brief 获取当前取色结果。
* @return 0xAARRGGBB 颜色值(Alpha 固定为不透明)。
*/
std::uint32_t CurrentColor() const;
/**
* @brief 取出并清除“取值已变化”标记。
* @param [OUT] color 变化后的颜色。
* @return 自上次调用以来取值发生过变化返回 true。
*/
bool TakeChanged(std::uint32_t& color);
/**
* @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 处理鼠标左键抬起。
* @return 需要重绘返回 true。
*/
bool OnLButtonUp();
/**
* @brief 处理键盘按键(Esc 收起、回车提交输入)。
* @param [IN] key 虚拟键码。
* @return 事件已被消费返回 true。
*/
bool OnKeyDown(WPARAM key);
/**
* @brief 处理字符输入。
* @param [IN] character 输入字符('\r' 提交、'\b' 退格、0x03 复制)。
* @return 界面状态发生变化返回 true。
*/
bool OnChar(wchar_t character);
/**
* @brief 判断面板是否处于内联文本输入状态。
* @return 正在输入返回 true。
*/
bool IsEditing() const { return m_editField != EditField::NONE; }
/**
* @brief 编辑态下按下鼠标右键:取消选区并把插入符移到文本末尾。
* @return 发生改变返回 true;不在编辑态返回 false。
*/
bool CollapseEditSelectionToEnd();
/**
* @brief 设置剪贴板所有者窗口句柄(用于输入框的复制/粘贴)。
* @param [IN] owner 宿主窗口句柄,允许为空。
*/
void SetOwnerWindow(HWND owner) { m_owner = owner; }
/**
* @brief 判断坐标是否落在拾色面板内部。
* @param [IN] x 客户区横坐标。
* @param [IN] y 客户区纵坐标。
* @return 落在内部返回 true。
*/
bool ContainsPoint(int x, int y) const;
/**
* @brief 查询该坐标应使用的系统光标。
* @param [IN] x 客户区横坐标。
* @param [IN] y 客户区纵坐标。
* @return 系统光标句柄;面板未打开时返回空指针。
*/
HCURSOR QueryCursor(int x, int y) const;
private:
/**
* @brief 面板内可进行内联文本输入的字段。
*/
enum class EditField : int
{
NONE = 0, /**< 未处于编辑状态。 */
R = 1, /**< 红色分量(0-255)。 */
G = 2, /**< 绿色分量(0-255)。 */
B = 3, /**< 蓝色分量(0-255)。 */
HEX = 4 /**< 十六进制色号。 */
};
/**
* @brief 依据锚点矩形与客户区计算面板矩形与内部控件矩形。
* @param [IN] bounds 宿主客户区矩形。
* @param [IN] anchor 触发控件矩形。
*/
void BuildLayout(const gd::RectF& bounds, const gd::RectF& anchor);
/**
* @brief 进入指定字段的内联输入状态。
* @param [IN] field 目标字段。
* @return 状态发生变化返回 true。
*/
bool BeginEdit(EditField field);
/**
* @brief 结束内联输入状态。
* @param [IN] commit 是否提交输入值。
* @return 状态发生变化返回 true。
*/
bool EndEdit(bool commit);
/**
* @brief 计算当前输入框的矩形。
* @return 输入框矩形。
*/
gd::RectF EditFieldRect() const;
/**
* @brief 查询坐标命中的滑块下标。
* @param [IN] x 客户区横坐标。
* @param [IN] y 客户区纵坐标。
* @return 滑块下标(0=R,1=G,2=B),未命中返回 -1。
*/
int SliderAtPoint(int x, int y) const;
/**
* @brief 应用滑块拖拽位置到对应通道。
* @param [IN] index 滑块下标。
* @param [IN] x 客户区横坐标。
*/
void ApplySlider(int index, float x);
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
const Theme* m_theme = nullptr; /**< 主题资源。 */
HWND m_owner = nullptr; /**< 剪贴板所有者窗口句柄。 */
float m_scale = 1.0f; /**< DPI 缩放比例。 */
bool m_open = false; /**< 是否处于打开状态。 */
bool m_changed = false; /**< 取值是否发生变化。 */
int m_draggingSlider = -1; /**< 正在拖拽的滑块下标,-1 表示未拖拽。 */
int m_hoverSlider = -1; /**< 当前悬停的滑块下标。 */
std::array<double, 3> m_channels = {0.0, 0.0, 0.0}; /**< RGB 分量(0-1)。 */
gd::RectF m_rect; /**< 面板整体矩形。 */
gd::RectF m_titleRect; /**< 标题区域。 */
std::array<gd::RectF, 3> m_tracks; /**< 滑块轨道矩形。 */
std::array<gd::RectF, 3> m_values; /**< 数值文本矩形。 */
gd::RectF m_previewRect; /**< 预览色块矩形。 */
gd::RectF m_hexRect; /**< 十六进制文本矩形。 */
EditField m_editField = EditField::NONE; /**< 当前处于输入状态的字段。 */
TextEdit m_edit; /**< 输入框编辑模型(光标/选区/剪贴板)。 */
};
} // namespace jdi
#endif // __COLOR_PICKER_POPUP_HPP__