diff --git a/Components/Application/Src/Application.cpp b/Components/Application/Src/Application.cpp index 1e89588..20d9aea 100644 --- a/Components/Application/Src/Application.cpp +++ b/Components/Application/Src/Application.cpp @@ -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(); diff --git a/Components/SignalPanel/Src/SignalPanel.cpp b/Components/SignalPanel/Src/SignalPanel.cpp index 943521e..d5b3773 100644 --- a/Components/SignalPanel/Src/SignalPanel.cpp +++ b/Components/SignalPanel/Src/SignalPanel.cpp @@ -105,6 +105,19 @@ namespace jdi return WithAlpha(color, static_cast(alpha * 255.0 + 0.5)); } + /** + * @brief 判断颜色是否偏暗(用于在色块之上选择可读的图标颜色)。 + * @param [IN] color 0xAARRGGBB 颜色值。 + * @return 相对亮度低于阈值返回 true。 + */ + bool IsDarkColor(std::uint32_t color) + { + const double r = static_cast((color >> 16) & 0xFFu); + const double g = static_cast((color >> 8) & 0xFFu); + const double b = static_cast(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(m_customChipRect.X), - static_cast(m_customChipRect.Y + m_customChipRect.Height), style.color); + m_colorPicker->Open(bounds, m_customChipRect, style.color); return true; } diff --git a/Utilities/Inc/ColorPickerPopup.hpp b/Utilities/Inc/ColorPickerPopup.hpp index 0729d97..948f486 100644 --- a/Utilities/Inc/ColorPickerPopup.hpp +++ b/Utilities/Inc/ColorPickerPopup.hpp @@ -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 查询坐标命中的滑块下标。 diff --git a/Utilities/Src/ColorPickerPopup.cpp b/Utilities/Src/ColorPickerPopup.cpp index ae9e86f..9273a1c 100644 --- a/Utilities/Src/ColorPickerPopup.cpp +++ b/Utilities/Src/ColorPickerPopup.cpp @@ -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(x); - float top = static_cast(y); + const float gap = 4.0f * m_scale; - // 优先向右下展开;越界时翻转,最后做边界收敛。 - if (left + width > bounds.X + bounds.Width) - { - left = static_cast(x) - width; - } + // 纵向:优先紧贴触发控件下方展开;空间不足时改到其上方,避免遮挡触发控件本身。 + float top = anchor.Y + anchor.Height + gap; if (top + height > bounds.Y + bounds.Height) { - top = static_cast(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((color >> 16) & 0xFFu) / 255.0; m_channels[1] = static_cast((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()