一、命名(用户要求) - 实验性功能里的「阶数 N」全部改为「迭代次数 N」(面板滑块标签、均值滤波/中心轴 的数值框标签、构建提示语)。 - 相关标识符与函数参数统一改名:order → iterations(Lane::MeanFilterItem::iterations、 Lane::weakBoostIterations、ComputeWeakWaveBoost/ComputeMovingAverageIterated 的形参、 MeanFilterCurveFor/WeakBoostCurveFor/WeakBoostValueAt/EdgeCenterCountsFor、 各曲线缓存项的字段、EdgePanelLayout::rowIterations/sliderIterations、 PlotEditTarget::MEAN_FILTER_ITERATIONS/EDGE_CENTER_ITERATIONS、 PlotDragMode::BOOST_ITERATIONS、kWeakBoostIterationsMin/Max/Label、 DerivedSignalRequest::iterations 等)。网格拖拽重排里的局部 order 为避免歧义 改名为 laneOrder;`std::memory_order_*`、`rowOrder`→`rowIterations` 一并核对无误。 - 导出信号尾缀统一为「N次迭代」: `<原信号> (N点均值 M次迭代)`、`<原信号> (弱波增强 X% M次迭代)`; 弱波增强此前缺失该信息,现已补上(两种派生信号都恒定带迭代次数)。 状态提示语同步为「… M 次迭代信号。」。 二、越界三角与光标读数的样式统一(用户要求) - 新增 `kMarkerTriangleGap`:网格内数据点越界时,方向三角与数值标注之间**留出间隙** (此前三角与胶囊贴在一起,看起来像胶囊上多出的尖角);中心轴/均值滤波/弱波增强的 派生取值标注同样处理。 - 光标时间读数(以及双光标 Δt 读数)改用与网格内数据点**完全一致**的越界样式: 三角画在胶囊**外侧**、尖端朝外、与胶囊之间留出同样的间隙;为此把读数胶囊在越界一侧 向内让出「三角深度 + 间隙」。旧的"三角压在胶囊上沿"的画法以及为它额外留出的叠放 间距(kCursorTipStackGap)一并删除。 三、大文件放大后"平移 / 改配色非常卡"的根因与修复(用户要求,流畅性优先) 用离屏探针(`.preflight/perf3`)在 VERY_BIG_DATA(1.77GB、2580 万采样 × 5 信号、 1224×796 绘图区)上先量化,实测到的三个根因: 1. **包络带"梳状化"**:当信号的振荡周期与像素列宽度相当时(编码器方波在 2ms/大格下 约 3 个采样点一列),逐列包络会在"全高"与"极窄"之间交替——实测 1224 列里有 988 处 全高跳变。这种多边形让 GDI+ 的扫描线填充耗时暴涨:同一条 2448 顶点的路径 **27.6ms → 1.1ms(±1 列极值扩展后快 25 倍)**。这正是"某些放大等级下平移特别卡" (实测 2ms/大格平移 87ms,其余等级 17~20ms)的原因。 → `EmitEnvelopeBand` 在拼装包络带时对列窗口做 ±1 列的极值扩展(纵向最多各多 1 像素, 肉眼不可辨),一次性消除该病理。 2. **派生预览曲线按折线逐段描边**:均值滤波/弱波增强曲线在可见采样数超过像素列数时 仍按"每 2 像素一个顶点"的抗锯齿折线绘制,而这类曲线常叠在方波上(大量近垂直跳变), 实测单条 12~42ms,5 个网格合计上百毫秒。 → 稠密时改用**逐像素列的包络带**(复用 `EmitEnvelopeBand`)一次 FillPath,实测 0.56ms / 1.53ms(分别快 22 倍 / 28 倍),视觉与细折线一致(列宽就是 1 像素)。 3. **悬停光晕用宽笔描整条折线**:实测悬停一帧多花 35ms。 → 包络带模式下改为"把带整体外扩后填充一次"(`PaintBandHalo`),悬停帧恢复正常。 另外修掉两个相关的固定开销: - `UiMeasureTextWidth` 增加 (字体, 文本) 记忆化缓存:它是布局代码的热点(浮动面板几何 按「网格数 × 面板种类」重复计算,每帧重复测量同一批字符串成百上千次),实测单个面板 的绘制因此从 3.2ms 降到 1ms 量级。字体重建(DPI 变化)时由 `UiClearMeasureCache` 作废。 实测(VERY_BIG_DATA 全选 5 信号,绘图区全重绘 = 平移一帧): - 20ms/大格(用户报告的场景):平移 20.1ms → **11.3ms**; - 2ms/大格(此前最糟):平移 86.7ms → **12.3ms**; - 网格 1 开弱波增强:63.9ms → **17.6ms**;5 个网格全开:136.6ms → **31.9ms**; - 悬停信号:整帧 49.6ms → **15.5ms**(与不悬停持平,光晕几乎免费)。 仍存的已知热点:0.5ms/大格附近(可见约 1000 个采样点、走**逐点描边**路径)平移约 28~39ms —— 该区间采样比像素还稀疏、无法用包络带替代,且用户明确要求保留抗锯齿, 本次未动。 四、验证 - 离屏 harness(窗口 SW_HIDE、不占用鼠标/键盘/屏幕)**355 项检查全部通过**, 新增 `[AD]`:越界读数胶囊向内让位、三角在外侧、三角与胶囊间有真实间隙、 胶囊上方不再有内容;取值标注与三角之间保留 `kMarkerTriangleGap` 的间隙(用 散点模式排除波形干扰后逐像素断言)。`[X]/[Y]/[AA]/[AB]/[Z]` 等既有用例同步通过。 - 性能结论来自 `.preflight/perf3`(离屏探针 + 两套微基准),已随任务清理。
417 lines
16 KiB
C++
417 lines
16 KiB
C++
#ifndef __PAINT_UTIL_HPP__
|
||
#define __PAINT_UTIL_HPP__
|
||
|
||
#include <windows.h>
|
||
#include <objidl.h>
|
||
#include <gdiplus.h>
|
||
|
||
#include <cstddef>
|
||
#include <cstdint>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
#include "TextEdit.hpp"
|
||
#include "Theme.hpp"
|
||
|
||
namespace jdi
|
||
{
|
||
|
||
/**
|
||
* @brief 文本水平对齐方式(垂直方向始终居中)。
|
||
*/
|
||
enum class TextAlign : int
|
||
{
|
||
LEFT = 0, /**< 左对齐。 */
|
||
CENTER = 1, /**< 水平居中。 */
|
||
RIGHT = 2 /**< 右对齐。 */
|
||
};
|
||
|
||
/**
|
||
* @brief 图标朝向。
|
||
*/
|
||
enum class IconDirection : int
|
||
{
|
||
LEFT = 0, /**< 指向左侧。 */
|
||
RIGHT = 1, /**< 指向右侧。 */
|
||
UP = 2, /**< 指向上方。 */
|
||
DOWN = 3 /**< 指向下方。 */
|
||
};
|
||
|
||
/**
|
||
* @brief 按 DPI 创建并缓存整套界面字体(GDI 字体句柄)。
|
||
*/
|
||
struct UiFonts
|
||
{
|
||
HFONT ui = nullptr; /**< 常规界面字体。 */
|
||
HFONT uiBold = nullptr; /**< 加粗界面字体。 */
|
||
HFONT uiSmall = nullptr; /**< 小号界面字体。 */
|
||
HFONT uiSmallBold = nullptr;/**< 小号加粗界面字体。 */
|
||
HFONT title = nullptr; /**< 标题字体。 */
|
||
HFONT mono = nullptr; /**< 等宽数值字体。 */
|
||
HFONT monoSmall = nullptr; /**< 小号等宽字体。 */
|
||
UINT dpi = 96; /**< 创建时所使用的 DPI。 */
|
||
|
||
/**
|
||
* @brief 依据 DPI 创建全部字体。
|
||
* @param [IN] dpi 目标 DPI(96 对应 100% 缩放)。
|
||
* @return 创建成功返回 true。
|
||
*/
|
||
bool Create(UINT dpi);
|
||
|
||
/**
|
||
* @brief 释放全部字体句柄。
|
||
*/
|
||
void Destroy();
|
||
|
||
~UiFonts() { Destroy(); }
|
||
};
|
||
|
||
/**
|
||
* @brief 将 0xAARRGGBB 颜色值转换为 GDI COLORREF。
|
||
* @param [IN] argb 颜色值。
|
||
* @return GDI 颜色值。
|
||
*/
|
||
inline COLORREF ToColorRef(std::uint32_t argb)
|
||
{
|
||
return RGB((argb >> 16) & 0xFFu, (argb >> 8) & 0xFFu, argb & 0xFFu);
|
||
}
|
||
|
||
/**
|
||
* @brief 判断点是否落在矩形内部。
|
||
* @param [IN] rect 目标矩形。
|
||
* @param [IN] x 横坐标。
|
||
* @param [IN] y 纵坐标。
|
||
* @return 落在内部返回 true。
|
||
*/
|
||
inline bool UiPointInRect(const gd::RectF& rect, float x, float y)
|
||
{
|
||
return x >= rect.X && x <= (rect.X + rect.Width) && y >= rect.Y && y <= (rect.Y + rect.Height);
|
||
}
|
||
|
||
/**
|
||
* @brief 填充矩形区域。
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] rect 目标矩形。
|
||
* @param [IN] argb 填充颜色。
|
||
*/
|
||
void UiFillRect(gd::Graphics& g, const gd::RectF& rect, std::uint32_t argb);
|
||
|
||
/**
|
||
* @brief 填充圆角矩形区域。
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] rect 目标矩形。
|
||
* @param [IN] radius 圆角半径。
|
||
* @param [IN] argb 填充颜色。
|
||
*/
|
||
void UiFillRoundRect(gd::Graphics& g, const gd::RectF& rect, float radius, std::uint32_t argb);
|
||
|
||
/**
|
||
* @brief 描边圆角矩形。
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] rect 目标矩形。
|
||
* @param [IN] radius 圆角半径。
|
||
* @param [IN] argb 线条颜色。
|
||
* @param [IN] width 线条宽度。
|
||
*/
|
||
void UiDrawRoundRect(gd::Graphics& g, const gd::RectF& rect, float radius, std::uint32_t argb, float width);
|
||
|
||
/**
|
||
* @brief 绘制一条直线。
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] x1 起点横坐标。
|
||
* @param [IN] y1 起点纵坐标。
|
||
* @param [IN] x2 终点横坐标。
|
||
* @param [IN] y2 终点纵坐标。
|
||
* @param [IN] argb 线条颜色。
|
||
* @param [IN] width 线条宽度。
|
||
*/
|
||
void UiDrawLine(gd::Graphics& g, float x1, float y1, float x2, float y2, std::uint32_t argb, float width);
|
||
|
||
/**
|
||
* @brief 在指定矩形内绘制单行文本(垂直居中,超长自动省略)。
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] text 文本内容。
|
||
* @param [IN] font 字体句柄。
|
||
* @param [IN] rect 文本布局矩形。
|
||
* @param [IN] argb 文本颜色。
|
||
* @param [IN] align 水平对齐方式。
|
||
*/
|
||
void UiText(gd::Graphics& g, const std::wstring& text, HFONT font, const gd::RectF& rect, std::uint32_t argb,
|
||
TextAlign align = TextAlign::LEFT);
|
||
|
||
/**
|
||
* @brief 测量单行文本的像素宽度(无需 GDI+ 上下文,可在布局阶段调用)。
|
||
* @param [IN] font 字体句柄。
|
||
* @param [IN] text 文本内容。
|
||
* @return 文本像素宽度。
|
||
*/
|
||
float UiMeasureTextWidth(HFONT font, const std::wstring& text);
|
||
|
||
/**
|
||
* @brief 在指定裁剪矩形内以显式起点绘制一段文本(使用 GDI ExtTextOut 裁剪)。
|
||
*
|
||
* `UiText` 走 `DrawTextW`,**不遵循 GDI+ 裁剪区**;输入框在长内容、水平滚动的情况下
|
||
* 会把字符画到框体之外。本函数用 `ETO_CLIPPING` 让 GDI 自己裁剪,彻底避免越界绘制。
|
||
*
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] text 文本内容。
|
||
* @param [IN] font 字体句柄。
|
||
* @param [IN] x 文本起始横坐标。
|
||
* @param [IN] rect 垂直居中参考矩形。
|
||
* @param [IN] argb 文本颜色。
|
||
* @param [IN] clipRect 裁剪矩形(超出部分不绘制)。
|
||
*/
|
||
void UiTextAtClipped(gd::Graphics& g, const std::wstring& text, HFONT font, float x, const gd::RectF& rect,
|
||
std::uint32_t argb, const gd::RectF& clipRect);
|
||
|
||
/**
|
||
* @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] text 原始文本。
|
||
* @param [IN] font 字体句柄。
|
||
* @param [IN] maxWidth 允许的最大像素宽度。
|
||
* @return 截断后的文本。
|
||
*/
|
||
std::wstring UiEllipsize(const std::wstring& text, HFONT font, float maxWidth);
|
||
|
||
/**
|
||
* @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,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 用 GDI 一次性绘制若干条**不透明 1px 实线**(每条线段相互独立)。
|
||
*
|
||
* 性能关键:GDI+ 的 `DrawLine` 实测每条约 0.1–0.19 ms(带抗锯齿的长线更慢),
|
||
* 而一张网格通常要画几十条网格线 —— 逐条调用会让单帧多花十几毫秒。
|
||
* 这里改用 GDI(一次取 HDC + 一支画笔 + 多个 LineTo),快一两个数量级,
|
||
* 而且像素级网格线本来就不需要抗锯齿,观感反而更清晰。
|
||
*
|
||
* ⚠️ GDI 绘制**不受 GDI+ 裁剪区约束**,因此必须显式传入裁剪矩形
|
||
* (内部用 `SaveDC` + `IntersectClipRect` 保证不越界)。
|
||
* ⚠️ 只能用于**不透明**颜色(GDI 不做 alpha 混合);半透明色需调用方先与底色混合。
|
||
*
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] clip 裁剪矩形(客户区坐标)。
|
||
* @param [IN] segments 线段数组,每 4 个 float 为一条(x1,y1,x2,y2)。
|
||
* @param [IN] segmentCount 线段数量。
|
||
* @param [IN] argb 颜色(Alpha 必须为 0xFF,否则不做任何绘制)。
|
||
* @param [IN] width 线宽(像素,>= 1;仅精确支持 1,更宽时按整数宽画)。
|
||
*/
|
||
void UiDrawSolidLines(gd::Graphics& g, const gd::RectF& clip, const float* segments,
|
||
std::size_t segmentCount, std::uint32_t argb, int width = 1);
|
||
|
||
/**
|
||
* @brief 把半透明颜色与已知不透明底色混合,得到可直接用于 GDI 的不透明颜色。
|
||
* @param [IN] background 不透明底色(0xFFRRGGBB)。
|
||
* @param [IN] argb 待叠加颜色(含 alpha)。
|
||
* @return 混合后的不透明颜色。
|
||
*/
|
||
std::uint32_t UiBlendOver(std::uint32_t background, std::uint32_t argb);
|
||
|
||
/**
|
||
* @brief 作废「文本宽度测量」的记忆化缓存。
|
||
*
|
||
* `UiMeasureTextWidth` 内部按 (字体句柄, 文本) 缓存测量结果以摊薄 GDI 调用开销;
|
||
* 字体句柄被重建(DPI 变化等)时必须调用本函数,否则系统复用的同一句柄值会命中
|
||
* 旧宽度,造成布局错位。
|
||
*/
|
||
void UiClearMeasureCache();
|
||
|
||
/**
|
||
* @brief 一次性填充多个圆角矩形(同色同圆角)。
|
||
*
|
||
* 每帧要画几十个刻度数值底板时,逐个调用 `UiFillRoundRect` 会带来可观的 GDI+ 调用开销;
|
||
* 合并成一条 GraphicsPath 后只 FillPath 一次(实测约快 3 倍)。
|
||
*
|
||
* @param [IN,OUT] g 绘图上下文。
|
||
* @param [IN] rects 矩形集合。
|
||
* @param [IN] radius 圆角半径。
|
||
* @param [IN] argb 填充色。
|
||
*/
|
||
void UiFillRoundRects(gd::Graphics& g, const std::vector<gd::RectF>& rects, float radius,
|
||
std::uint32_t argb);
|
||
|
||
/**
|
||
* @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 将滑块轨道上的横坐标换算为取值比例。
|
||
* @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] 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 取值胶囊底色上的高对比度文字色与描边色。
|
||
*/
|
||
struct UiInk
|
||
{
|
||
std::uint32_t text = 0xFF073642u; /**< 文字色(不透明)。 */
|
||
std::uint32_t outline = 0x99FDF6E3u; /**< 描边色(半透明,恒与文字色反相)。 */
|
||
};
|
||
|
||
/**
|
||
* @brief 颜色的相对亮度(0-1,逐通道线性加权)。
|
||
* @param [IN] color 0xAARRGGBB 颜色值。
|
||
* @return 相对亮度。
|
||
*/
|
||
double UiColorLuminance(std::uint32_t color);
|
||
|
||
/**
|
||
* @brief 依据胶囊底色求高对比度的文字色与描边色(对底色配色作线性响应)。
|
||
*
|
||
* 求值分两步:
|
||
* 1. **亮度**:按"取最大对比"的一侧选定亮文字或暗文字。这是唯一的阈值判断,但它
|
||
* 本身就是"任意底色下都保持高对比"的必要条件 —— 任何连续的亮度取值都会在中性灰
|
||
* 附近同时远离两侧极值,对比度必然塌陷。
|
||
* 2. **配色**:把该侧的极值色与**底色的互补色**按固定比例线性混合。互补色的相对亮度
|
||
* 恰为 `1 - 底色亮度`,因此文字/描边的亮度是底色亮度的**线性**函数,色相也随信号
|
||
* 配色连续变化(不再是固定的黑/白两色)。
|
||
*
|
||
* 描边色取相反的一侧,保证"描边—文字—底色"三段式对比。
|
||
*
|
||
* @param [IN] background 胶囊底色(0xAARRGGBB)。
|
||
* @return 文字色与描边色。
|
||
*/
|
||
UiInk UiContrastInk(std::uint32_t background);
|
||
|
||
/**
|
||
* @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,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);
|
||
|
||
/**
|
||
* @brief 判断给定不透明度是否低到需要为样块补充描边。
|
||
* @param [IN] opacity 不透明度(0-1)。
|
||
* @return 需要描边返回 true。
|
||
*/
|
||
bool UiSwatchNeedsOutline(float opacity);
|
||
|
||
} // namespace jdi
|
||
|
||
#endif // __PAINT_UTIL_HPP__
|