Merge pull request #7417 from Robyt3/UI-ColorPicker-RGBA

Add mode selection to color picker popups (RGBA, HSVA, HSLA)
This commit is contained in:
Jupeyy 2023-11-05 13:10:08 +00:00 committed by GitHub
commit 50905325d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 136 additions and 32 deletions

View file

@ -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<ColorHSVA>(HslaColor);
s_ColorPickerPopupContext.m_RgbaColor = color_cast<ColorRGBA>(s_ColorPickerPopupContext.m_HsvaColor);
s_ColorPickerPopupContext.m_Alpha = Alpha;
UI()->ShowPopupColorPicker(UI()->MouseX(), UI()->MouseY(), &s_ColorPickerPopupContext);
}

View file

@ -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<SColorPickerPopupContext *>(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<ColorHSLA>(PickerColorHSV);
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
}
}
else if(pColorPicker->m_ColorMode == SColorPickerPopupContext::MODE_RGBA)
{
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<ColorHSLA>(PickerColorRGB);
PickerColorHSV = color_cast<ColorHSVA>(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);
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<ColorHSVA>(PickerColorHSL);
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
}
}
else
{
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);
dbg_assert(false, "Color picker mode invalid");
}
PickerColorHSV = ColorHSVA(H / 255.0f, S / 255.0f, V / 255.0f, A / 255.0f);
SValueSelectorProperties Props;
Props.m_UseScroll = false;
Props.m_IsHex = true;
Props.m_HexPrefix = pColorPicker->m_Alpha ? 8 : 6;
const unsigned Hex = color_cast<ColorRGBA>(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<ColorHSVA>(ColorRGBA::UnpackAlphaLast<ColorRGBA>(NewHex, pColorPicker->m_Alpha));
const float OldAlpha = PickerColorRGB.a;
PickerColorRGB = ColorRGBA::UnpackAlphaLast<ColorRGBA>(Hex, pColorPicker->m_Alpha);
if(!pColorPicker->m_Alpha)
PickerColorHSV.a = A / 255.0f;
PickerColorRGB.a = OldAlpha;
PickerColorHSL = color_cast<ColorHSLA>(PickerColorRGB);
PickerColorHSV = color_cast<ColorHSVA>(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<ColorHSLA>(PickerColorHSV);
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
}
if(pUI->DoPickerLogic(&pColorPicker->m_HuePickerId, &HueArea, &PickerX, &PickerY))
{
PickerColorHSV.x = 1.0f - PickerY / HueArea.h;
PickerColorHSL = color_cast<ColorHSLA>(PickerColorHSV);
PickerColorRGB = color_cast<ColorRGBA>(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<ColorRGBA>(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<ColorHSLA>(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);
}

View file

@ -502,7 +502,7 @@ public:
int DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pID, const std::function<const char *()> &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 @@ public:
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);

View file

@ -3133,14 +3133,17 @@ int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int *
}
else if(ButtonResult > 0)
{
s_ColorPickerPopupContext.m_HsvaColor = color_cast<ColorHSVA>(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<ColorHSLA>(ColorPick);
s_ColorPickerPopupContext.m_HsvaColor = color_cast<ColorHSVA>(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<ColorRGBA>(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;