From d35577d3ed0bfc56ddf85a2e8b163d9d02bec809 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Mon, 8 May 2023 17:33:10 -0400 Subject: [PATCH] configuration: Implement slider --- src/common/settings.h | 13 +- .../configuration/configuration_shared.cpp | 203 ++++++++++++++---- src/yuzu/configuration/configuration_shared.h | 6 +- src/yuzu/configuration/configure_graphics.cpp | 31 ++- src/yuzu/configuration/configure_graphics.h | 2 - .../configure_graphics_advanced.cpp | 2 +- .../configure_graphics_advanced.h | 2 - 7 files changed, 188 insertions(+), 71 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index 2879237cc5..4ca8299b39 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -200,6 +200,8 @@ public: virtual bool RuntimeModfiable() const = 0; virtual void SetGlobal(bool global) {} virtual constexpr u32 Id() const = 0; + virtual std::string MinVal() const = 0; + virtual std::string MaxVal() const = 0; virtual bool UsingGlobal() const { return false; } @@ -336,7 +338,7 @@ protected: if constexpr (std::is_same()) { return value_; } else if constexpr (std::is_same>()) { - return value_.has_value() ? std::to_string(*value_) : "0"; + return value_.has_value() ? std::to_string(*value_) : "none"; } else if constexpr (std::is_same()) { return value_ ? "true" : "false"; } else { @@ -401,7 +403,7 @@ public: if constexpr (std::is_same()) { this->SetValue(input); } else if constexpr (std::is_same>()) { - this->SetValue(static_cast(std::stoll(input))); + this->SetValue(static_cast(std::stoul(input))); } else if constexpr (std::is_same()) { this->SetValue(input == "true"); } else { @@ -435,6 +437,13 @@ public: return id; } + virtual std::string MinVal() const override { + return this->ToString(minimum); + } + virtual std::string MaxVal() const override { + return this->ToString(maximum); + } + protected: Type value{}; ///< The setting const Type default_value{}; ///< The default value diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 45165c2e9b..076d9cc0d7 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -13,10 +13,14 @@ #include #include #include +#include +#include #include #include #include +#include #include +#include #include "common/settings.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_per_game.h" @@ -24,7 +28,7 @@ namespace ConfigurationShared { -static QPushButton* CreateClearGlobalButton(QWidget* parent, Settings::BasicSetting* setting) { +static QPushButton* CreateRestoreGlobalButton(QWidget* parent, Settings::BasicSetting* setting) { QStyle* style = parent->style(); QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_DialogResetButton)); QPushButton* button = new QPushButton(*icon, QStringLiteral(""), parent); @@ -40,10 +44,8 @@ static QPushButton* CreateClearGlobalButton(QWidget* parent, Settings::BasicSett return button; } -static std::pair> CreateCheckBox(Settings::BasicSetting* setting, - const QString& label, - QWidget* parent, - std::list& trackers) { +static std::tuple> CreateCheckBox( + Settings::BasicSetting* setting, const QString& label, QWidget* parent) { QWidget* widget = new QWidget(parent); QHBoxLayout* layout = new QHBoxLayout(widget); @@ -54,13 +56,15 @@ static std::pair> CreateCheckBox(Settings::Basic std::function load_func; + QPushButton* button{nullptr}; + layout->addWidget(checkbox); if (Settings::IsConfiguringGlobal()) { load_func = [setting, checkbox]() { setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); }; } else { - auto* button = CreateClearGlobalButton(parent, setting); + button = CreateRestoreGlobalButton(parent, setting); layout->addWidget(button); QObject::connect(checkbox, &QCheckBox::stateChanged, [button](int) { @@ -86,7 +90,7 @@ static std::pair> CreateCheckBox(Settings::Basic layout->setContentsMargins(0, 0, 0, 0); - return {widget, load_func}; + return {widget, checkbox, button, load_func}; } static std::tuple> CreateCombobox( @@ -122,7 +126,7 @@ static std::tuple> Cre setting->LoadString(std::to_string(combobox->currentIndex())); }; } else if (managed) { - button = CreateClearGlobalButton(parent, setting); + button = CreateRestoreGlobalButton(parent, setting); layout->addWidget(button); QObject::connect(button, &QAbstractButton::clicked, [button, combobox, setting](bool) { @@ -149,8 +153,8 @@ static std::tuple> Cre return {group, combobox, button, load_func}; } -static std::tuple> CreateLineEdit( - Settings::BasicSetting* setting, const QString& label, QWidget* parent) { +static std::tuple> CreateLineEdit( + Settings::BasicSetting* setting, const QString& label, QWidget* parent, bool managed = true) { QWidget* widget = new QWidget(parent); widget->setObjectName(label); @@ -160,58 +164,140 @@ static std::tuple> CreateLineEdit( const QString text = QString::fromStdString(setting->ToString()); line_edit->setText(text); - std::function load_func; + std::function load_func = []() {}; + QLabel* q_label = new QLabel(label, widget); // setSizePolicy lets widget expand and take an equal part of the space as the line edit - if (Settings::IsConfiguringGlobal()) { - QLabel* q_label = new QLabel(label, widget); - q_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - layout->addWidget(q_label); + q_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + layout->addWidget(q_label); + layout->addWidget(line_edit); + + QPushButton* button{nullptr}; + + if (Settings::IsConfiguringGlobal() && !managed) { load_func = [line_edit, setting]() { std::string load_text = line_edit->text().toStdString(); setting->LoadString(load_text); }; - } else { - QCheckBox* checkbox = new QCheckBox(label, parent); - checkbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - layout->addWidget(checkbox); + } else if (!managed) { + button = CreateRestoreGlobalButton(parent, setting); + layout->addWidget(button); - const auto highlight_func = [widget, line_edit](int state) { - bool using_global = state != Qt::Checked; - SetHighlight(widget, !using_global); - line_edit->setEnabled(!using_global); - }; + QObject::connect(button, &QAbstractButton::clicked, [=](bool) { + button->setEnabled(false); + button->setVisible(false); - QObject::connect(checkbox, qOverload(&QCheckBox::stateChanged), widget, - highlight_func); + line_edit->setText(QString::fromStdString(setting->ToStringGlobal())); + }); - checkbox->setCheckState(setting->UsingGlobal() ? Qt::Unchecked : Qt::Checked); - highlight_func(checkbox->checkState()); + QObject::connect(line_edit, &QLineEdit::textChanged, [=](QString) { + button->setEnabled(true); + button->setVisible(true); + }); - load_func = [checkbox, setting, line_edit]() { - if (checkbox->checkState() == Qt::Checked) { - setting->SetGlobal(false); - - std::string load_text = line_edit->text().toStdString(); - setting->LoadString(load_text); - } else { - setting->SetGlobal(true); + load_func = [=]() { + bool using_global = !button->isEnabled(); + setting->SetGlobal(using_global); + if (!using_global) { + setting->LoadString(line_edit->text().toStdString()); } }; } - layout->addWidget(line_edit); + layout->setContentsMargins(0, 0, 0, 0); + + return {widget, line_edit, button, load_func}; +} + +static std::tuple> CreateSlider( + Settings::BasicSetting* setting, const QString& name, QWidget* parent, bool reversed, + float multiplier) { + QWidget* widget = new QWidget(parent); + QHBoxLayout* layout = new QHBoxLayout(widget); + QSlider* slider = new QSlider(Qt::Horizontal, widget); + QLabel* label = new QLabel(name, widget); + QPushButton* button{nullptr}; + QLabel* feedback = new QLabel(widget); + + layout->addWidget(label); + layout->addWidget(slider); + layout->addWidget(feedback); + + label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); layout->setContentsMargins(0, 0, 0, 0); - return {widget, line_edit, load_func}; + int max_val = std::stoi(setting->MaxVal()); + + QObject::connect(slider, &QAbstractSlider::valueChanged, [=](int value) { + int present = (reversed ? max_val - value : value) * multiplier; + feedback->setText( + QStringLiteral("%1%").arg(QString::fromStdString(std::to_string(present)))); + }); + + slider->setValue(std::stoi(setting->ToString())); + slider->setMinimum(std::stoi(setting->MinVal())); + slider->setMaximum(max_val); + + if (reversed) { + slider->setInvertedAppearance(true); + } + + std::function load_func; + + if (Settings::IsConfiguringGlobal()) { + load_func = [=]() { setting->LoadString(std::to_string(slider->value())); }; + } else { + button = CreateRestoreGlobalButton(parent, setting); + layout->addWidget(button); + + QObject::connect(button, &QAbstractButton::clicked, [=](bool) { + slider->setValue(std::stoi(setting->ToStringGlobal())); + + button->setEnabled(false); + button->setVisible(false); + }); + + QObject::connect(slider, &QAbstractSlider::sliderMoved, [=](int) { + button->setEnabled(true); + button->setVisible(true); + }); + + load_func = [=]() { + bool using_global = !button->isEnabled(); + setting->SetGlobal(using_global); + if (!using_global) { + setting->LoadString(std::to_string(slider->value())); + } + }; + } + + return {widget, slider, button, []() {}}; +} + +static std::tuple> +CreateCheckBoxWithLineEdit(Settings::BasicSetting* setting, const QString& label, QWidget* parent) { + auto tuple = CreateCheckBox(setting, label, parent); + auto* widget = std::get<0>(tuple); + auto* checkbox = std::get<1>(tuple); + auto* button = std::get<2>(tuple); + auto load_func = std::get<3>(tuple); + QHBoxLayout* layout = dynamic_cast(widget->layout()); + + auto line_edit_tuple = CreateLineEdit(setting, label, parent, false); + auto* line_edit_widget = std::get<0>(line_edit_tuple); + auto* line_edit = std::get<1>(line_edit_tuple); + + layout->insertWidget(1, line_edit_widget); + + return {widget, checkbox, line_edit, button, load_func}; } std::tuple CreateWidget( Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, bool runtime_lock, std::forward_list>& apply_funcs, - std::list& trackers, RequestType request, bool managed) { + RequestType request, bool managed, float multiplier, const std::string& text_box_default) { if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) { LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting->GetLabel()); return {nullptr, nullptr, nullptr}; @@ -242,9 +328,27 @@ std::tuple CreateWidget( QPushButton* button; if (type == typeid(bool)) { - auto pair = CreateCheckBox(setting, label, parent, trackers); - widget = pair.first; - load_func = pair.second; + switch (request) { + case RequestType::Default: { + auto tuple = CreateCheckBox(setting, label, parent); + widget = std::get<0>(tuple); + extra = std::get<1>(tuple); + button = std::get<2>(tuple); + load_func = std::get<3>(tuple); + break; + } + case RequestType::LineEdit: { + auto tuple = CreateCheckBoxWithLineEdit(setting, label, parent); + widget = std::get<0>(tuple); + break; + } + case RequestType::ComboBox: + case RequestType::SpinBox: + case RequestType::Slider: + case RequestType::ReverseSlider: + case RequestType::MaxEnum: + break; + } } else if (setting->IsEnum()) { auto tuple = CreateCombobox(setting, label, parent, managed); widget = std::get<0>(tuple); @@ -253,11 +357,13 @@ std::tuple CreateWidget( load_func = std::get<3>(tuple); } else if (type == typeid(u32) || type == typeid(int)) { switch (request) { + case RequestType::LineEdit: case RequestType::Default: { auto tuple = CreateLineEdit(setting, label, parent); widget = std::get<0>(tuple); extra = std::get<1>(tuple); - load_func = std::get<2>(tuple); + button = std::get<2>(tuple); + load_func = std::get<3>(tuple); break; } case RequestType::ComboBox: { @@ -268,8 +374,17 @@ std::tuple CreateWidget( load_func = std::get<3>(tuple); break; } - case RequestType::SpinBox: case RequestType::Slider: + case RequestType::ReverseSlider: { + auto tuple = CreateSlider(setting, label, parent, request == RequestType::ReverseSlider, + multiplier); + widget = std::get<0>(tuple); + extra = std::get<1>(tuple); + button = std::get<2>(tuple); + load_func = std::get<3>(tuple); + break; + } + case RequestType::SpinBox: case RequestType::MaxEnum: break; } diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index 63df11d261..ef3b7c9a9f 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -48,14 +48,16 @@ enum class RequestType { ComboBox, SpinBox, Slider, + ReverseSlider, + LineEdit, MaxEnum, }; std::tuple CreateWidget( Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, bool runtime_lock, std::forward_list>& apply_funcs, - std::list& trackers, RequestType request = RequestType::Default, - bool managed = true); + RequestType request = RequestType::Default, bool managed = true, float multiplier = 1.0f, + const std::string& text_box_default = ""); // Global-aware apply and set functions diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 1145b6c43e..d3ca7e8cc0 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -97,7 +97,6 @@ ConfigureGraphics::ConfigureGraphics( Settings::values.bg_blue.GetValue())); UpdateAPILayout(); PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout - // SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition()); // VSync setting needs to be determined after populating the VSync combobox if (Settings::IsConfiguringGlobal()) { @@ -134,18 +133,13 @@ ConfigureGraphics::ConfigureGraphics( // } // UpdateBackgroundColorButton(new_bg_color); // }); + // ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); + // ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); api_combobox->setEnabled(!UISettings::values.has_broken_vulkan && api_combobox->isEnabled()); ui->api_widget->setEnabled( (!UISettings::values.has_broken_vulkan || Settings::IsConfiguringGlobal()) && ui->api_widget->isEnabled()); - // ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); - // ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); - - // connect(ui->fsr_sharpening_slider, &QSlider::valueChanged, this, - // &ConfigureGraphics::SetFSRIndicatorText); - // ui->fsr_sharpening_combobox->setVisible(!Settings::IsConfiguringGlobal()); - // ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal()); } void ConfigureGraphics::PopulateVSyncModeSelection() { @@ -230,11 +224,19 @@ void ConfigureGraphics::SetConfiguration() { setting->Id() == Settings::values.shader_backend.Id() || setting->Id() == Settings::values.vsync_mode.Id()) { return ConfigurationShared::CreateWidget( - setting, translations, this, runtime_lock, apply_funcs, trackers, + setting, translations, this, runtime_lock, apply_funcs, ConfigurationShared::RequestType::ComboBox, false); + } else if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) { + return ConfigurationShared::CreateWidget( + setting, translations, this, runtime_lock, apply_funcs, + ConfigurationShared::RequestType::ReverseSlider, true, 0.5f); + } else if (setting->Id() == Settings::values.use_speed_limit.Id()) { + return ConfigurationShared::CreateWidget( + setting, translations, this, runtime_lock, apply_funcs, + ConfigurationShared::RequestType::LineEdit, true, 1.0f, setting->ToString()); } else { return ConfigurationShared::CreateWidget(setting, translations, this, runtime_lock, - apply_funcs, trackers); + apply_funcs); } }(); @@ -251,12 +253,10 @@ void ConfigureGraphics::SetConfiguration() { QObject::connect(api_restore_global_button, &QAbstractButton::clicked, [=](bool) { UpdateAPILayout(); }); + // Detach API's restore button and place it where we want widget->layout()->removeWidget(api_restore_global_button); api_layout->addWidget(api_restore_global_button); } - } else if (setting->Id() == Settings::values.vulkan_device.Id()) { - api_layout->addWidget(widget); - api_combobox = reinterpret_cast(extra); } else if (setting->Id() == Settings::values.vulkan_device.Id()) { hold_api.push_front(widget); vulkan_device_combobox = reinterpret_cast(extra); @@ -284,11 +284,6 @@ void ConfigureGraphics::SetConfiguration() { } } -void ConfigureGraphics::SetFSRIndicatorText(int percentage) { - // ui->fsr_sharpening_value->setText( - // tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2))); -} - const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode, Settings::RendererBackend backend) const { switch (mode) { diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 12a588127b..a049458a8c 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -58,7 +58,6 @@ private: void RetrieveVulkanDevices(); - void SetFSRIndicatorText(int percentage); /* Turns a Vulkan present mode into a textual string for a UI * (and eventually for a human to read) */ const QString TranslateVSyncMode(VkPresentModeKHR mode, @@ -69,7 +68,6 @@ private: std::unique_ptr ui; QColor bg_color; - std::list trackers{}; std::forward_list> apply_funcs{}; std::vector& records; diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 8a53ad1111..4a38686935 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -33,7 +33,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { for (auto setting : Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) { auto [widget, extra, button] = ConfigurationShared::CreateWidget( - setting, translations, this, runtime_lock, apply_funcs, trackers); + setting, translations, this, runtime_lock, apply_funcs); if (widget == nullptr) { continue; diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 3ac6b4bce5..327134ee67 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -34,8 +34,6 @@ private: std::unique_ptr ui; - std::list trackers{}; - const Core::System& system; const ConfigurationShared::TranslationMap& translations; std::forward_list> apply_funcs;