#ifndef __UI_CONTROLS_HPP__ #define __UI_CONTROLS_HPP__ #include #include #include #include #include #include #include "PaintUtil.hpp" #include "TextEdit.hpp" namespace jdi { /** * @brief 通用 UI 控件(属于 `Components/Shared`)。 * * 这些控件的绘制 / 命中逻辑被**多个功能组件复用**(信号面板的行与样式区、绘图区的 * 浮动面板与取值胶囊、工具栏、标签栏、弹出菜单、拾色器),因此在共享组件中集中实现, * 而不是散落在各自的实现文件里。 * * 依赖方向:`Components/Shared` → `Utilities`(只使用 `PaintUtil` 提供的低层绘制原语), * 绝不反向依赖任何功能组件。 */ /** * @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] direction 三角形朝向。 */ void UiDrawTriangleIcon(gd::Graphics& g, const gd::RectF& rect, std::uint32_t argb, IconDirection direction); /** * @brief 颜色的相对亮度(0-1,逐通道线性加权)。 * @param [IN] color 0xAARRGGBB 颜色值。 * @return 相对亮度。 */ double UiColorLuminance(std::uint32_t color); /** * @brief 取值胶囊底色上的高对比度文字色与描边色。 */ struct UiInk { std::uint32_t text = 0xFF073642u; /**< 文字色(不透明)。 */ std::uint32_t outline = 0x99FDF6E3u; /**< 描边色(半透明,恒与文字色反相)。 */ }; /** * @brief 依据胶囊底色求高对比度的文字色与描边色(对底色配色作线性响应)。 * * 求值分两步: * 1. **亮度**:按"取最大对比"的一侧选定亮文字或暗文字。这是唯一的阈值判断,但它 * 本身就是"任意底色下都保持高对比"的必要条件 —— 任何连续的亮度取值都会在中性灰 * 附近同时远离两侧极值,对比度必然塌陷。 * 2. **配色**:把该侧的极值色与**底色的互补色**按固定比例线性混合。互补色的相对亮度 * 恰为 `1 - 底色亮度`,因此文字/描边的亮度是底色亮度的**线性**函数,色相也随信号 * 配色连续变化(不再是固定的黑/白两色)。 * * 描边色取相反的一侧,保证"描边—文字—底色"三段式对比。 * * @param [IN] background 胶囊底色(0xAARRGGBB)。 * @return 文字色与描边色。 */ UiInk UiContrastInk(std::uint32_t background); /** * @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] track 轨道矩形。 * @param [IN] ratio 当前值比例(0-1)。 * @param [IN] fillColor 已填充部分颜色。 * @param [IN] active 是否处于悬停或拖拽状态(影响圆钮半径)。 * @param [IN] scale DPI 缩放比例。 */ void UiDrawSlider(gd::Graphics& g, const gd::RectF& track, double ratio, std::uint32_t fillColor, bool active, float scale); /** * @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); /** * @brief 计算输入框文本的绘制起点(已考虑超出框宽时的水平滚动)。 * @param [IN] rect 输入框矩形。 * @param [IN] edit 编辑模型。 * @param [IN] font 字体句柄。 * @param [IN] scale 缩放比例。 * @param [OUT] innerWidth 框内可用宽度输出。 * @return 文本绘制起点横坐标。 */ float UiEditTextLeft(const gd::RectF& rect, const TextEdit& edit, HFONT font, float scale, float& innerWidth); /** * @brief 把输入框内的横坐标换算为字符偏移(就近取整,用于鼠标定位插入符)。 * @param [IN] font 字体句柄。 * @param [IN] text 当前文本。 * @param [IN] localX 相对文本起点的横坐标(可超出 [0, 文本宽度])。 * @return 字符偏移。 */ std::size_t UiEditOffsetAt(HFONT font, const std::wstring& text, float localX); /** * @brief 绘制单行内联输入框(含选区高亮、插入符与水平滚动)。 * * 初始状态为“整体选中”时以强调色底衬显示全部内容,首字符键入即整体替换, * 交互观感与常见登录界面的账号/密码输入框一致;文本超出框宽时自动横向滚动, * 保证插入符始终可见。 * * @param [IN,OUT] g 绘图上下文。 * @param [IN] rect 输入框矩形。 * @param [IN] edit 输入框编辑模型。 * @param [IN] font 文本字体。 * @param [IN] scale DPI 缩放比例。 */ void UiDrawEditField(gd::Graphics& g, const gd::RectF& rect, const TextEdit& edit, HFONT font, float scale); /** * @brief 只绘制输入框的**内容**(选区高亮 / 文本 / 插入符),不绘制底板与边框。 * * 用于"宿主已经画好了外框"的场景(例如信号面板的「筛选信号」输入框):若直接调用 * UiDrawEditField,会在外框内部再套一个带边框的圆角框,形成一圈多余的内圈。 * * @param [IN,OUT] g 绘图上下文。 * @param [IN] rect 输入框矩形(内容区,几何与 UiDrawEditField 完全一致)。 * @param [IN] edit 输入框编辑模型。 * @param [IN] font 文本字体。 * @param [IN] scale DPI 缩放比例。 */ void UiDrawEditFieldContent(gd::Graphics& g, const gd::RectF& rect, const TextEdit& edit, HFONT font, float scale); /** * @brief 处理输入框内的鼠标按下:命中则把插入符定位到最近的字符边界并开始拖拽框选。 * @param [IN] font 字体句柄。 * @param [IN] rect 输入框矩形。 * @param [IN,OUT] edit 编辑模型。 * @param [IN] scale 缩放比例。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @return 命中输入框并开始拖拽返回 true。 */ bool UiEditFieldMouseDown(HFONT font, const gd::RectF& rect, TextEdit& edit, float scale, int x, int y); /** * @brief 处理输入框内的鼠标拖拽移动(扩展选区)。 * @param [IN] font 字体句柄。 * @param [IN] rect 输入框矩形。 * @param [IN,OUT] edit 编辑模型。 * @param [IN] scale 缩放比例。 * @param [IN] x 客户区横坐标。 * @return 选区发生变化返回 true。 */ bool UiEditFieldMouseMove(HFONT font, const gd::RectF& rect, TextEdit& edit, float scale, int x); /** * @brief 判断给定不透明度是否低到需要为样块补充描边。 * @param [IN] opacity 不透明度(0-1)。 * @return 需要描边返回 true。 */ bool UiSwatchNeedsOutline(float opacity); /** * @brief 绘制颜色样块:叠加不透明度填充,透明度过低时补充描边以保证可辨识。 * @param [IN,OUT] g 绘图上下文。 * @param [IN] rect 样块矩形。 * @param [IN] color 基础颜色(0xAARRGGBB,其 Alpha 通道会被不透明度覆盖)。 * @param [IN] opacity 不透明度(0-1)。 * @param [IN] radius 圆角半径。 * @param [IN] scale DPI 缩放比例,用于推导描边粗细。 * @return 实际填充颜色的 0xAARRGGBB 值(供需要同步其他元素的调用方使用)。 */ std::uint32_t UiDrawSwatch(gd::Graphics& g, const gd::RectF& rect, std::uint32_t color, float opacity, float radius, float scale); } // namespace jdi #endif // __UI_CONTROLS_HPP__