diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index cf741f5884..87ae8a640a 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -16,6 +16,7 @@ #include "Common/System/System.h" #include "Common/TimeUtil.h" #include "Common/StringUtils.h" +#include "Common/Log.h" namespace UI { @@ -24,7 +25,6 @@ static constexpr float MIN_TEXT_SCALE = 0.8f; static constexpr float MAX_ITEM_SIZE = 65535.0f; void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured) { - *measured = sz; if (sz == WRAP_CONTENT) { if (spec.type == UNSPECIFIED) *measured = contentWidth; @@ -40,6 +40,8 @@ void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measure *measured = spec.size; } else if (spec.type == EXACTLY || (spec.type == AT_MOST && *measured > spec.size)) { *measured = spec.size; + } else { + *measured = sz; } } @@ -412,7 +414,7 @@ void ClickableItem::GetContentDimensions(const UIContext &dc, float &w, float &h } ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParams) { - if (!layoutParams) { + if (!layoutParams && autoExpand_) { if (layoutParams_->width == WRAP_CONTENT) layoutParams_->width = FILL_PARENT; } diff --git a/Common/UI/View.h b/Common/UI/View.h index 64c9cdacf8..fb26db156f 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -692,6 +692,11 @@ public: // Draws the item background. void Draw(UIContext &dc) override; + + void SetAutoExpand(bool autoExpand) { autoExpand_ = autoExpand; } + +private: + bool autoExpand_ = true; }; // Use to trigger something or open a submenu screen. diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 00d5c41f34..9c7960f2fe 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1593,6 +1593,7 @@ StickyChoice *ChoiceStrip::Choice(int index) { return static_cast(views_[index]); return nullptr; } + ListView::ListView(ListAdaptor *a, std::set hidden, LayoutParams *layoutParams) : ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a), maxHeight_(0), hidden_(hidden) { diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index ef4e2c83b5..06fc69a159 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -19,11 +19,11 @@ // Postprocessing shader manager // For FXAA, "Natural", bloom, B&W, cross processing and whatnot. +#pragma once + #include #include -#include "Common/Data/Format/IniFile.h" - struct ShaderInfo { Path iniFile; // which ini file was this definition in? So we can write settings back later std::string section; // ini file section. This is saved. diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 24d0c87301..fd80fa8daf 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -37,7 +37,6 @@ #include "Core/System.h" #include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" -#include "GPU/Common/PostShader.h" static const int leftColumnWidth = 200; static const float orgRatio = 1.764706f; // 480.0 / 272.0 @@ -196,7 +195,7 @@ void DisplayLayoutScreen::CreateViews() { // impossible. root_->SetExclusiveTouch(true); - ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); + ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(400.0f, FILL_PARENT, 10.f, 10.f, NONE, 10.f, false)); ViewGroup *leftColumn = new LinearLayout(ORIENT_VERTICAL); leftScrollView->Add(leftColumn); leftScrollView->SetClickableBackground(true); @@ -255,8 +254,6 @@ void DisplayLayoutScreen::CreateViews() { static const char *bufFilters[] = { "Linear", "Nearest", }; leftColumn->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); - leftColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); - Draw::DrawContext *draw = screenManager()->getDrawContext(); bool multiViewSupported = draw->GetDeviceCaps().multiViewSupported; @@ -265,12 +262,22 @@ void DisplayLayoutScreen::CreateViews() { return g_Config.bStereoRendering && multiViewSupported; }; + leftColumn->Add(new ItemHeader(gr->T("Postprocessing effect"))); + std::set alreadyAddedShader; + settingsVisible_.resize(g_Config.vPostShaderNames.size()); + 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]; - leftColumn->Add(new ItemHeader(StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1))); - postProcChoice_ = leftColumn->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName)); + + // TODO: I want to set UI::FILL_PARENT or an explicit width here, but breaks badly??? + LinearLayout *shaderRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::WRAP_CONTENT, UI::WRAP_CONTENT)); + shaderRow->SetSpacing(4.0f); + leftColumn->Add(shaderRow); + + postProcChoice_ = shaderRow->Add(new ChoiceWithValueDisplay(&shaderNames_[i], "", &PostShaderTranslateName, new LinearLayoutParams(1.0f))); + postProcChoice_->SetAutoExpand(false); postProcChoice_->OnClick.Add([=](EventParams &e) { auto gr = GetI18NCategory("Graphics"); auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i, false); @@ -285,11 +292,61 @@ void DisplayLayoutScreen::CreateViews() { return !g_Config.bSkipBufferEffects && !enableStereo(); }); + if (i < g_Config.vPostShaderNames.size()) { + bool hasSettings = false; + std::vector shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + hasSettings = true; + break; + } + } + } + if (hasSettings) { + auto settingsButton = shaderRow->Add(new Choice(ImageID("I_SLIDERS"))); + settingsButton->OnClick.Add([=](EventParams &e) { + settingsVisible_[i] = !settingsVisible_[i]; + RecreateViews(); + return UI::EVENT_DONE; + }); + } + } + + if (i > 0 && i < g_Config.vPostShaderNames.size()) { + auto upButton = shaderRow->Add(new Choice(ImageID("I_ARROW_UP"))); + 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"))); + 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"))); + 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()) continue; - auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + if (!settingsVisible_[i]) + continue; + + std::vector shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); for (auto shaderInfo : shaderChain) { // Disable duplicated shader slider bool duplicated = alreadyAddedShader.find(shaderInfo->section) != alreadyAddedShader.end(); @@ -300,6 +357,7 @@ void DisplayLayoutScreen::CreateViews() { for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { auto &setting = shaderInfo->settings[i]; if (!setting.name.empty()) { + // This map lookup will create the setting in the mPostShaderSetting map if it doesn't exist, with a default value of 0.0. auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; if (duplicated) { auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); @@ -320,3 +378,40 @@ void DisplayLayoutScreen::CreateViews() { root_->Add(new DisplayLayoutBackground(mode_, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, 0.0f, 0.0f, 0.0f, 0.0f))); } + +void PostProcScreen::CreateViews() { + auto ps = GetI18NCategory("PostShaders"); + ReloadAllPostShaderInfo(screenManager()->getDrawContext()); + shaders_ = GetAllPostShaderInfo(); + std::vector items; + int selected = -1; + const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; + + for (int i = 0; i < (int)shaders_.size(); i++) { + if (!shaders_[i].visible) + continue; + if (shaders_[i].isStereo != showStereoShaders_) + continue; + if (shaders_[i].section == selectedName) + selected = (int)indexTranslation_.size(); + items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); + indexTranslation_.push_back(i); + } + adaptor_ = UI::StringVectorListAdaptor(items, selected); + ListPopupScreen::CreateViews(); +} + +void PostProcScreen::OnCompleted(DialogResult result) { + if (result != DR_OK) + return; + 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; + } else { + if (id_ < (int)g_Config.vPostShaderNames.size()) + g_Config.vPostShaderNames[id_] = value; + else + g_Config.vPostShaderNames.push_back(value); + } +} diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 690bbfde55..d55d89d462 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -19,6 +19,8 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "GPU/Common/PostShader.h" + #include "MiscScreens.h" class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { @@ -45,4 +47,23 @@ private: UI::ChoiceStrip *mode_ = nullptr; UI::Choice *postProcChoice_ = nullptr; std::string shaderNames_[256]; + std::vector settingsVisible_; +}; + +class PostProcScreen : public ListPopupScreen { +public: + PostProcScreen(const std::string &title, int id, bool showStereoShaders) + : ListPopupScreen(title), id_(id), showStereoShaders_(showStereoShaders) { } + + void CreateViews() override; + + const char *tag() const override { return "PostProc"; } + +private: + void OnCompleted(DialogResult result) override; + bool ShowButtons() const override { return true; } + std::vector shaders_; + int id_; + bool showStereoShaders_; + std::vector indexTranslation_; }; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 505897dba6..e00ec856a0 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -551,45 +551,6 @@ void PromptScreen::TriggerFinish(DialogResult result) { UIDialogScreenWithBackground::TriggerFinish(result); } -PostProcScreen::PostProcScreen(const std::string &title, int id, bool showStereoShaders) : ListPopupScreen(title), id_(id), showStereoShaders_(showStereoShaders) { } - -void PostProcScreen::CreateViews() { - auto ps = GetI18NCategory("PostShaders"); - ReloadAllPostShaderInfo(screenManager()->getDrawContext()); - shaders_ = GetAllPostShaderInfo(); - std::vector items; - int selected = -1; - const std::string selectedName = id_ >= (int)g_Config.vPostShaderNames.size() ? "Off" : g_Config.vPostShaderNames[id_]; - - for (int i = 0; i < (int)shaders_.size(); i++) { - if (!shaders_[i].visible) - continue; - if (shaders_[i].isStereo != showStereoShaders_) - continue; - if (shaders_[i].section == selectedName) - selected = (int)indexTranslation_.size(); - items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); - indexTranslation_.push_back(i); - } - adaptor_ = UI::StringVectorListAdaptor(items, selected); - ListPopupScreen::CreateViews(); -} - -void PostProcScreen::OnCompleted(DialogResult result) { - if (result != DR_OK) - return; - 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; - } else { - if (id_ < (int)g_Config.vPostShaderNames.size()) - g_Config.vPostShaderNames[id_] = value; - else - g_Config.vPostShaderNames.push_back(value); - } -} - TextureShaderScreen::TextureShaderScreen(const std::string &title) : ListPopupScreen(title) {} void TextureShaderScreen::CreateViews() { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index f0eca81ff5..07f544f855 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -109,23 +109,6 @@ private: std::vector langs_; }; -class PostProcScreen : public ListPopupScreen { -public: - PostProcScreen(const std::string &title, int id, bool showStereoShaders); - - void CreateViews() override; - - const char *tag() const override { return "PostProc"; } - -private: - void OnCompleted(DialogResult result) override; - bool ShowButtons() const override { return true; } - std::vector shaders_; - int id_; - bool showStereoShaders_; - std::vector indexTranslation_; -}; - class TextureShaderScreen : public ListPopupScreen { public: TextureShaderScreen(const std::string &title);