fix: 自定义颜色色块与预设色块保持一致,拾色浮窗改为锚点定位并放行面板内点击
- 自定义颜色入口改为与预设色块完全一致的呈现:当前颜色不在预设中时, 方格直接填充该自定义颜色(并自动选择浅色/深色加号图标以保证可读性), 外框尺寸与选中样式与预设色块完全相同。 - 拾色浮窗改为以触发控件矩形为锚点定位:优先紧贴其下方展开,空间不足时改到上方, 修复此前浮窗遮挡「加号」方格的问题。 - 拾色浮窗展开时点击面板内的其它控件(预设色、线宽、样式、透明度等)不再被吞掉, 改为「先收起浮窗、再放行该次点击」,一次点击即可切换预设色; 点击面板外或绘图区仍只收起浮窗。
This commit is contained in:
1 parent
729494d1ec
commit
0f98dd9a85
4 files changed
+64
-31
No files matched your search
@@ -1183,13 +1183,25 @@ namespace jdi
|
||||
m_plot.OnLButtonUp(0, 0);
|
||||
m_activeTarget = Target::NONE;
|
||||
m_draggingSplitter = false;
|
||||
m_colorPicker.OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
if (m_colorPicker.IsOpen())
|
||||
|
||||
// 点击拾色器外部时收起;若落点落在信号面板内则放行本次点击,
|
||||
// 便于用户在展开状态下直接改选预设色、线宽等其它样式。
|
||||
if (m_colorPicker.ContainsPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
|
||||
{
|
||||
m_colorPicker.OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
SetCapture(hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_colorPicker.Close();
|
||||
if (!m_panel.HitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
|
||||
{
|
||||
InvalidateRect(hwnd, nullptr, FALSE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
repaint = true;
|
||||
consume = true;
|
||||
consume = false;
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
m_colorPicker.OnLButtonUp();
|
||||
|
||||
@@ -105,6 +105,19 @@ namespace jdi
|
||||
return WithAlpha(color, static_cast<unsigned int>(alpha * 255.0 + 0.5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断颜色是否偏暗(用于在色块之上选择可读的图标颜色)。
|
||||
* @param [IN] color 0xAARRGGBB 颜色值。
|
||||
* @return 相对亮度低于阈值返回 true。
|
||||
*/
|
||||
bool IsDarkColor(std::uint32_t color)
|
||||
{
|
||||
const double r = static_cast<double>((color >> 16) & 0xFFu);
|
||||
const double g = static_cast<double>((color >> 8) & 0xFFu);
|
||||
const double b = static_cast<double>(color & 0xFFu);
|
||||
return (0.299 * r + 0.587 * g + 0.114 * b) < 140.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将数值限制到合法区间。
|
||||
* @param [IN] value 输入值。
|
||||
@@ -852,14 +865,23 @@ namespace jdi
|
||||
}
|
||||
|
||||
// 自定义颜色入口:与预设色块完全同尺寸、同外框样式的小方格,仅多一个加号图标。
|
||||
// 当前颜色不在预设中时,方格直接填充该颜色,与预设色块的表现保持一致。
|
||||
const bool chipHot = (m_hoverStyle == StyleHit::CUSTOM_CHIP);
|
||||
const bool chipActive = !presetActive && (m_colorPicker != nullptr) && m_colorPicker->IsOpen();
|
||||
UiFillRoundRect(g, m_customChipRect, kCorner * m_scale, m_theme->cardBg);
|
||||
UiDrawRoundRect(g, m_customChipRect, kCorner * m_scale, m_theme->borderStrong, 1.0f);
|
||||
UiDrawPlusIcon(g, m_customChipRect, chipHot ? m_theme->accent : m_theme->text,
|
||||
1.6f * m_scale);
|
||||
|
||||
// 当前颜色不在预设中时,用与预设一致的外框指示“正在使用自定义颜色”。
|
||||
std::uint32_t chipColor = m_theme->cardBg;
|
||||
std::uint32_t iconColor = chipHot ? m_theme->accent : m_theme->text;
|
||||
if (!presetActive)
|
||||
{
|
||||
chipColor = ApplyOpacity(style->color, style->opacity);
|
||||
iconColor = IsDarkColor(chipColor) ? 0xFFFDF6E3u : 0xFF073642u;
|
||||
}
|
||||
|
||||
UiFillRoundRect(g, m_customChipRect, kCorner * m_scale, chipColor);
|
||||
UiDrawRoundRect(g, m_customChipRect, kCorner * m_scale,
|
||||
chipHot ? m_theme->accent : m_theme->borderStrong, 1.0f);
|
||||
UiDrawPlusIcon(g, m_customChipRect, iconColor, 1.6f * m_scale);
|
||||
|
||||
// 选中外框与预设色块完全一致(当前正在使用自定义颜色或被悬停时显示)。
|
||||
if (!presetActive || chipHot)
|
||||
{
|
||||
const gd::RectF& chip = m_customChipRect;
|
||||
@@ -869,7 +891,6 @@ namespace jdi
|
||||
!presetActive ? m_theme->textStrong : m_theme->borderStrong,
|
||||
!presetActive ? 1.6f : 1.0f);
|
||||
}
|
||||
(void)chipActive;
|
||||
}
|
||||
|
||||
// ---- 第二行:线宽 ----
|
||||
@@ -1193,8 +1214,7 @@ namespace jdi
|
||||
}
|
||||
|
||||
const gd::RectF bounds = (m_clientBounds.Width > 1.0f) ? m_clientBounds : m_area;
|
||||
m_colorPicker->Open(bounds, static_cast<int>(m_customChipRect.X),
|
||||
static_cast<int>(m_customChipRect.Y + m_customChipRect.Height), style.color);
|
||||
m_colorPicker->Open(bounds, m_customChipRect, style.color);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,10 @@ namespace jdi
|
||||
/**
|
||||
* @brief 在指定位置打开拾色面板。
|
||||
* @param [IN] bounds 宿主客户区矩形,用于把面板限制在窗口内。
|
||||
* @param [IN] x 锚点横坐标(客户区坐标)。
|
||||
* @param [IN] y 锚点纵坐标(客户区坐标)。
|
||||
* @param [IN] anchor 触发控件矩形(客户区坐标),面板会紧贴其下方或上方展开。
|
||||
* @param [IN] color 初始颜色(0xAARRGGBB,仅取 RGB 分量)。
|
||||
*/
|
||||
void Open(const gd::RectF& bounds, int x, int y, std::uint32_t color);
|
||||
void Open(const gd::RectF& bounds, const gd::RectF& anchor, std::uint32_t color);
|
||||
|
||||
/**
|
||||
* @brief 关闭拾色面板。
|
||||
@@ -116,12 +115,11 @@ namespace jdi
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 依据锚点与客户区计算面板矩形与内部控件矩形。
|
||||
* @brief 依据锚点矩形与客户区计算面板矩形与内部控件矩形。
|
||||
* @param [IN] bounds 宿主客户区矩形。
|
||||
* @param [IN] x 锚点横坐标。
|
||||
* @param [IN] y 锚点纵坐标。
|
||||
* @param [IN] anchor 触发控件矩形。
|
||||
*/
|
||||
void BuildLayout(const gd::RectF& bounds, int x, int y);
|
||||
void BuildLayout(const gd::RectF& bounds, const gd::RectF& anchor);
|
||||
|
||||
/**
|
||||
* @brief 查询坐标命中的滑块下标。
|
||||
|
||||
@@ -111,27 +111,30 @@ namespace jdi
|
||||
return true;
|
||||
}
|
||||
|
||||
void ColorPickerPopup::BuildLayout(const gd::RectF& bounds, int x, int y)
|
||||
void ColorPickerPopup::BuildLayout(const gd::RectF& bounds, const gd::RectF& anchor)
|
||||
{
|
||||
const float width = kPanelWidth * m_scale;
|
||||
const float height = (kPadV * 2.0f + kTitleHeight + kTitleGap + kRowHeight * 3.0f + kRowGap * 2.0f +
|
||||
kPreviewGap + kPreviewHeight) *
|
||||
m_scale;
|
||||
|
||||
float left = static_cast<float>(x);
|
||||
float top = static_cast<float>(y);
|
||||
const float gap = 4.0f * m_scale;
|
||||
|
||||
// 优先向右下展开;越界时翻转,最后做边界收敛。
|
||||
if (left + width > bounds.X + bounds.Width)
|
||||
{
|
||||
left = static_cast<float>(x) - width;
|
||||
}
|
||||
// 纵向:优先紧贴触发控件下方展开;空间不足时改到其上方,避免遮挡触发控件本身。
|
||||
float top = anchor.Y + anchor.Height + gap;
|
||||
if (top + height > bounds.Y + bounds.Height)
|
||||
{
|
||||
top = static_cast<float>(y) - height;
|
||||
top = anchor.Y - height - gap;
|
||||
}
|
||||
top = std::max(bounds.Y + 2.0f, std::min(top, bounds.Y + bounds.Height - height - 2.0f));
|
||||
|
||||
// 横向:与触发控件左对齐,越界时再收敛。
|
||||
float left = anchor.X;
|
||||
if (left + width > bounds.X + bounds.Width)
|
||||
{
|
||||
left = anchor.X + anchor.Width - width;
|
||||
}
|
||||
left = std::max(bounds.X + 2.0f, std::min(left, bounds.X + bounds.Width - width - 2.0f));
|
||||
top = std::max(bounds.Y + 2.0f, std::min(top, bounds.Y + bounds.Height - height - 2.0f));
|
||||
|
||||
m_rect = gd::RectF(left, top, width, height);
|
||||
|
||||
@@ -160,7 +163,7 @@ namespace jdi
|
||||
96.0f * m_scale, 20.0f * m_scale);
|
||||
}
|
||||
|
||||
void ColorPickerPopup::Open(const gd::RectF& bounds, int x, int y, std::uint32_t color)
|
||||
void ColorPickerPopup::Open(const gd::RectF& bounds, const gd::RectF& anchor, std::uint32_t color)
|
||||
{
|
||||
m_channels[0] = static_cast<double>((color >> 16) & 0xFFu) / 255.0;
|
||||
m_channels[1] = static_cast<double>((color >> 8) & 0xFFu) / 255.0;
|
||||
@@ -171,7 +174,7 @@ namespace jdi
|
||||
m_draggingSlider = -1;
|
||||
m_hoverSlider = -1;
|
||||
|
||||
BuildLayout(bounds, x, y);
|
||||
BuildLayout(bounds, anchor);
|
||||
}
|
||||
|
||||
void ColorPickerPopup::Close()
|
||||
|
||||
Reference in new issue
Block a user