From c48623de8fc9055113f527fc1766a5786e906281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 11 Nov 2023 16:42:25 +0100 Subject: [PATCH 1/3] Extract `CEditor::DoColorPickerButton` function Fix color not being updated while shift key is pressed, due to use of `else if`. --- src/game/editor/editor.cpp | 109 ++++++++++++++++++++----------------- src/game/editor/editor.h | 4 ++ 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index a60ba6379..a7aa16629 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -3098,58 +3098,15 @@ int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int * } else if(pProps[i].m_Type == PROPTYPE_COLOR) { - const ColorRGBA ColorPick = ColorRGBA::UnpackAlphaLast(pProps[i].m_Value); - - CUIRect ColorRect; - Shifter.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * UI()->ButtonColorMul(&pIDs[i])), IGraphics::CORNER_ALL, 5.0f); - Shifter.Margin(1.0f, &ColorRect); - ColorRect.Draw(ColorPick, IGraphics::CORNER_ALL, ColorRect.h / 2.0f); - - static CUI::SColorPickerPopupContext s_ColorPickerPopupContext; - const int ButtonResult = DoButton_Editor_Common(&pIDs[i], nullptr, 0, &Shifter, 0, "Click to show the color picker. Shift+rightclick to copy color to clipboard. Shift+leftclick to paste color from clipboard."); - if(Input()->ShiftIsPressed()) - { - if(ButtonResult == 1) + const auto &&SetColor = [&](ColorRGBA NewColor) { + const int NewValue = NewColor.PackAlphaLast(); + if(NewValue != pProps[i].m_Value) { - const char *pClipboard = Input()->GetClipboardText(); - if(*pClipboard == '#' || *pClipboard == '$') // ignore leading # (web color format) and $ (console color format) - ++pClipboard; - if(str_isallnum_hex(pClipboard)) - { - std::optional ParsedColor = color_parse(pClipboard); - if(ParsedColor) - { - *pNewVal = ParsedColor.value().PackAlphaLast(); - Change = i; - } - } - } - else if(ButtonResult == 2) - { - char aClipboard[9]; - str_format(aClipboard, sizeof(aClipboard), "%08X", ColorPick.PackAlphaLast()); - Input()->SetClipboardText(aClipboard); - } - } - else if(ButtonResult > 0) - { - 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)) - { - const int NewColor = s_ColorPickerPopupContext.m_RgbaColor.PackAlphaLast(s_ColorPickerPopupContext.m_Alpha); - if(NewColor != pProps[i].m_Value) - { - *pNewVal = NewColor; + *pNewVal = NewValue; Change = i; } - } + }; + DoColorPickerButton(&pIDs[i], &Shifter, ColorRGBA::UnpackAlphaLast(pProps[i].m_Value), SetColor); } else if(pProps[i].m_Type == PROPTYPE_IMAGE) { @@ -3284,6 +3241,60 @@ int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int * return Change; } +void CEditor::DoColorPickerButton(const void *pID, const CUIRect *pRect, ColorRGBA Color, const std::function &SetColor) +{ + CUIRect ColorRect; + pRect->Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * UI()->ButtonColorMul(pID)), IGraphics::CORNER_ALL, 5.0f); + pRect->Margin(1.0f, &ColorRect); + ColorRect.Draw(Color, IGraphics::CORNER_ALL, 5.0f); + + const int ButtonResult = DoButton_Editor_Common(pID, nullptr, 0, pRect, 0, "Click to show the color picker. Shift+rightclick to copy color to clipboard. Shift+leftclick to paste color from clipboard."); + if(Input()->ShiftIsPressed()) + { + if(ButtonResult == 1) + { + const char *pClipboard = Input()->GetClipboardText(); + if(*pClipboard == '#' || *pClipboard == '$') // ignore leading # (web color format) and $ (console color format) + ++pClipboard; + if(str_isallnum_hex(pClipboard)) + { + std::optional ParsedColor = color_parse(pClipboard); + if(ParsedColor) + { + SetColor(ParsedColor.value()); + } + } + } + else if(ButtonResult == 2) + { + char aClipboard[9]; + str_format(aClipboard, sizeof(aClipboard), "%08X", Color.PackAlphaLast()); + Input()->SetClipboardText(aClipboard); + } + } + else if(ButtonResult > 0) + { + if(m_ColorPickerPopupContext.m_ColorMode == CUI::SColorPickerPopupContext::MODE_UNSET) + m_ColorPickerPopupContext.m_ColorMode = CUI::SColorPickerPopupContext::MODE_RGBA; + m_ColorPickerPopupContext.m_RgbaColor = Color; + m_ColorPickerPopupContext.m_HslaColor = color_cast(Color); + m_ColorPickerPopupContext.m_HsvaColor = color_cast(m_ColorPickerPopupContext.m_HslaColor); + m_ColorPickerPopupContext.m_Alpha = true; + m_pColorPickerPopupActiveID = pID; + UI()->ShowPopupColorPicker(UI()->MouseX(), UI()->MouseY(), &m_ColorPickerPopupContext); + } + + if(UI()->IsPopupOpen(&m_ColorPickerPopupContext)) + { + if(m_pColorPickerPopupActiveID == pID) + SetColor(m_ColorPickerPopupContext.m_RgbaColor); + } + else + { + m_pColorPickerPopupActiveID = nullptr; + } +} + void CEditor::RenderLayers(CUIRect LayersBox) { const float RowHeight = 12.0f; diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 1d66de2fd..19327666c 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -496,6 +496,10 @@ public: int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f)); + CUI::SColorPickerPopupContext m_ColorPickerPopupContext; + const void *m_pColorPickerPopupActiveID = nullptr; + void DoColorPickerButton(const void *pID, const CUIRect *pRect, ColorRGBA Color, const std::function &SetColor); + int m_Mode; int m_Dialog; char m_aTooltip[256] = ""; From d8452ad02ca4a34e1897ce8963eec06c9556b675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 11 Nov 2023 16:42:46 +0100 Subject: [PATCH 2/3] Extract `ShowPopupEnvPoint` local function --- src/game/editor/editor.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index a7aa16629..a39b935a8 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -6269,6 +6269,11 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) } { + static SPopupMenuId s_PopupEnvPointId; + const auto &&ShowPopupEnvPoint = [&]() { + UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint); + }; + if(s_Operation == OP_NONE) SetHotEnvelopePoint(View, pEnvelope, s_ActiveChannels); @@ -6412,8 +6417,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) if(m_vSelectedEnvelopePoints.size() == 1) { m_UpdateEnvPointInfo = true; - static SPopupMenuId s_PopupEnvPointId; - UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint); + ShowPopupEnvPoint(); } else if(m_vSelectedEnvelopePoints.size() > 1) { @@ -6556,8 +6560,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) if(IsTangentOutPointSelected(i, c)) { m_UpdateEnvPointInfo = true; - static SPopupMenuId s_PopupEnvPointId; - UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint); + ShowPopupEnvPoint(); } UI()->SetActiveItem(nullptr); } @@ -6689,8 +6692,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) if(IsTangentInPointSelected(i, c)) { m_UpdateEnvPointInfo = true; - static SPopupMenuId s_PopupEnvPointId; - UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint); + ShowPopupEnvPoint(); } UI()->SetActiveItem(nullptr); } From bd4c138107d86409b7587f626f8d0d27300f6666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 11 Nov 2023 17:12:51 +0100 Subject: [PATCH 3/3] Show color picker button for color envelope points Simplify selecting envelope point colors by showing a color picker button that opens a color picker popup to change the color of the selected envelope point. The existing editbox to change only the selected channel's value is kept, as the color picker popup does not support the same precision to specify the individual color channel values. Closes #7317. --- src/game/editor/editor.cpp | 2 +- src/game/editor/popups.cpp | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index a39b935a8..22d43de19 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -6271,7 +6271,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) { static SPopupMenuId s_PopupEnvPointId; const auto &&ShowPopupEnvPoint = [&]() { - UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56, this, PopupEnvPoint); + UI()->DoPopupMenu(&s_PopupEnvPointId, UI()->MouseX(), UI()->MouseY(), 150, 56 + (pEnvelope->GetChannels() == 4 ? 16.0f : 0.0f), this, PopupEnvPoint); }; if(s_Operation == OP_NONE) diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 14ce6e499..3cddb4321 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -1296,10 +1296,34 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie pEditor->m_ShowEnvelopePreview = SHOWENV_SELECTED; + std::shared_ptr pEnvelope = pEditor->m_Map.m_vpEnvelopes[pEditor->m_SelectedEnvelope]; + + if(pEnvelope->GetChannels() == 4) + { + View.HSplitTop(RowHeight, &Row, &View); + View.HSplitTop(4.0f, nullptr, &View); + Row.VSplitLeft(60.0f, &Label, &Row); + Row.VSplitLeft(10.0f, nullptr, &EditBox); + pEditor->UI()->DoLabel(&Label, "Color:", RowHeight - 2.0f, TEXTALIGN_ML); + + const auto [SelectedIndex, _] = pEditor->m_vSelectedEnvelopePoints.front(); + auto *pValues = pEnvelope->m_vPoints[SelectedIndex].m_aValues; + const ColorRGBA Color = ColorRGBA(fx2f(pValues[0]), fx2f(pValues[1]), fx2f(pValues[2]), fx2f(pValues[3])); + const auto &&SetColor = [&](ColorRGBA NewColor) { + if(Color == NewColor) + return; + for(int Channel = 0; Channel < 4; ++Channel) + pValues[Channel] = f2fx(NewColor[Channel]); + pEditor->m_UpdateEnvPointInfo = true; + pEditor->m_Map.OnModify(); + }; + static char s_ColorPickerButton; + pEditor->DoColorPickerButton(&s_ColorPickerButton, &EditBox, Color, SetColor); + } + static CLineInputNumber s_CurValueInput; static CLineInputNumber s_CurTimeInput; - std::shared_ptr pEnvelope = pEditor->m_Map.m_vpEnvelopes[pEditor->m_SelectedEnvelope]; if(pEditor->m_UpdateEnvPointInfo) { pEditor->m_UpdateEnvPointInfo = false; @@ -1336,14 +1360,14 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie View.HSplitTop(RowHeight, &Row, &View); Row.VSplitLeft(60.0f, &Label, &Row); Row.VSplitLeft(10.0f, nullptr, &EditBox); - pEditor->UI()->DoLabel(&Label, "Value:", RowHeight - 2.0f, TEXTALIGN_LEFT); + pEditor->UI()->DoLabel(&Label, "Value:", RowHeight - 2.0f, TEXTALIGN_ML); pEditor->DoEditBox(&s_CurValueInput, &EditBox, RowHeight - 2.0f, IGraphics::CORNER_ALL, "The value of the selected envelope point"); - View.HMargin(4.0f, &View); + View.HSplitTop(4.0f, nullptr, &View); View.HSplitTop(RowHeight, &Row, &View); Row.VSplitLeft(60.0f, &Label, &Row); Row.VSplitLeft(10.0f, nullptr, &EditBox); - pEditor->UI()->DoLabel(&Label, "Time (in s):", RowHeight - 2.0f, TEXTALIGN_LEFT); + pEditor->UI()->DoLabel(&Label, "Time (in s):", RowHeight - 2.0f, TEXTALIGN_ML); pEditor->DoEditBox(&s_CurTimeInput, &EditBox, RowHeight - 2.0f, IGraphics::CORNER_ALL, "The time of the selected envelope point"); if(pEditor->Input()->KeyIsPressed(KEY_RETURN) || pEditor->Input()->KeyIsPressed(KEY_KP_ENTER)) @@ -1371,7 +1395,6 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie else { auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front(); - if(pEnvelope->GetChannels() == 4) CurrentValue = clamp(CurrentValue, 0.0f, 1.0f); pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] = f2fx(CurrentValue); @@ -1400,7 +1423,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie pEditor->m_Map.OnModify(); } - View.HMargin(6.0f, &View); + View.HSplitTop(6.0f, nullptr, &View); View.HSplitTop(RowHeight, &Row, &View); static int s_DeleteButtonID = 0; const char *pButtonText = pEditor->IsTangentSelected() ? "Reset" : "Delete";