diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 81aedce8c86..87ff08c283c 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -411,7 +411,9 @@ ColorHSLA CMenus::DoButton_ColorPicker(const CUIRect *pRect, unsigned int *pHsla if(UI()->DoButtonLogic(pHslaColor, 0, pRect)) { s_ColorPickerPopupContext.m_pHslaColor = pHslaColor; + s_ColorPickerPopupContext.m_HslaColor = HslaColor; s_ColorPickerPopupContext.m_HsvaColor = color_cast(HslaColor); + s_ColorPickerPopupContext.m_RgbaColor = color_cast(s_ColorPickerPopupContext.m_HsvaColor); s_ColorPickerPopupContext.m_Alpha = Alpha; UI()->ShowPopupColorPicker(UI()->MouseX(), UI()->MouseY(), &s_ColorPickerPopupContext); } diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp index e88106eaae9..a02b4d238e6 100644 --- a/src/game/client/ui.cpp +++ b/src/game/client/ui.cpp @@ -968,16 +968,16 @@ int CUI::DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pID, const return DoButtonLogic(pID, Props.m_Checked, pRect); } -int CUI::DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding, bool TransparentInactive) +int CUI::DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding, bool TransparentInactive, bool Enabled) { if(!TransparentInactive || CheckActiveItem(pButtonContainer) || HotItem() == pButtonContainer) - pRect->Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * ButtonColorMul(pButtonContainer)), IGraphics::CORNER_ALL, 3.0f); + pRect->Draw(Enabled ? ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * ButtonColorMul(pButtonContainer)) : ColorRGBA(0.0f, 0.0f, 0.0f, 0.4f), IGraphics::CORNER_ALL, 3.0f); CUIRect Label; pRect->Margin(Padding, &Label); DoLabel(&Label, pText, Size, Align); - return DoButtonLogic(pButtonContainer, 0, pRect); + return Enabled ? DoButtonLogic(pButtonContainer, 0, pRect) : 0; } int64_t CUI::DoValueSelector(const void *pID, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props) @@ -1687,9 +1687,9 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View SColorPickerPopupContext *pColorPicker = static_cast(pContext); CUI *pUI = pColorPicker->m_pUI; - CUIRect ColorsArea = View, HueArea, BottomArea, HueRect, SatRect, ValueRect, HexRect, AlphaRect; + CUIRect ColorsArea, HueArea, BottomArea, ModeButtonArea, HueRect, SatRect, ValueRect, HexRect, AlphaRect; - ColorsArea.HSplitBottom(View.h - 140.0f, &ColorsArea, &BottomArea); + View.HSplitTop(140.0f, &ColorsArea, &BottomArea); ColorsArea.VSplitRight(20.0f, &ColorsArea, &HueArea); BottomArea.HSplitTop(3.0f, nullptr, &BottomArea); @@ -1708,8 +1708,10 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View ValueRect.VSplitLeft(ValuePadding, nullptr, &ValueRect); BottomArea.HSplitTop(20.0f, &HexRect, &BottomArea); + BottomArea.HSplitTop(3.0f, nullptr, &BottomArea); HexRect.VSplitLeft(HexValueWidth, &HexRect, &AlphaRect); AlphaRect.VSplitLeft(ValuePadding, nullptr, &AlphaRect); + BottomArea.HSplitTop(20.0f, &ModeButtonArea, &BottomArea); const ColorRGBA BlackColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f); @@ -1720,10 +1722,8 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View ColorsArea.Margin(1.0f, &ColorsArea); ColorHSVA PickerColorHSV = pColorPicker->m_HsvaColor; - unsigned H = (unsigned)(PickerColorHSV.x * 255.0f); - unsigned S = (unsigned)(PickerColorHSV.y * 255.0f); - unsigned V = (unsigned)(PickerColorHSV.z * 255.0f); - unsigned A = (unsigned)(PickerColorHSV.a * 255.0f); + ColorRGBA PickerColorRGB = pColorPicker->m_RgbaColor; + ColorHSLA PickerColorHSL = pColorPicker->m_HslaColor; // Color Area ColorRGBA TL, TR, BL, BR; @@ -1759,35 +1759,98 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View HuePartialArea.Draw4(TL, TL, BL, BL, IGraphics::CORNER_NONE, 0.0f); } + const auto &&RenderAlphaSelector = [&](unsigned OldA) -> unsigned { + if(pColorPicker->m_Alpha) + { + return pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[3], &AlphaRect, "A:", OldA, 0, 255); + } + else + { + char aBuf[8]; + str_format(aBuf, sizeof(aBuf), "A: %d", OldA); + pUI->DoLabel(&AlphaRect, aBuf, 10.0f, TEXTALIGN_MC); + AlphaRect.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.65f), IGraphics::CORNER_ALL, 3.0f); + return OldA; + } + }; + // Editboxes Area - H = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", H, 0, 255); - S = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", S, 0, 255); - V = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "V:", V, 0, 255); - if(pColorPicker->m_Alpha) + if(pColorPicker->m_ColorMode == SColorPickerPopupContext::MODE_HSVA) { - A = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[3], &AlphaRect, "A:", A, 0, 255); + const unsigned OldH = (unsigned)(PickerColorHSV.h * 255.0f); + const unsigned OldS = (unsigned)(PickerColorHSV.s * 255.0f); + const unsigned OldV = (unsigned)(PickerColorHSV.v * 255.0f); + const unsigned OldA = (unsigned)(PickerColorHSV.a * 255.0f); + + const unsigned H = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", OldH, 0, 255); + const unsigned S = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", OldS, 0, 255); + const unsigned V = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "V:", OldV, 0, 255); + const unsigned A = RenderAlphaSelector(OldA); + + if(OldH != H || OldS != S || OldV != V || OldA != A) + { + PickerColorHSV = ColorHSVA(H / 255.0f, S / 255.0f, V / 255.0f, A / 255.0f); + PickerColorHSL = color_cast(PickerColorHSV); + PickerColorRGB = color_cast(PickerColorHSL); + } } - else + else if(pColorPicker->m_ColorMode == SColorPickerPopupContext::MODE_RGBA) { - char aBuf[8]; - str_format(aBuf, sizeof(aBuf), "A: %d", A); - pUI->DoLabel(&AlphaRect, aBuf, 10.0f, TEXTALIGN_MC); - AlphaRect.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.65f), IGraphics::CORNER_ALL, 3.0f); + const unsigned OldR = (unsigned)(PickerColorRGB.r * 255.0f); + const unsigned OldG = (unsigned)(PickerColorRGB.g * 255.0f); + const unsigned OldB = (unsigned)(PickerColorRGB.b * 255.0f); + const unsigned OldA = (unsigned)(PickerColorRGB.a * 255.0f); + + const unsigned R = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "R:", OldR, 0, 255); + const unsigned G = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "G:", OldG, 0, 255); + const unsigned B = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "B:", OldB, 0, 255); + const unsigned A = RenderAlphaSelector(OldA); + + if(OldR != R || OldG != G || OldB != B || OldA != A) + { + PickerColorRGB = ColorRGBA(R / 255.0f, G / 255.0f, B / 255.0f, A / 255.0f); + PickerColorHSL = color_cast(PickerColorRGB); + PickerColorHSV = color_cast(PickerColorHSL); + } } + else if(pColorPicker->m_ColorMode == SColorPickerPopupContext::MODE_HSLA) + { + const unsigned OldH = (unsigned)(PickerColorHSL.h * 255.0f); + const unsigned OldS = (unsigned)(PickerColorHSL.s * 255.0f); + const unsigned OldL = (unsigned)(PickerColorHSL.l * 255.0f); + const unsigned OldA = (unsigned)(PickerColorHSL.a * 255.0f); - PickerColorHSV = ColorHSVA(H / 255.0f, S / 255.0f, V / 255.0f, A / 255.0f); + const unsigned H = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", OldH, 0, 255); + const unsigned S = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", OldS, 0, 255); + const unsigned L = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "L:", OldL, 0, 255); + const unsigned A = RenderAlphaSelector(OldA); + + if(OldH != H || OldS != S || OldL != L || OldA != A) + { + PickerColorHSL = ColorHSLA(H / 255.0f, S / 255.0f, L / 255.0f, A / 255.0f); + PickerColorHSV = color_cast(PickerColorHSL); + PickerColorRGB = color_cast(PickerColorHSL); + } + } + else + { + dbg_assert(false, "Color picker mode invalid"); + } SValueSelectorProperties Props; Props.m_UseScroll = false; Props.m_IsHex = true; Props.m_HexPrefix = pColorPicker->m_Alpha ? 8 : 6; - const unsigned Hex = color_cast(PickerColorHSV).PackAlphaLast(pColorPicker->m_Alpha); - const unsigned NewHex = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[4], &HexRect, "Hex:", Hex, 0, pColorPicker->m_Alpha ? 0xFFFFFFFFll : 0xFFFFFFll, Props); - if(Hex != NewHex) + const unsigned OldHex = PickerColorRGB.PackAlphaLast(pColorPicker->m_Alpha); + const unsigned Hex = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[4], &HexRect, "Hex:", OldHex, 0, pColorPicker->m_Alpha ? 0xFFFFFFFFll : 0xFFFFFFll, Props); + if(OldHex != Hex) { - PickerColorHSV = color_cast(ColorRGBA::UnpackAlphaLast(NewHex, pColorPicker->m_Alpha)); + const float OldAlpha = PickerColorRGB.a; + PickerColorRGB = ColorRGBA::UnpackAlphaLast(Hex, pColorPicker->m_Alpha); if(!pColorPicker->m_Alpha) - PickerColorHSV.a = A / 255.0f; + PickerColorRGB.a = OldAlpha; + PickerColorHSL = color_cast(PickerColorRGB); + PickerColorHSV = color_cast(PickerColorHSL); } // Logic @@ -1796,10 +1859,16 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View { PickerColorHSV.y = PickerX / ColorsArea.w; PickerColorHSV.z = 1.0f - PickerY / ColorsArea.h; + PickerColorHSL = color_cast(PickerColorHSV); + PickerColorRGB = color_cast(PickerColorHSL); } if(pUI->DoPickerLogic(&pColorPicker->m_HuePickerId, &HueArea, &PickerX, &PickerY)) + { PickerColorHSV.x = 1.0f - PickerY / HueArea.h; + PickerColorHSL = color_cast(PickerColorHSV); + PickerColorRGB = color_cast(PickerColorHSL); + } // Marker Color Area const float MarkerX = ColorsArea.x + ColorsArea.w * PickerColorHSV.y; @@ -1812,7 +1881,7 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View pUI->Graphics()->QuadsBegin(); pUI->Graphics()->SetColor(MarkerOutline); pUI->Graphics()->DrawCircle(MarkerX, MarkerY, 4.5f, 32); - pUI->Graphics()->SetColor(color_cast(PickerColorHSV)); + pUI->Graphics()->SetColor(PickerColorRGB); pUI->Graphics()->DrawCircle(MarkerX, MarkerY, 3.5f, 32); pUI->Graphics()->QuadsEnd(); @@ -1831,8 +1900,23 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View HueMarker.Draw(HueMarkerColor, IGraphics::CORNER_ALL, 1.2f); pColorPicker->m_HsvaColor = PickerColorHSV; + pColorPicker->m_RgbaColor = PickerColorRGB; + pColorPicker->m_HslaColor = PickerColorHSL; if(pColorPicker->m_pHslaColor != nullptr) - *pColorPicker->m_pHslaColor = color_cast(PickerColorHSV).Pack(pColorPicker->m_Alpha); + *pColorPicker->m_pHslaColor = PickerColorHSL.Pack(pColorPicker->m_Alpha); + + static const SColorPickerPopupContext::EColorPickerMode s_aModes[] = {SColorPickerPopupContext::MODE_HSVA, SColorPickerPopupContext::MODE_RGBA, SColorPickerPopupContext::MODE_HSLA}; + static const char *s_apModeLabels[std::size(s_aModes)] = {"HSVA", "RGBA", "HSLA"}; + for(SColorPickerPopupContext::EColorPickerMode Mode : s_aModes) + { + CUIRect ModeButton; + ModeButtonArea.VSplitLeft(HsvValueWidth, &ModeButton, &ModeButtonArea); + ModeButtonArea.VSplitLeft(ValuePadding, nullptr, &ModeButtonArea); + if(pUI->DoButton_PopupMenu(&pColorPicker->m_aModeButtons[(int)Mode], s_apModeLabels[Mode], &ModeButton, 10.0f, TEXTALIGN_MC, 2.0f, false, pColorPicker->m_ColorMode != Mode)) + { + pColorPicker->m_ColorMode = Mode; + } + } return CUI::POPUP_KEEP_OPEN; } @@ -1840,5 +1924,7 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View void CUI::ShowPopupColorPicker(float X, float Y, SColorPickerPopupContext *pContext) { pContext->m_pUI = this; - DoPopupMenu(pContext, X, Y, 160.0f + 10.0f, 186.0f + 10.0f, pContext, PopupColorPicker); + if(pContext->m_ColorMode == SColorPickerPopupContext::MODE_UNSET) + pContext->m_ColorMode = SColorPickerPopupContext::MODE_HSVA; + DoPopupMenu(pContext, X, Y, 160.0f + 10.0f, 209.0f + 10.0f, pContext, PopupColorPicker); } diff --git a/src/game/client/ui.h b/src/game/client/ui.h index 895961b61b4..80a7e26dfe6 100644 --- a/src/game/client/ui.h +++ b/src/game/client/ui.h @@ -502,7 +502,7 @@ class CUI int DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pID, const std::function &GetTextLambda, const CUIRect *pRect, const SMenuButtonProperties &Props = {}); // only used for popup menus - int DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding = 0.0f, bool TransparentInactive = false); + int DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding = 0.0f, bool TransparentInactive = false, bool Enabled = true); // value selector int64_t DoValueSelector(const void *pID, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props = {}); @@ -600,13 +600,26 @@ class CUI struct SColorPickerPopupContext : public SPopupMenuId { + enum EColorPickerMode + { + MODE_UNSET = -1, + MODE_HSVA, + MODE_RGBA, + MODE_HSLA, + }; + CUI *m_pUI; // set by CUI when popup is shown + EColorPickerMode m_ColorMode = MODE_UNSET; bool m_Alpha = false; unsigned int *m_pHslaColor = nullptr; // may be nullptr ColorHSVA m_HsvaColor; + ColorRGBA m_RgbaColor; + ColorHSLA m_HslaColor; + // UI element IDs const char m_HuePickerId = 0; const char m_ColorPickerId = 0; const char m_aValueSelectorIds[5] = {0}; + CButtonContainer m_aModeButtons[(int)MODE_HSLA + 1]; }; void ShowPopupColorPicker(float X, float Y, SColorPickerPopupContext *pContext); diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index adbf16d2548..811b0b6b5d6 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -3133,14 +3133,17 @@ int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int * } else if(ButtonResult > 0) { - s_ColorPickerPopupContext.m_HsvaColor = color_cast(ColorPick); + if(s_ColorPickerPopupContext.m_ColorMode == CUI::SColorPickerPopupContext::MODE_UNSET) + s_ColorPickerPopupContext.m_ColorMode = CUI::SColorPickerPopupContext::MODE_RGBA; + s_ColorPickerPopupContext.m_RgbaColor = ColorPick; + s_ColorPickerPopupContext.m_HslaColor = color_cast(ColorPick); + s_ColorPickerPopupContext.m_HsvaColor = color_cast(s_ColorPickerPopupContext.m_HslaColor); s_ColorPickerPopupContext.m_Alpha = true; UI()->ShowPopupColorPicker(UI()->MouseX(), UI()->MouseY(), &s_ColorPickerPopupContext); } else if(UI()->IsPopupOpen(&s_ColorPickerPopupContext)) { - ColorRGBA c = color_cast(s_ColorPickerPopupContext.m_HsvaColor); - const int NewColor = c.PackAlphaLast(s_ColorPickerPopupContext.m_Alpha); + const int NewColor = s_ColorPickerPopupContext.m_RgbaColor.PackAlphaLast(s_ColorPickerPopupContext.m_Alpha); if(NewColor != pProps[i].m_Value) { *pNewVal = NewColor;