From f66d617107e45f8213643f2bbaa5f58878c3d3a6 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Mon, 8 May 2023 22:37:03 -0400 Subject: [PATCH] configuration: Move CreateWidget to a class We were passing so many objects between the function and the caller that it needed to be redesigned. --- src/yuzu/CMakeLists.txt | 2 + src/yuzu/configuration/config.cpp | 3 + .../configuration/configuration_shared.cpp | 386 ------------------ src/yuzu/configuration/configuration_shared.h | 18 - src/yuzu/configuration/configure_general.cpp | 63 +-- src/yuzu/configuration/configure_graphics.cpp | 55 ++- src/yuzu/configuration/configure_graphics.h | 1 + .../configure_graphics_advanced.cpp | 8 +- src/yuzu/configuration/shared_widget.cpp | 360 ++++++++++++++++ src/yuzu/configuration/shared_widget.h | 64 +++ 10 files changed, 507 insertions(+), 453 deletions(-) create mode 100644 src/yuzu/configuration/shared_widget.cpp create mode 100644 src/yuzu/configuration/shared_widget.h diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 8b54e12689..899b758717 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -145,6 +145,8 @@ add_executable(yuzu configuration/input_profiles.h configuration/shared_translation.cpp configuration/shared_translation.h + configuration/shared_widget.cpp + configuration/shared_widget.h debugger/console.cpp debugger/console.h debugger/controller.cpp diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index c6a34e7870..08aa208593 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -1346,8 +1346,11 @@ void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const { if (!setting->Save()) { + LOG_DEBUG(Frontend, "Skipping \"{}\" marked for not saving", setting->GetLabel()); return; } + LOG_DEBUG(Frontend, "Saving {} setting \"{}\"...", global ? "global" : "custom", + setting->GetLabel()); const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString())); const QVariant default_value = QVariant::fromValue(QString::fromStdString(setting->DefaultToString())); diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 076d9cc0d7..dff70f04b6 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -28,392 +28,6 @@ namespace ConfigurationShared { -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); - button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); - - QSizePolicy sp_retain = button->sizePolicy(); - sp_retain.setRetainSizeWhenHidden(true); - button->setSizePolicy(sp_retain); - - button->setEnabled(!setting->UsingGlobal()); - button->setVisible(!setting->UsingGlobal()); - - return button; -} - -static std::tuple> CreateCheckBox( - Settings::BasicSetting* setting, const QString& label, QWidget* parent) { - QWidget* widget = new QWidget(parent); - QHBoxLayout* layout = new QHBoxLayout(widget); - - QCheckBox* checkbox = new QCheckBox(label, parent); - checkbox->setObjectName(QString::fromStdString(setting->GetLabel())); - checkbox->setCheckState(setting->ToString() == "true" ? Qt::CheckState::Checked - : Qt::CheckState::Unchecked); - - 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 { - button = CreateRestoreGlobalButton(parent, setting); - layout->addWidget(button); - - QObject::connect(checkbox, &QCheckBox::stateChanged, [button](int) { - button->setVisible(true); - button->setEnabled(true); - }); - - QObject::connect(button, &QAbstractButton::clicked, [checkbox, setting, button](bool) { - checkbox->setCheckState(setting->ToStringGlobal() == "true" ? Qt::Checked - : Qt::Unchecked); - button->setEnabled(false); - button->setVisible(false); - }); - - load_func = [setting, checkbox, button]() { - bool using_global = !button->isEnabled(); - setting->SetGlobal(using_global); - if (!using_global) { - setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); - } - }; - } - - layout->setContentsMargins(0, 0, 0, 0); - - return {widget, checkbox, button, load_func}; -} - -static std::tuple> CreateCombobox( - Settings::BasicSetting* setting, const QString& label, QWidget* parent, bool managed) { - const auto type = setting->TypeId(); - - QWidget* group = new QWidget(parent); - group->setObjectName(QString::fromStdString(setting->GetLabel())); - QLayout* layout = new QHBoxLayout(group); - - QLabel* qt_label = new QLabel(label, parent); - QComboBox* combobox = new QComboBox(parent); - - QPushButton* button{nullptr}; - - std::forward_list combobox_enumerations = ComboboxEnumeration(type, parent); - for (const auto& item : combobox_enumerations) { - combobox->addItem(item); - } - - layout->addWidget(qt_label); - layout->addWidget(combobox); - - layout->setSpacing(6); - layout->setContentsMargins(0, 0, 0, 0); - - combobox->setCurrentIndex(std::stoi(setting->ToString())); - - std::function load_func = []() {}; - - if (Settings::IsConfiguringGlobal() && managed) { - load_func = [setting, combobox]() { - setting->LoadString(std::to_string(combobox->currentIndex())); - }; - } else if (managed) { - button = CreateRestoreGlobalButton(parent, setting); - layout->addWidget(button); - - QObject::connect(button, &QAbstractButton::clicked, [button, combobox, setting](bool) { - button->setEnabled(false); - button->setVisible(false); - - combobox->setCurrentIndex(std::stoi(setting->ToStringGlobal())); - }); - - QObject::connect(combobox, QOverload::of(&QComboBox::activated), [=](int) { - button->setEnabled(true); - button->setVisible(true); - }); - - load_func = [setting, combobox, button]() { - bool using_global = !button->isEnabled(); - setting->SetGlobal(using_global); - if (!using_global) { - setting->LoadString(std::to_string(combobox->currentIndex())); - } - }; - } - - return {group, combobox, button, load_func}; -} - -static std::tuple> CreateLineEdit( - Settings::BasicSetting* setting, const QString& label, QWidget* parent, bool managed = true) { - QWidget* widget = new QWidget(parent); - widget->setObjectName(label); - - QHBoxLayout* layout = new QHBoxLayout(widget); - QLineEdit* line_edit = new QLineEdit(parent); - - const QString text = QString::fromStdString(setting->ToString()); - line_edit->setText(text); - - 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 - 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 if (!managed) { - button = CreateRestoreGlobalButton(parent, setting); - layout->addWidget(button); - - QObject::connect(button, &QAbstractButton::clicked, [=](bool) { - button->setEnabled(false); - button->setVisible(false); - - line_edit->setText(QString::fromStdString(setting->ToStringGlobal())); - }); - - QObject::connect(line_edit, &QLineEdit::textChanged, [=](QString) { - button->setEnabled(true); - button->setVisible(true); - }); - - load_func = [=]() { - bool using_global = !button->isEnabled(); - setting->SetGlobal(using_global); - if (!using_global) { - setting->LoadString(line_edit->text().toStdString()); - } - }; - } - - 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); - - 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, - 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}; - } - - const auto type = setting->TypeId(); - const int id = setting->Id(); - QWidget* widget{nullptr}; - void* extra{nullptr}; - - std::function load_func; - - const auto [label, tooltip] = [&]() { - const auto& setting_label = setting->GetLabel(); - if (translations.contains(id)) { - return std::pair{translations.at(id).first, translations.at(id).second}; - } - LOG_ERROR(Frontend, "Translation table lacks entry for \"{}\"", setting_label); - return std::pair{QString::fromStdString(setting_label), QStringLiteral("")}; - }(); - - if (label == QStringLiteral("")) { - LOG_DEBUG(Frontend, "Translation table has emtpy entry for \"{}\", skipping...", - setting->GetLabel()); - return {nullptr, nullptr, nullptr}; - } - - QPushButton* button; - - if (type == typeid(bool)) { - 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); - extra = std::get<1>(tuple); - button = std::get<2>(tuple); - 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); - button = std::get<2>(tuple); - load_func = std::get<3>(tuple); - break; - } - case RequestType::ComboBox: { - auto tuple = CreateCombobox(setting, label, parent, managed); - widget = std::get<0>(tuple); - extra = std::get<1>(tuple); - button = std::get<2>(tuple); - load_func = std::get<3>(tuple); - break; - } - 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; - } - } - - if (widget == nullptr) { - LOG_ERROR(Frontend, "No widget was created for \"{}\"", setting->GetLabel()); - return {nullptr, nullptr, nullptr}; - } - - apply_funcs.push_front([load_func, setting](bool powered_on) { - if (setting->RuntimeModfiable() || !powered_on) { - load_func(); - } - }); - - bool enable = runtime_lock || setting->RuntimeModfiable(); - if (setting->Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) { - enable &= !setting->UsingGlobal(); - } - widget->setEnabled(enable); - - widget->setVisible(Settings::IsConfiguringGlobal() || setting->Switchable()); - - widget->setToolTip(tooltip); - - return {widget, extra, button}; -} - Tab::Tab(std::shared_ptr> group_, QWidget* parent) : QWidget(parent), group{group_} { if (group != nullptr) { diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index ef3b7c9a9f..0a0a92ae5b 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -13,8 +13,6 @@ #include "common/settings.h" #include "yuzu/configuration/shared_translation.h" -class QPushButton; - namespace ConfigurationShared { class Tab : public QWidget { @@ -43,22 +41,6 @@ enum class CheckState { Count, // Simply the number of states, not a valid checkbox state }; -enum class RequestType { - Default, - 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, - RequestType request = RequestType::Default, bool managed = true, float multiplier = 1.0f, - const std::string& text_box_default = ""); - // Global-aware apply and set functions // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 8c6fee2a5e..764ff68b38 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -21,10 +21,10 @@ ConfigureGeneral::ConfigureGeneral( SetConfiguration(); - if (Settings::IsConfiguringGlobal()) { - connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, - [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); }); - } + // if (Settings::IsConfiguringGlobal()) { + // connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, + // [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); }); + // } connect(ui->button_reset_defaults, &QPushButton::clicked, this, &ConfigureGeneral::ResetDefaults); @@ -46,17 +46,17 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_controller_applet_disabled->setChecked( UISettings::values.controller_applet_disabled.GetValue()); - ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); - ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); + // ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); + // ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); ui->button_reset_defaults->setEnabled(runtime_lock); - if (Settings::IsConfiguringGlobal()) { - ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue()); - } else { - ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && - use_speed_limit != ConfigurationShared::CheckState::Global); - } + // if (Settings::IsConfiguringGlobal()) { + // ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue()); + // } else { + // ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && + // use_speed_limit != ConfigurationShared::CheckState::Global); + // } } // Called to set the callback when resetting settings to defaults @@ -91,20 +91,20 @@ void ConfigureGeneral::ApplyConfiguration() { ui->toggle_controller_applet_disabled->isChecked(); // Guard if during game and set to game-specific value - if (Settings::values.use_speed_limit.UsingGlobal()) { - Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == - Qt::Checked); - Settings::values.speed_limit.SetValue(ui->speed_limit->value()); - } + // if (Settings::values.use_speed_limit.UsingGlobal()) { + // Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == + // Qt::Checked); + // Settings::values.speed_limit.SetValue(ui->speed_limit->value()); + // } } else { - bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global; - Settings::values.use_speed_limit.SetGlobal(global_speed_limit); - Settings::values.speed_limit.SetGlobal(global_speed_limit); - if (!global_speed_limit) { - Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == - Qt::Checked); - Settings::values.speed_limit.SetValue(ui->speed_limit->value()); - } + // bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global; + // Settings::values.use_speed_limit.SetGlobal(global_speed_limit); + // Settings::values.speed_limit.SetGlobal(global_speed_limit); + // if (!global_speed_limit) { + // Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == + // Qt::Checked); + // Settings::values.speed_limit.SetValue(ui->speed_limit->value()); + // } } } @@ -125,8 +125,8 @@ void ConfigureGeneral::SetupPerGameUI() { // Disables each setting if: // - A game is running (thus settings in use), and // - A non-global setting is applied. - ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal()); - ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal()); + // ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal()); + // ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal()); return; } @@ -144,8 +144,9 @@ void ConfigureGeneral::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, use_multi_core); - connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { - ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && - (use_speed_limit != ConfigurationShared::CheckState::Global)); - }); + // connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { + // ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && + // (use_speed_limit != + // ConfigurationShared::CheckState::Global)); + // }); } diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index d3ca7e8cc0..093e336256 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include "ui_configure_graphics.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics.h" +#include "yuzu/configuration/shared_widget.h" #include "yuzu/qt_common.h" #include "yuzu/uisettings.h" #include "yuzu/vk_device_info.h" @@ -219,35 +221,38 @@ void ConfigureGraphics::SetConfiguration() { for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) { const auto& setting_label = setting->GetLabel(); - auto [widget, extra, button] = [&]() { + ConfigurationShared::Widget* widget = [&]() { if (setting->Id() == Settings::values.vulkan_device.Id() || setting->Id() == Settings::values.shader_backend.Id() || setting->Id() == Settings::values.vsync_mode.Id()) { - return ConfigurationShared::CreateWidget( + return new ConfigurationShared::Widget( setting, translations, this, runtime_lock, apply_funcs, ConfigurationShared::RequestType::ComboBox, false); } else if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) { - return ConfigurationShared::CreateWidget( + return new ConfigurationShared::Widget( 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( + return new ConfigurationShared::Widget( setting, translations, this, runtime_lock, apply_funcs, - ConfigurationShared::RequestType::LineEdit, true, 1.0f, setting->ToString()); + ConfigurationShared::RequestType::LineEdit, true, 1.0f, + Settings::values.speed_limit.ToString()); } else { - return ConfigurationShared::CreateWidget(setting, translations, this, runtime_lock, - apply_funcs); + return new ConfigurationShared::Widget(setting, translations, this, runtime_lock, + apply_funcs); } }(); - if (widget == nullptr) { + if (!widget->Valid()) { + LOG_DEBUG(Frontend, "Deleted widget for \"{}\"", setting->GetLabel()); + delete widget; continue; } if (setting->Id() == Settings::values.renderer_backend.Id()) { api_grid_layout->addWidget(widget); - api_combobox = reinterpret_cast(extra); - api_restore_global_button = button; + api_combobox = widget->combobox; + api_restore_global_button = widget->restore_button; if (!Settings::IsConfiguringGlobal()) { QObject::connect(api_restore_global_button, &QAbstractButton::clicked, @@ -259,14 +264,33 @@ void ConfigureGraphics::SetConfiguration() { } } else if (setting->Id() == Settings::values.vulkan_device.Id()) { hold_api.push_front(widget); - vulkan_device_combobox = reinterpret_cast(extra); + vulkan_device_combobox = widget->combobox; vulkan_device_widget = widget; } else if (setting->Id() == Settings::values.shader_backend.Id()) { hold_api.push_front(widget); - shader_backend_combobox = reinterpret_cast(extra); + shader_backend_combobox = widget->combobox; shader_backend_widget = widget; + } else if (setting->Id() == Settings::values.use_speed_limit.Id()) { + apply_funcs.push_front([setting, widget](bool powered_on) { + if (!setting->RuntimeModfiable() && powered_on) { + return; + } + + u16 value = QVariant(widget->line_edit->text()).value(); + auto& speed_limit = Settings::values.speed_limit; + if (Settings::IsConfiguringGlobal()) { + speed_limit.SetValue(value); + } else { + bool using_global = !widget->restore_button->isVisible(); + speed_limit.SetGlobal(using_global); + if (!using_global) { + speed_limit.SetValue(value); + } + } + }); + hold_graphics[setting->IsEnum()][setting_label] = widget; } else if (setting->Id() == Settings::values.vsync_mode.Id()) { - vsync_mode_combobox = reinterpret_cast(extra); + vsync_mode_combobox = widget->combobox; hold_graphics[setting->IsEnum()][setting_label] = widget; } else { hold_graphics[setting->IsEnum()][setting_label] = widget; @@ -360,6 +384,7 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) { } void ConfigureGraphics::UpdateAPILayout() { + bool runtime_lock = !system.IsPoweredOn(); if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) { vulkan_device = Settings::values.vulkan_device.GetValue(true); shader_backend = Settings::values.shader_backend.GetValue(true); @@ -368,8 +393,8 @@ void ConfigureGraphics::UpdateAPILayout() { } else { vulkan_device = Settings::values.vulkan_device.GetValue(); shader_backend = Settings::values.shader_backend.GetValue(); - vulkan_device_widget->setEnabled(true); - shader_backend_widget->setEnabled(true); + vulkan_device_widget->setEnabled(runtime_lock); + shader_backend_widget->setEnabled(runtime_lock); } switch (GetCurrentGraphicsBackend()) { diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index a049458a8c..4ef551341a 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -15,6 +15,7 @@ #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" +class QPushButton; class QEvent; class QObject; class QComboBox; diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 4a38686935..4f57a7ae6d 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -8,6 +8,7 @@ #include "ui_configure_graphics_advanced.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_advanced.h" +#include "yuzu/configuration/shared_widget.h" ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( const Core::System& system_, @@ -32,10 +33,11 @@ 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); + ConfigurationShared::Widget* widget = + new ConfigurationShared::Widget(setting, translations, this, runtime_lock, apply_funcs); - if (widget == nullptr) { + if (!widget->Valid()) { + delete widget; continue; } diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp new file mode 100644 index 0000000000..0676973a91 --- /dev/null +++ b/src/yuzu/configuration/shared_widget.cpp @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common/settings.h" +#include "yuzu/configuration/shared_translation.h" +#include "yuzu/configuration/shared_widget.h" + +namespace ConfigurationShared { + +void Widget::CreateRestoreGlobalButton() { + QStyle* style = this->style(); + QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_DialogResetButton)); + restore_button = new QPushButton(*icon, QStringLiteral(""), this); + restore_button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); + + QSizePolicy sp_retain = restore_button->sizePolicy(); + sp_retain.setRetainSizeWhenHidden(true); + restore_button->setSizePolicy(sp_retain); + + restore_button->setEnabled(!setting.UsingGlobal()); + restore_button->setVisible(!setting.UsingGlobal()); +} + +void Widget::CreateCheckBox(const QString& label, std::function& load_func) { + created = true; + + QHBoxLayout* layout = new QHBoxLayout(this); + + checkbox = new QCheckBox(label, this); + checkbox->setObjectName(QString::fromStdString(setting.GetLabel())); + checkbox->setCheckState(setting.ToString() == "true" ? Qt::CheckState::Checked + : Qt::CheckState::Unchecked); + + layout->addWidget(checkbox); + if (Settings::IsConfiguringGlobal()) { + load_func = [=]() { + setting.LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); + }; + } else { + CreateRestoreGlobalButton(); + layout->addWidget(restore_button); + + QObject::connect(checkbox, &QCheckBox::stateChanged, [&](int) { + restore_button->setVisible(true); + restore_button->setEnabled(true); + }); + + QObject::connect(restore_button, &QAbstractButton::clicked, [&](bool) { + checkbox->setCheckState(setting.ToStringGlobal() == "true" ? Qt::Checked + : Qt::Unchecked); + restore_button->setEnabled(false); + restore_button->setVisible(false); + }); + + load_func = [=]() { + bool using_global = !restore_button->isEnabled(); + setting.SetGlobal(using_global); + if (!using_global) { + setting.LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); + } + }; + } + + layout->setContentsMargins(0, 0, 0, 0); +} + +void Widget::CreateCombobox(const QString& label, bool managed, std::function& load_func) { + created = true; + + const auto type = setting.TypeId(); + + QLayout* layout = new QHBoxLayout(this); + + QLabel* qt_label = new QLabel(label, this); + combobox = new QComboBox(this); + + std::forward_list combobox_enumerations = ComboboxEnumeration(type, this); + for (const auto& item : combobox_enumerations) { + combobox->addItem(item); + } + + layout->addWidget(qt_label); + layout->addWidget(combobox); + + layout->setSpacing(6); + layout->setContentsMargins(0, 0, 0, 0); + + combobox->setCurrentIndex(std::stoi(setting.ToString())); + + if (Settings::IsConfiguringGlobal() && managed) { + load_func = [=]() { setting.LoadString(std::to_string(combobox->currentIndex())); }; + } else if (managed) { + CreateRestoreGlobalButton(); + layout->addWidget(restore_button); + + QObject::connect(restore_button, &QAbstractButton::clicked, [&](bool) { + restore_button->setEnabled(false); + restore_button->setVisible(false); + + combobox->setCurrentIndex(std::stoi(setting.ToStringGlobal())); + }); + + QObject::connect(combobox, QOverload::of(&QComboBox::activated), [=](int) { + restore_button->setEnabled(true); + restore_button->setVisible(true); + }); + + load_func = [=]() { + bool using_global = !restore_button->isEnabled(); + setting.SetGlobal(using_global); + if (!using_global) { + setting.LoadString(std::to_string(combobox->currentIndex())); + } + }; + } +} + +void Widget::CreateLineEdit(const QString& label, bool managed, std::function& load_func) { + created = true; + + QHBoxLayout* layout = new QHBoxLayout(this); + line_edit = new QLineEdit(this); + + const QString text = QString::fromStdString(setting.ToString()); + line_edit->setText(text); + + QLabel* q_label = new QLabel(label, this); + // setSizePolicy lets widget expand and take an equal part of the space as the line edit + q_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + layout->addWidget(q_label); + + layout->addWidget(line_edit); + + if (Settings::IsConfiguringGlobal() && !managed) { + load_func = [=]() { + std::string load_text = line_edit->text().toStdString(); + setting.LoadString(load_text); + }; + } else if (!managed) { + CreateRestoreGlobalButton(); + layout->addWidget(restore_button); + + QObject::connect(restore_button, &QAbstractButton::clicked, [&](bool) { + restore_button->setEnabled(false); + restore_button->setVisible(false); + + line_edit->setText(QString::fromStdString(setting.ToStringGlobal())); + }); + + QObject::connect(line_edit, &QLineEdit::textChanged, [&](QString) { + restore_button->setEnabled(true); + restore_button->setVisible(true); + }); + + load_func = [=]() { + bool using_global = !restore_button->isEnabled(); + setting.SetGlobal(using_global); + if (!using_global) { + setting.LoadString(line_edit->text().toStdString()); + } + }; + } + + layout->setContentsMargins(0, 0, 0, 0); +} + +void Widget::CreateSlider(const QString& name, bool reversed, float multiplier, + std::function& load_func) { + created = true; + + QHBoxLayout* layout = new QHBoxLayout(this); + slider = new QSlider(Qt::Horizontal, this); + QLabel* label = new QLabel(name, this); + QLabel* feedback = new QLabel(this); + + layout->addWidget(label); + layout->addWidget(slider); + layout->addWidget(feedback); + + label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + layout->setContentsMargins(0, 0, 0, 0); + + 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); + } + + if (Settings::IsConfiguringGlobal()) { + load_func = [=]() { setting.LoadString(std::to_string(slider->value())); }; + } else { + CreateRestoreGlobalButton(); + layout->addWidget(restore_button); + + QObject::connect(restore_button, &QAbstractButton::clicked, [=](bool) { + slider->setValue(std::stoi(setting.ToStringGlobal())); + + restore_button->setEnabled(false); + restore_button->setVisible(false); + }); + + QObject::connect(slider, &QAbstractSlider::sliderMoved, [=](int) { + restore_button->setEnabled(true); + restore_button->setVisible(true); + }); + + load_func = [=]() { + bool using_global = !restore_button->isEnabled(); + setting.SetGlobal(using_global); + if (!using_global) { + setting.LoadString(std::to_string(slider->value())); + } + }; + } +} + +void Widget::CreateCheckBoxWithLineEdit(const QString& label, const std::string& text_box_default, + std::function& load_func) { + created = true; + + CreateCheckBox(label, load_func); + + QHBoxLayout* layout = reinterpret_cast(this->layout()); + + line_edit = new QLineEdit(this); + line_edit->setText(QString::fromStdString(text_box_default)); + + checkbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + layout->insertWidget(1, line_edit); + + QObject::connect(line_edit, &QLineEdit::textEdited, + [=](const QString&) { checkbox->setCheckState(Qt::Checked); }); + + if (!Settings::IsConfiguringGlobal()) { + QObject::connect(restore_button, &QAbstractButton::clicked, [=](bool) { + line_edit->setText(QString::fromStdString(text_box_default)); + }); + + QObject::connect(line_edit, &QLineEdit::textEdited, [=](const QString&) { + restore_button->setEnabled(true); + restore_button->setVisible(true); + }); + } +} + +bool Widget::Valid() { + return created; +} + +Widget::~Widget() = default; + +Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translations_, + QWidget* parent_, bool runtime_lock, + std::forward_list>& apply_funcs, RequestType request, + bool managed, float multiplier, const std::string& text_box_default) + : QWidget(parent_), parent{parent_}, translations{translations_}, setting{*setting_} { + if (!Settings::IsConfiguringGlobal() && !setting.Switchable()) { + LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting.GetLabel()); + return; + } + + const auto type = setting.TypeId(); + const int id = setting.Id(); + + const auto [label, tooltip] = [&]() { + const auto& setting_label = setting.GetLabel(); + if (translations.contains(id)) { + return std::pair{translations.at(id).first, translations.at(id).second}; + } + LOG_WARNING(Frontend, "Translation table lacks entry for \"{}\"", setting_label); + return std::pair{QString::fromStdString(setting_label), QStringLiteral("")}; + }(); + + if (label == QStringLiteral("")) { + LOG_DEBUG(Frontend, "Translation table has emtpy entry for \"{}\", skipping...", + setting.GetLabel()); + return; + } + + std::function load_func = []() {}; + + if (type == typeid(bool)) { + switch (request) { + case RequestType::Default: + CreateCheckBox(label, load_func); + break; + case RequestType::LineEdit: + case RequestType::SpinBox: + CreateCheckBoxWithLineEdit(label, text_box_default, load_func); + break; + case RequestType::ComboBox: + case RequestType::Slider: + case RequestType::ReverseSlider: + case RequestType::MaxEnum: + break; + } + } else if (setting.IsEnum()) { + CreateCombobox(label, managed, load_func); + } else if (type == typeid(u32) || type == typeid(int)) { + switch (request) { + case RequestType::Slider: + case RequestType::ReverseSlider: + CreateSlider(label, request == RequestType::ReverseSlider, multiplier, load_func); + break; + case RequestType::LineEdit: + case RequestType::Default: + CreateLineEdit(label, managed, load_func); + break; + case RequestType::ComboBox: + CreateCombobox(label, managed, load_func); + break; + case RequestType::SpinBox: + case RequestType::MaxEnum: + break; + } + } + + if (!created) { + LOG_ERROR(Frontend, "No widget was created for \"{}\"", setting.GetLabel()); + return; + } + + apply_funcs.push_front([load_func, setting_](bool powered_on) { + LOG_DEBUG(Frontend, "{}", setting_->GetLabel()); + if (setting_->RuntimeModfiable() || !powered_on) { + load_func(); + } + }); + + bool enable = runtime_lock || setting.RuntimeModfiable(); + if (setting.Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) { + enable &= setting.UsingGlobal(); + } + this->setEnabled(enable); + + this->setVisible(Settings::IsConfiguringGlobal() || setting.Switchable()); + + this->setToolTip(tooltip); +} + +} // namespace ConfigurationShared diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h new file mode 100644 index 0000000000..559a27b413 --- /dev/null +++ b/src/yuzu/configuration/shared_widget.h @@ -0,0 +1,64 @@ +#include "yuzu/configuration/configuration_shared.h" +#include "yuzu/configuration/shared_translation.h" + +class QPushButton; +class QComboBox; +class QLineEdit; +class QSlider; +class QCheckBox; + +namespace Settings { +class BasicSetting; +} + +namespace ConfigurationShared { + +enum class RequestType { + Default, + ComboBox, + SpinBox, + Slider, + ReverseSlider, + LineEdit, + MaxEnum, +}; + +class Widget : public QWidget { + Q_OBJECT + +public: + Widget(Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, + bool runtime_lock, std::forward_list>& apply_funcs, + RequestType request = RequestType::Default, bool managed = true, float multiplier = 1.0f, + const std::string& text_box_default = ""); + virtual ~Widget(); + + bool Valid(); + + QPushButton* restore_button{}; + QLineEdit* line_edit{}; + QCheckBox* checkbox{}; + QSlider* slider{}; + QComboBox* combobox{}; + +private: + void CreateCheckBox(const QString& label, std::function& load_func); + void CreateCheckBoxWithLineEdit(const QString& label, const std::string& text_box_default, + std::function& load_func); + void CreateCheckBoxWithSpinBox(const QString& label, const std::string& text_box_default, + std::function& load_func); + void CreateCombobox(const QString& label, bool managed, std::function& load_func); + void CreateLineEdit(const QString& label, bool managed, std::function& load_func); + void CreateSlider(const QString& label, bool reversed, float multiplier, + std::function& load_func); + + void CreateRestoreGlobalButton(); + + QWidget* parent; + const TranslationMap& translations; + Settings::BasicSetting& setting; + + bool created{false}; +}; + +} // namespace ConfigurationShared