Files
Just-DataInspector/Utilities/Inc/ColorPickerPopup.hpp
T
DeepSeek V4.1 Flash 53768b8b25 fix: 统一输入框编辑能力、修复拖拽合并网格并支持光标吸附数据点
统一文本输入(新增 Utilities/Inc/TextEdit.hpp + TextEdit.cpp)
- 一个共享的编辑模型,提供光标/选区/过滤/限长,接入全部输入框:
  样式区数值与信号名/分组名、波形图例改名、视图标签页改名、
  拾色器 R/G/B 与色号、光标时间与网格上下限。
- 新增能力:Ctrl+A/C/X/V(含剪贴板清洗)、Shift+方向键与 Home/End 选区、
  退格与删除清除选区、代理对安全的光标步进。
- 渲染改为选区高亮 + 插入符,文本超出框宽时水平滚动并让插入符始终可见;
  初始态为整段选中,首字符键入即整体替换(保持"登录框"式交互)。
- 新增 Utf8Util::PasteTextFromClipboard(换行/制表符折叠为空格)。

修复网格合并(Utilities/Src/DataModel.cpp)
- 拖拽信号到其它网格时先固定目标网格的锚信号,再移除源信号并按引用找回目标,
  避免空网格回收导致下标错位,从"与原网格交换位置"改为真正合并。
- 自定义划分下未分配网格的可见信号改为各自独占一个新网格,
  修复"拖拽合并后再勾选新信号被并入该合并网格"的问题。

绘图区(Components/PlotView)
- 网格右键菜单新增"时间轴自适应(匹配本网格)",把时间轴对齐到该网格信号范围。
- 时间轴放大到采样点在屏幕上可分辨(>=6 逻辑像素)时,拖动光标吸附到最近数据点;
  缩小到无法分辨时保持自由移动,避免光标"跳格"。

验证:真实输入脚本逐项核对——拖拽合并后单网格含两条曲线、拖拽合并再勾选新信号得 G2 独立网格、
Shift 选区 + Delete 清除、Ctrl+A/C/V 复制粘贴、46 字符文本水平滚动、拾色器色号 1E90FF、
标签页改名 A1、光标时间框复制粘贴、全视图拖动得 0.522213(不吸附)而放大后得 0.28125(= 225 × 0.00125,已吸附)。
2026-09-30 13:40:58 +08:00

223 lines
6.7 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 设置剪贴板所有者窗口句柄(用于输入框的复制/粘贴)。
* @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__