From a83a3f9d5d709bd9831efd6e9d109bc22d6d950b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 7 Dec 2022 01:09:44 +0100 Subject: [PATCH] Declutter using a context menu, which I had to create from scratch. --- Common/UI/UIScreen.cpp | 41 ++++++++++++++++++--- Common/UI/UIScreen.h | 38 +++++++++++++++++-- Common/UI/View.cpp | 1 + UI/DisplayLayoutScreen.cpp | 75 ++++++++++++++++++++++++-------------- 4 files changed, 119 insertions(+), 36 deletions(-) diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index ff30080553..fb2371c3e4 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -312,10 +312,6 @@ void PopupScreen::TriggerFinish(DialogResult result) { } } -void PopupScreen::resized() { - RecreateViews(); -} - void PopupScreen::CreateViews() { using namespace UI; UIContext &dc = *screenManager()->getUIContext(); @@ -336,7 +332,9 @@ void PopupScreen::CreateViews() { box_->SetDropShadowExpand(std::max(dp_xres, dp_yres)); View *title = new PopupHeader(title_); - box_->Add(title); + if (HasTitleBar()) { + box_->Add(title); + } CreatePopupContents(box_); root_->SetDefaultFocusView(box_); @@ -403,6 +401,39 @@ UI::EventReturn ListPopupScreen::OnListChoice(UI::EventParams &e) { namespace UI { +PopupContextMenuScreen::PopupContextMenuScreen(const ContextMenuItem *items, size_t itemCount, I18NCategory *category, UI::View *sourceView) + : PopupScreen("", "", ""), items_(items), itemCount_(itemCount), category_(category), sourceView_(sourceView) +{ + enabled_.resize(itemCount, true); + SetPopupOrigin(sourceView); +} + +void PopupContextMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { + for (size_t i = 0; i < itemCount_; i++) { + if (items_[i].imageID) { + Choice *choice = new Choice(items_[i].text, ImageID(items_[i].imageID)); + parent->Add(choice); + if (enabled_[i]) { + choice->OnClick.Add([=](EventParams &p) { + TriggerFinish(DR_OK); + p.a = (uint32_t)i; + OnChoice.Dispatch(p); + return EVENT_DONE; + }); + } + else { + choice->SetEnabled(false); + } + } + } + + // Hacky: Override the position to look like a popup menu. + AnchorLayoutParams *ap = (AnchorLayoutParams *)parent->GetLayoutParams(); + ap->center = false; + ap->left = sourceView_->GetBounds().x; + ap->top = sourceView_->GetBounds().y2(); +} + std::string ChopTitle(const std::string &title) { size_t pos = title.find('\n'); if (pos != title.npos) { diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index d1f483f0fc..1b25dc4231 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -76,7 +76,6 @@ public: virtual bool isTransparent() const override { return true; } virtual bool touch(const TouchInput &touch) override; virtual bool key(const KeyInput &key) override; - virtual void resized() override; virtual void TriggerFinish(DialogResult result) override; @@ -91,6 +90,7 @@ protected: virtual bool ShowButtons() const { return true; } virtual bool CanComplete(DialogResult result) { return true; } virtual void OnCompleted(DialogResult result) {} + virtual bool HasTitleBar() const { return true; } const std::string &Title() { return title_; } virtual void update() override; @@ -250,7 +250,7 @@ public: Event OnChange; private: - virtual void OnCompleted(DialogResult result) override; + void OnCompleted(DialogResult result) override; TextEdit *edit_; std::string *value_; std::string textEditValue_; @@ -258,13 +258,45 @@ private: int maxLen_; }; +// TODO: Break out a lot of popup stuff from UIScreen.h. + +struct ContextMenuItem { + const char *text; + const char *imageID; +}; + +// Once a selection has been made, +class PopupContextMenuScreen : public PopupScreen { +public: + PopupContextMenuScreen(const ContextMenuItem *items, size_t itemCount, I18NCategory *category, UI::View *sourceView); + void CreatePopupContents(ViewGroup *parent) override; + + const char *tag() const override { return "ContextMenuPopup"; } + + void SetEnabled(size_t index, bool enabled) { + enabled_[index] = enabled; + } + + UI::Event OnChoice; + +protected: + bool HasTitleBar() const { return false; } + +private: + const ContextMenuItem *items_; + size_t itemCount_; + I18NCategory *category_; + UI::View *sourceView_; + std::vector enabled_; +}; + class AbstractChoiceWithValueDisplay : public UI::Choice { public: AbstractChoiceWithValueDisplay(const std::string &text, LayoutParams *layoutParams = nullptr) : Choice(text, layoutParams) { } - virtual void Draw(UIContext &dc) override; + void Draw(UIContext &dc) override; void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; protected: diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 48d6de8abf..c3bdf847d6 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -500,6 +500,7 @@ void Choice::Draw(UIContext &dc) { if (image_.isValid()) { const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(image_); + _dbg_assert_(image); paddingX += image->w + 6; availWidth -= image->w + 6; // TODO: Use scale rotation and flip here as well (DrawImageRotated is always ALIGN_CENTER for now) diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index cb20889c13..b3b6794616 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -23,6 +23,7 @@ #include "Common/Render/DrawBuffer.h" #include "Common/UI/Context.h" #include "Common/UI/View.h" +#include "Common/UI/UIScreen.h" #include "Common/Math/math_util.h" #include "Common/System/Display.h" #include "Common/System/NativeApp.h" @@ -267,6 +268,12 @@ void DisplayLayoutScreen::CreateViews() { std::set alreadyAddedShader; settingsVisible_.resize(g_Config.vPostShaderNames.size()); + static ContextMenuItem postShaderContextMenu[] = { + { "Move Up", "I_ARROW_UP" }, + { "Move Down", "I_ARROW_DOWN" }, + { "Remove", "I_TRASHCAN" }, + }; + for (int i = 0; i < (int)g_Config.vPostShaderNames.size() + 1 && i < ARRAY_SIZE(shaderNames_); ++i) { // Vector element pointer get invalidated on resize, cache name to have always a valid reference in the rendering thread shaderNames_[i] = i == g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[i]; @@ -310,32 +317,35 @@ void DisplayLayoutScreen::CreateViews() { return UI::EVENT_DONE; }); } + + auto moreButton = shaderRow->Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(0.0f))); + moreButton->OnClick.Add([=](EventParams &e) -> UI::EventReturn { + PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(postShaderContextMenu, ARRAY_SIZE(postShaderContextMenu), gr.get(), moreButton); + screenManager()->push(contextMenu); + contextMenu->SetEnabled(0, i > 0); + contextMenu->SetEnabled(1, i < g_Config.vPostShaderNames.size() - 1); + contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn { + switch (e.a) { + case 0: // Move up + std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); + break; + case 1: // Move down + std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); + break; + case 2: // Remove + g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); + break; + default: + return UI::EVENT_DONE; + } + NativeMessageReceived("gpu_configChanged", ""); + RecreateViews(); + return UI::EVENT_DONE; + }); + return UI::EVENT_DONE; + }); } - if (i > 0 && i < g_Config.vPostShaderNames.size()) { - auto upButton = shaderRow->Add(new Choice(ImageID("I_ARROW_UP"), new LinearLayoutParams(0.0f))); - upButton->OnClick.Add([=](EventParams &e) { - std::swap(g_Config.vPostShaderNames[i - 1], g_Config.vPostShaderNames[i]); - RecreateViews(); - return UI::EVENT_DONE; - }); - } - if (i < g_Config.vPostShaderNames.size() - 1) { - auto downButton = shaderRow->Add(new Choice(ImageID("I_ARROW_DOWN"), new LinearLayoutParams(0.0f))); - downButton->OnClick.Add([=](EventParams &e) { - std::swap(g_Config.vPostShaderNames[i], g_Config.vPostShaderNames[i + 1]); - RecreateViews(); - return UI::EVENT_DONE; - }); - } - if (i < g_Config.vPostShaderNames.size()) { - auto deleteButton = shaderRow->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(0.0f))); - deleteButton->OnClick.Add([=](EventParams &e) { - g_Config.vPostShaderNames.erase(g_Config.vPostShaderNames.begin() + i); - RecreateViews(); - return UI::EVENT_DONE; - }); - } // No need for settings on the last one. if (i == g_Config.vPostShaderNames.size()) @@ -405,11 +415,20 @@ void PostProcScreen::OnCompleted(DialogResult result) { const std::string &value = shaders_[indexTranslation_[listView_->GetSelected()]].section; // I feel this logic belongs more in the caller, but eh... if (showStereoShaders_) { - g_Config.sStereoToMonoShader = value; + if (g_Config.sStereoToMonoShader != value) { + g_Config.sStereoToMonoShader = value; + NativeMessageReceived("gpu_configChanged", ""); + } } else { - if (id_ < (int)g_Config.vPostShaderNames.size()) - g_Config.vPostShaderNames[id_] = value; - else + if (id_ < (int)g_Config.vPostShaderNames.size()) { + if (g_Config.vPostShaderNames[id_] != value) { + g_Config.vPostShaderNames[id_] = value; + NativeMessageReceived("gpu_configChanged", ""); + } + } + else { g_Config.vPostShaderNames.push_back(value); + NativeMessageReceived("gpu_configChanged", ""); + } } }