From ad645c29a44bd117cad90bda56e1f4d6296f2666 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Wed, 21 Jun 2023 01:42:42 -0400
Subject: [PATCH] configuration: Use a builder to create widgets

This gets rid of some repeated code and sets us up to send more
information to the new widget.
---
 src/yuzu/configuration/configure_audio.cpp    | 38 ++++++--------
 src/yuzu/configuration/configure_audio.h      | 18 +++----
 src/yuzu/configuration/configure_cpu.cpp      | 23 ++++-----
 src/yuzu/configuration/configure_cpu.h        | 12 ++---
 src/yuzu/configuration/configure_dialog.cpp   | 23 ++++-----
 src/yuzu/configuration/configure_dialog.h     |  4 +-
 src/yuzu/configuration/configure_general.cpp  | 19 ++++---
 src/yuzu/configuration/configure_general.h    | 19 +++----
 src/yuzu/configuration/configure_graphics.cpp | 32 +++++-------
 src/yuzu/configuration/configure_graphics.h   | 23 +++++----
 .../configure_graphics_advanced.cpp           | 21 ++++----
 .../configure_graphics_advanced.h             | 13 ++---
 src/yuzu/configuration/configure_per_game.cpp | 19 +++----
 src/yuzu/configuration/configure_per_game.h   |  4 +-
 src/yuzu/configuration/configure_system.cpp   | 43 +++++++---------
 src/yuzu/configuration/configure_system.h     | 19 ++++---
 src/yuzu/configuration/shared_widget.cpp      | 35 ++++++++++---
 src/yuzu/configuration/shared_widget.h        | 50 +++++++++++--------
 18 files changed, 206 insertions(+), 209 deletions(-)

diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 8c5378925..6db47fd61 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -16,23 +16,19 @@
 #include "yuzu/configuration/shared_widget.h"
 #include "yuzu/uisettings.h"
 
-ConfigureAudio::ConfigureAudio(
-    const Core::System& system_,
-    std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
-    const ConfigurationShared::TranslationMap& translations_,
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations_, QWidget* parent)
-    : Tab(group_, parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_},
-      translations{translations_}, combobox_translations{combobox_translations_} {
+ConfigureAudio::ConfigureAudio(const Core::System& system_,
+                               std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
+                               const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {
     ui->setupUi(this);
-    Setup();
+    Setup(builder);
 
     SetConfiguration();
 }
 
 ConfigureAudio::~ConfigureAudio() = default;
 
-void ConfigureAudio::Setup() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
     auto& layout = *ui->audio_widget->layout();
 
     std::forward_list<Settings::BasicSetting*> settings;
@@ -47,31 +43,27 @@ void ConfigureAudio::Setup() {
     push(Settings::Category::SystemAudio);
 
     for (auto* setting : settings) {
-        if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
-            continue;
-        }
-
         auto* widget = [&]() {
             if (setting->Id() == Settings::values.volume.Id()) {
                 // volume needs to be a slider (default is line edit)
-                return new ConfigurationShared::Widget(setting, translations, combobox_translations,
-                                                       this, runtime_lock, apply_funcs, nullptr,
-                                                       ConfigurationShared::RequestType::Slider,
-                                                       tr("%1%", "Volume percentage (e.g. 50%)"));
+                return builder.BuildWidget(setting, apply_funcs, nullptr,
+                                           ConfigurationShared::RequestType::Slider,
+                                           tr("%1%", "Volume percentage (e.g. 50%)"));
             } else if (setting->Id() == Settings::values.audio_output_device_id.Id() ||
                        setting->Id() == Settings::values.audio_input_device_id.Id() ||
                        setting->Id() == Settings::values.sink_id.Id()) {
                 // These need to be unmanaged comboboxes, so we can populate them ourselves
                 // TODO (lat9nq): Let it manage sink_id
-                return new ConfigurationShared::Widget(
-                    setting, translations, combobox_translations, this, runtime_lock, apply_funcs,
-                    ConfigurationShared::RequestType::ComboBox, false);
+                return builder.BuildWidget(setting, apply_funcs,
+                                           ConfigurationShared::RequestType::ComboBox, false);
             } else {
-                return new ConfigurationShared::Widget(setting, translations, combobox_translations,
-                                                       this, runtime_lock, apply_funcs);
+                return builder.BuildWidget(setting, apply_funcs);
             }
         }();
 
+        if (widget == nullptr) {
+            continue;
+        }
         if (!widget->Valid()) {
             delete widget;
             continue;
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 31cf682e0..94606f210 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <QWidget>
 #include "yuzu/configuration/configuration_shared.h"
-#include "yuzu/configuration/shared_translation.h"
 
 class QComboBox;
 
@@ -20,14 +19,15 @@ namespace Ui {
 class ConfigureAudio;
 }
 
+namespace ConfigurationShared {
+class Builder;
+}
+
 class ConfigureAudio : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureAudio(
-        const Core::System& system_,
-        std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
-        const ConfigurationShared::TranslationMap& translations_,
-        const ConfigurationShared::ComboboxTranslationMap& combobox_translations_,
-        QWidget* parent = nullptr);
+    explicit ConfigureAudio(const Core::System& system_,
+                            std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
+                            const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
     ~ConfigureAudio() override;
 
     void ApplyConfiguration() override;
@@ -45,13 +45,11 @@ private:
     void SetOutputSinkFromSinkID();
     void SetAudioDevicesFromDeviceID();
 
-    void Setup();
+    void Setup(const ConfigurationShared::Builder& builder);
 
     std::unique_ptr<Ui::ConfigureAudio> ui;
 
     const Core::System& system;
-    const ConfigurationShared::TranslationMap& translations;
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
 
     std::forward_list<std::function<void(bool)>> apply_funcs{};
 
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 210af146d..57cdc4c63 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -13,16 +13,14 @@
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_cpu.h"
 
-ConfigureCpu::ConfigureCpu(
-    const Core::System& system_,
-    std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
-    const ConfigurationShared::TranslationMap& translations_,
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations_, QWidget* parent)
+ConfigureCpu::ConfigureCpu(const Core::System& system_,
+                           std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
+                           const ConfigurationShared::Builder& builder, QWidget* parent)
     : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureCpu>()}, system{system_},
-      translations{translations_}, combobox_translations{combobox_translations_} {
+      combobox_translations(builder.ComboboxTranslations()) {
     ui->setupUi(this);
 
-    Setup();
+    Setup(builder);
 
     SetConfiguration();
 
@@ -33,8 +31,7 @@ ConfigureCpu::ConfigureCpu(
 ConfigureCpu::~ConfigureCpu() = default;
 
 void ConfigureCpu::SetConfiguration() {}
-void ConfigureCpu::Setup() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) {
     auto* accuracy_layout = ui->widget_accuracy->layout();
     auto* unsafe_layout = ui->unsafe_widget->layout();
     std::map<std::string, QWidget*> unsafe_hold{};
@@ -50,13 +47,11 @@ void ConfigureCpu::Setup() {
     push(Settings::Category::CpuUnsafe);
 
     for (const auto setting : settings) {
-        if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
+        auto* widget = builder.BuildWidget(setting, apply_funcs);
+
+        if (widget == nullptr) {
             continue;
         }
-
-        auto* widget = new ConfigurationShared::Widget(setting, translations, combobox_translations,
-                                                       this, runtime_lock, apply_funcs);
-
         if (!widget->Valid()) {
             delete widget;
             continue;
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index 57603e5c9..ab19c0ba1 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -18,13 +18,15 @@ namespace Ui {
 class ConfigureCpu;
 }
 
+namespace ConfigurationShared {
+class Builder;
+}
+
 class ConfigureCpu : public ConfigurationShared::Tab {
 public:
     explicit ConfigureCpu(const Core::System& system_,
                           std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
-                          const ConfigurationShared::TranslationMap& translations,
-                          const ConfigurationShared::ComboboxTranslationMap& combobox_translations,
-                          QWidget* parent = nullptr);
+                          const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
     ~ConfigureCpu() override;
 
     void ApplyConfiguration() override;
@@ -36,15 +38,13 @@ private:
 
     void UpdateGroup(int index);
 
-    void Setup();
+    void Setup(const ConfigurationShared::Builder& builder);
 
     std::unique_ptr<Ui::ConfigureCpu> ui;
 
     const Core::System& system;
 
-    const ConfigurationShared::TranslationMap& translations;
     const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
-
     std::forward_list<std::function<void(bool)>> apply_funcs{};
 
     QComboBox* accuracy_combobox;
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index c7d132fc8..183555acd 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -32,28 +32,23 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
                                  std::vector<VkDeviceInfo::Record>& vk_device_records,
                                  Core::System& system_, bool enable_web_config)
     : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},
-      registry(registry_), system{system_},
-      translations{ConfigurationShared::InitializeTranslations(this)},
-      combobox_translations{ConfigurationShared::ComboboxEnumeration(this)},
-      audio_tab{std::make_unique<ConfigureAudio>(system_, nullptr, *translations,
-                                                 *combobox_translations, this)},
-      cpu_tab{std::make_unique<ConfigureCpu>(system_, nullptr, *translations,
-                                             *combobox_translations, this)},
+      registry(registry_), system{system_}, builder{std::make_unique<ConfigurationShared::Builder>(
+                                                this, !system_.IsPoweredOn())},
+      audio_tab{std::make_unique<ConfigureAudio>(system_, nullptr, *builder, this)},
+      cpu_tab{std::make_unique<ConfigureCpu>(system_, nullptr, *builder, this)},
       debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)},
       filesystem_tab{std::make_unique<ConfigureFilesystem>(this)},
-      general_tab{std::make_unique<ConfigureGeneral>(system_, nullptr, *translations,
-                                                     *combobox_translations, this)},
-      graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(
-          system_, nullptr, *translations, *combobox_translations, this)},
+      general_tab{std::make_unique<ConfigureGeneral>(system_, nullptr, *builder, this)},
+      graphics_advanced_tab{
+          std::make_unique<ConfigureGraphicsAdvanced>(system_, nullptr, *builder, this)},
       graphics_tab{std::make_unique<ConfigureGraphics>(
           system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
-          nullptr, *translations, *combobox_translations, this)},
+          nullptr, *builder, this)},
       hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
       input_tab{std::make_unique<ConfigureInput>(system_, this)},
       network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
       profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
-      system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *translations,
-                                                   *combobox_translations, this)},
+      system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *builder, this)},
       ui_tab{std::make_unique<ConfigureUi>(system_, this)}, web_tab{std::make_unique<ConfigureWeb>(
                                                                 this)} {
     Settings::SetConfiguringGlobal(true);
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 931900b7d..1bfc9f9d0 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -7,6 +7,7 @@
 #include <memory>
 #include <vector>
 #include <QDialog>
+#include "configuration/shared_widget.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/shared_translation.h"
 #include "yuzu/vk_device_info.h"
@@ -72,8 +73,7 @@ private:
     HotkeyRegistry& registry;
 
     Core::System& system;
-    std::unique_ptr<ConfigurationShared::TranslationMap> translations;
-    std::unique_ptr<ConfigurationShared::ComboboxTranslationMap> combobox_translations;
+    std::unique_ptr<ConfigurationShared::Builder> builder;
     std::forward_list<ConfigurationShared::Tab*> tab_group;
 
     std::unique_ptr<ConfigureAudio> audio_tab;
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index ca5b92bc0..54113543a 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -15,12 +15,12 @@
 ConfigureGeneral::ConfigureGeneral(
     const Core::System& system_,
     std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
-    const ConfigurationShared::TranslationMap& translations_,
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations_, QWidget* parent)
-    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_},
-      translations{translations_}, combobox_translations{combobox_translations_} {
+    const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_} {
     ui->setupUi(this);
 
+    Setup(builder);
+
     SetConfiguration();
 
     connect(ui->button_reset_defaults, &QPushButton::clicked, this,
@@ -33,17 +33,20 @@ ConfigureGeneral::ConfigureGeneral(
 
 ConfigureGeneral::~ConfigureGeneral() = default;
 
-void ConfigureGeneral::SetConfiguration() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureGeneral::SetConfiguration() {}
+
+void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) {
     QLayout& layout = *ui->general_widget->layout();
 
     std::map<u32, QWidget*> hold{};
 
     for (const auto setting :
          UISettings::values.linkage.by_category[Settings::Category::UiGeneral]) {
-        auto* widget = new ConfigurationShared::Widget(setting, translations, combobox_translations,
-                                                       this, runtime_lock, apply_funcs);
+        auto* widget = builder.BuildWidget(setting, apply_funcs);
 
+        if (widget == nullptr) {
+            continue;
+        }
         if (!widget->Valid()) {
             delete widget;
             continue;
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 864dc3d2e..f8ed3f8ab 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -7,7 +7,6 @@
 #include <memory>
 #include <QWidget>
 #include "yuzu/configuration/configuration_shared.h"
-#include "yuzu/configuration/shared_widget.h"
 
 namespace Core {
 class System;
@@ -20,14 +19,16 @@ namespace Ui {
 class ConfigureGeneral;
 }
 
+namespace ConfigurationShared {
+class Builder;
+}
+
 class ConfigureGeneral : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureGeneral(
-        const Core::System& system_,
-        std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
-        const ConfigurationShared::TranslationMap& translations_,
-        const ConfigurationShared::ComboboxTranslationMap& combobox_translations_,
-        QWidget* parent = nullptr);
+    explicit ConfigureGeneral(const Core::System& system_,
+                              std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
+                              const ConfigurationShared::Builder& builder,
+                              QWidget* parent = nullptr);
     ~ConfigureGeneral() override;
 
     void SetResetCallback(std::function<void()> callback);
@@ -36,6 +37,8 @@ public:
     void SetConfiguration() override;
 
 private:
+    void Setup(const ConfigurationShared::Builder& builder);
+
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
@@ -46,6 +49,4 @@ private:
     std::forward_list<std::function<void(bool)>> apply_funcs{};
 
     const Core::System& system;
-    const ConfigurationShared::TranslationMap& translations;
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
 };
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 2f041cba6..18872fa69 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -81,18 +81,17 @@ ConfigureGraphics::ConfigureGraphics(
     const Core::System& system_, std::vector<VkDeviceInfo::Record>& records_,
     const std::function<void()>& expose_compute_option_,
     std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
-    const ConfigurationShared::TranslationMap& translations_,
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations_, QWidget* parent)
+    const ConfigurationShared::Builder& builder, QWidget* parent)
     : ConfigurationShared::Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
       records{records_}, expose_compute_option{expose_compute_option_}, system{system_},
-      translations{translations_}, combobox_translations{combobox_translations_},
+      combobox_translations{builder.ComboboxTranslations()},
       shader_mapping{combobox_translations.at(typeid(Settings::ShaderBackend))} {
     vulkan_device = Settings::values.vulkan_device.GetValue();
     RetrieveVulkanDevices();
 
     ui->setupUi(this);
 
-    Setup();
+    Setup(builder);
 
     for (const auto& device : vulkan_devices) {
         vulkan_device_combobox->addItem(device);
@@ -218,8 +217,7 @@ ConfigureGraphics::~ConfigureGraphics() = default;
 
 void ConfigureGraphics::SetConfiguration() {}
 
-void ConfigureGraphics::Setup() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) {
     QLayout* api_layout = ui->api_widget->layout();
     QWidget* api_grid_widget = new QWidget(this);
     QVBoxLayout* api_grid_layout = new QVBoxLayout(api_grid_widget);
@@ -232,30 +230,26 @@ void ConfigureGraphics::Setup() {
     std::forward_list<QWidget*> hold_api;
 
     for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) {
-        if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
-            continue;
-        }
-
         ConfigurationShared::Widget* widget = [&]() {
             // Set managed to false on these and set up the comboboxes ourselves
             if (setting->Id() == Settings::values.vulkan_device.Id() ||
                 setting->Id() == Settings::values.shader_backend.Id() ||
                 setting->Id() == Settings::values.vsync_mode.Id()) {
-                return new ConfigurationShared::Widget(
-                    setting, translations, combobox_translations, this, runtime_lock, apply_funcs,
-                    ConfigurationShared::RequestType::ComboBox, false);
+                return builder.BuildWidget(setting, apply_funcs,
+                                           ConfigurationShared::RequestType::ComboBox, false);
             } else if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) {
                 // FSR needs a reversed slider
-                return new ConfigurationShared::Widget(
-                    setting, translations, combobox_translations, this, runtime_lock, apply_funcs,
-                    ConfigurationShared::RequestType::ReverseSlider, true, 0.5f, nullptr,
-                    tr("%1%", "FSR sharpening percentage (e.g. 50%)"));
+                return builder.BuildWidget(
+                    setting, apply_funcs, ConfigurationShared::RequestType::ReverseSlider, true,
+                    0.5f, nullptr, tr("%1%", "FSR sharpening percentage (e.g. 50%)"));
             } else {
-                return new ConfigurationShared::Widget(setting, translations, combobox_translations,
-                                                       this, runtime_lock, apply_funcs);
+                return builder.BuildWidget(setting, apply_funcs);
             }
         }();
 
+        if (widget == nullptr) {
+            continue;
+        }
         if (!widget->Valid()) {
             delete widget;
             continue;
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 718ba54f5..1848b1593 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -6,6 +6,7 @@
 #include <functional>
 #include <memory>
 #include <type_traits>
+#include <typeindex>
 #include <vector>
 #include <QColor>
 #include <QString>
@@ -13,9 +14,9 @@
 #include <qobjectdefs.h>
 #include <vulkan/vulkan_core.h>
 #include "common/common_types.h"
+#include "configuration/shared_translation.h"
 #include "vk_device_info.h"
 #include "yuzu/configuration/configuration_shared.h"
-#include "yuzu/configuration/shared_translation.h"
 
 class QPushButton;
 class QEvent;
@@ -36,15 +37,18 @@ namespace Ui {
 class ConfigureGraphics;
 }
 
+namespace ConfigurationShared {
+class Builder;
+}
+
 class ConfigureGraphics : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureGraphics(
-        const Core::System& system_, std::vector<VkDeviceInfo::Record>& records,
-        const std::function<void()>& expose_compute_option_,
-        std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
-        const ConfigurationShared::TranslationMap& translations_,
-        const ConfigurationShared::ComboboxTranslationMap& combobox_translations_,
-        QWidget* parent = nullptr);
+    explicit ConfigureGraphics(const Core::System& system_,
+                               std::vector<VkDeviceInfo::Record>& records,
+                               const std::function<void()>& expose_compute_option_,
+                               std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
+                               const ConfigurationShared::Builder& builder,
+                               QWidget* parent = nullptr);
     ~ConfigureGraphics() override;
 
     void ApplyConfiguration() override;
@@ -54,7 +58,7 @@ private:
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
-    void Setup();
+    void Setup(const ConfigurationShared::Builder& builder);
 
     void PopulateVSyncModeSelection();
     void UpdateBackgroundColorButton(QColor color);
@@ -89,7 +93,6 @@ private:
     const std::function<void()>& expose_compute_option;
 
     const Core::System& system;
-    const ConfigurationShared::TranslationMap& translations;
     const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
     const std::vector<std::pair<u32, QString>>& shader_mapping;
 
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index e2f7d284d..757e4659d 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -14,13 +14,13 @@
 ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(
     const Core::System& system_,
     std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
-    const ConfigurationShared::TranslationMap& translations_,
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations_, QWidget* parent)
-    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_},
-      translations{translations_}, combobox_translations{combobox_translations_} {
+    const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
 
     ui->setupUi(this);
 
+    Setup(builder);
+
     SetConfiguration();
 
     checkbox_enable_compute_pipelines->setVisible(false);
@@ -28,20 +28,19 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(
 
 ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
 
-void ConfigureGraphicsAdvanced::SetConfiguration() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureGraphicsAdvanced::SetConfiguration() {}
+
+void ConfigureGraphicsAdvanced::Setup(const ConfigurationShared::Builder& builder) {
     auto& layout = *ui->populate_target->layout();
     std::map<u32, QWidget*> hold{}; // A map will sort the data for us
 
     for (auto setting :
          Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) {
-        if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
+        ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
+
+        if (widget == nullptr) {
             continue;
         }
-
-        ConfigurationShared::Widget* widget = new ConfigurationShared::Widget(
-            setting, translations, combobox_translations, this, runtime_lock, apply_funcs);
-
         if (!widget->Valid()) {
             delete widget;
             continue;
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 90b79f786..5530827d1 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -6,7 +6,6 @@
 #include <memory>
 #include <QWidget>
 #include "yuzu/configuration/configuration_shared.h"
-#include "yuzu/configuration/shared_translation.h"
 
 namespace Core {
 class System;
@@ -16,14 +15,16 @@ namespace Ui {
 class ConfigureGraphicsAdvanced;
 }
 
+namespace ConfigurationShared {
+class Builder;
+}
+
 class ConfigureGraphicsAdvanced : public ConfigurationShared::Tab {
 public:
     explicit ConfigureGraphicsAdvanced(
         const Core::System& system_,
         std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
-        const ConfigurationShared::TranslationMap& translations_,
-        const ConfigurationShared::ComboboxTranslationMap& combobox_translations_,
-        QWidget* parent = nullptr);
+        const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
     ~ConfigureGraphicsAdvanced() override;
 
     void ApplyConfiguration() override;
@@ -32,14 +33,14 @@ public:
     void ExposeComputeOption();
 
 private:
+    void Setup(const ConfigurationShared::Builder& builder);
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
     std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
 
     const Core::System& system;
-    const ConfigurationShared::TranslationMap& translations;
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
+
     std::forward_list<std::function<void(bool)>> apply_funcs;
 
     QWidget* checkbox_enable_compute_pipelines{};
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 5863beca0..cee8e726d 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -17,6 +17,7 @@
 #include <QTimer>
 
 #include "common/fs/fs_util.h"
+#include "configuration/shared_widget.h"
 #include "core/core.h"
 #include "core/file_sys/control_metadata.h"
 #include "core/file_sys/patch_manager.h"
@@ -42,8 +43,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
                                    Core::System& system_)
     : QDialog(parent),
       ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_},
-      translations{ConfigurationShared::InitializeTranslations(this)},
-      combobox_translations{ConfigurationShared::ComboboxEnumeration(this)},
+      builder{std::make_unique<ConfigurationShared::Builder>(this, !system_.IsPoweredOn())},
       tab_group{std::make_shared<std::forward_list<ConfigurationShared::Tab*>>()} {
     const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name));
     const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename())
@@ -51,18 +51,15 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
     game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
 
     addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this);
-    audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *translations,
-                                                 *combobox_translations, this);
-    cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *translations,
-                                             *combobox_translations, this);
-    graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(
-        system_, tab_group, *translations, *combobox_translations, this);
+    audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this);
+    cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this);
+    graphics_advanced_tab =
+        std::make_unique<ConfigureGraphicsAdvanced>(system_, tab_group, *builder, this);
     graphics_tab = std::make_unique<ConfigureGraphics>(
         system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
-        tab_group, *translations, *combobox_translations, this);
+        tab_group, *builder, this);
     input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
-    system_tab = std::make_unique<ConfigureSystem>(system_, tab_group, *translations,
-                                                   *combobox_translations, this);
+    system_tab = std::make_unique<ConfigureSystem>(system_, tab_group, *builder, this);
 
     ui->setupUi(this);
 
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index 4849ac291..4ddd18c1f 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -11,6 +11,7 @@
 #include <QDialog>
 #include <QList>
 
+#include "configuration/shared_widget.h"
 #include "core/file_sys/vfs_types.h"
 #include "vk_device_info.h"
 #include "yuzu/configuration/config.h"
@@ -75,8 +76,7 @@ private:
     std::unique_ptr<Config> game_config;
 
     Core::System& system;
-    std::unique_ptr<ConfigurationShared::TranslationMap> translations;
-    std::unique_ptr<ConfigurationShared::ComboboxTranslationMap> combobox_translations;
+    std::unique_ptr<ConfigurationShared::Builder> builder;
     std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> tab_group;
 
     std::unique_ptr<ConfigurePerGameAddons> addons_tab;
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 6a985c515..9be09244a 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -46,13 +46,11 @@ static bool IsValidLocale(u32 region_index, u32 language_index) {
 
 ConfigureSystem::ConfigureSystem(
     Core::System& system_, std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group_,
-    const ConfigurationShared::TranslationMap& translations_,
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations_, QWidget* parent)
-    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_},
-      translations{translations_}, combobox_translations{combobox_translations_} {
+    const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
     ui->setupUi(this);
 
-    Setup();
+    Setup(builder);
 
     connect(rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
         rng_seed_edit->setEnabled(state == Qt::Checked);
@@ -104,8 +102,7 @@ void ConfigureSystem::RetranslateUI() {
     ui->retranslateUi(this);
 }
 
-void ConfigureSystem::Setup() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) {
     auto& core_layout = *ui->core_widget->layout();
     auto& system_layout = *ui->system_widget->layout();
 
@@ -123,37 +120,31 @@ void ConfigureSystem::Setup() {
     push(Settings::values.linkage.by_category[Settings::Category::System]);
 
     for (auto setting : settings) {
-        if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
-            continue;
-        }
-
-        [[maybe_unused]] std::string label = setting->GetLabel();
-        ConfigurationShared::Widget* widget = [this, setting, runtime_lock]() {
+        ConfigurationShared::Widget* widget = [this, setting, &builder]() {
             if (setting->Id() == Settings::values.custom_rtc.Id()) {
                 // custom_rtc needs a DateTimeEdit (default is LineEdit), and a checkbox to manage
                 // it and custom_rtc_enabled
-                return new ConfigurationShared::Widget(
-                    setting, translations, combobox_translations, this, runtime_lock, apply_funcs,
-                    &Settings::values.custom_rtc_enabled,
-                    ConfigurationShared::RequestType::DateTimeEdit);
+                return builder.BuildWidget(setting, apply_funcs,
+                                           &Settings::values.custom_rtc_enabled,
+                                           ConfigurationShared::RequestType::DateTimeEdit);
             } else if (setting->Id() == Settings::values.rng_seed.Id()) {
                 // rng_seed needs a HexEdit (default is LineEdit), and a checkbox to manage
                 // it and rng_seed_enabled
-                return new ConfigurationShared::Widget(
-                    setting, translations, combobox_translations, this, runtime_lock, apply_funcs,
-                    &Settings::values.rng_seed_enabled, ConfigurationShared::RequestType::HexEdit);
+                return builder.BuildWidget(setting, apply_funcs, &Settings::values.rng_seed_enabled,
+                                           ConfigurationShared::RequestType::HexEdit);
             } else if (setting->Id() == Settings::values.speed_limit.Id()) {
                 // speed_limit needs a checkbox to set use_speed_limit, as well as a spinbox
-                return new ConfigurationShared::Widget(
-                    setting, translations, combobox_translations, this, runtime_lock, apply_funcs,
-                    &Settings::values.use_speed_limit, ConfigurationShared::RequestType::SpinBox,
-                    tr("%", "Limit speed percentage (e.g. 50%)"));
+                return builder.BuildWidget(setting, apply_funcs, &Settings::values.use_speed_limit,
+                                           ConfigurationShared::RequestType::SpinBox,
+                                           tr("%", "Limit speed percentage (e.g. 50%)"));
             } else {
-                return new ConfigurationShared::Widget(setting, translations, combobox_translations,
-                                                       this, runtime_lock, apply_funcs);
+                return builder.BuildWidget(setting, apply_funcs);
             }
         }();
 
+        if (widget == nullptr) {
+            continue;
+        }
         if (!widget->Valid()) {
             delete widget;
             continue;
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index 4457ccc21..7f4259698 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -9,13 +9,11 @@
 
 #include <QWidget>
 #include "yuzu/configuration/configuration_shared.h"
-#include "yuzu/configuration/shared_translation.h"
 
 class QCheckBox;
 class QLineEdit;
 class QComboBox;
 class QDateTimeEdit;
-
 namespace Core {
 class System;
 }
@@ -24,13 +22,16 @@ namespace Ui {
 class ConfigureSystem;
 }
 
+namespace ConfigurationShared {
+class Builder;
+}
+
 class ConfigureSystem : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureSystem(
-        Core::System& system_, std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
-        const ConfigurationShared::TranslationMap& translations,
-        const ConfigurationShared::ComboboxTranslationMap& combobox_translations,
-        QWidget* parent = nullptr);
+    explicit ConfigureSystem(Core::System& system_,
+                             std::shared_ptr<std::forward_list<ConfigurationShared::Tab*>> group,
+                             const ConfigurationShared::Builder& builder,
+                             QWidget* parent = nullptr);
     ~ConfigureSystem() override;
 
     void ApplyConfiguration() override;
@@ -40,7 +41,7 @@ private:
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
-    void Setup();
+    void Setup(const ConfigurationShared::Builder& builder);
 
     std::forward_list<std::function<void(bool)>> apply_funcs{};
 
@@ -48,8 +49,6 @@ private:
     bool enabled = false;
 
     Core::System& system;
-    const ConfigurationShared::TranslationMap& translations;
-    const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
 
     QCheckBox* rng_seed_checkbox;
     QLineEdit* rng_seed_edit;
diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp
index d153d8d6b..dc8b31238 100644
--- a/src/yuzu/configuration/shared_widget.cpp
+++ b/src/yuzu/configuration/shared_widget.cpp
@@ -529,11 +529,34 @@ Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translati
     this->setToolTip(tooltip);
 }
 
-Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translations_,
-               const ComboboxTranslationMap& combobox_translations, QWidget* parent_,
-               bool runtime_lock_, std::forward_list<std::function<void(bool)>>& apply_funcs_,
-               Settings::BasicSetting* other_setting, RequestType request, const QString& string)
-    : Widget(setting_, translations_, combobox_translations, parent_, runtime_lock_, apply_funcs_,
-             request, true, 1.0f, other_setting, string) {}
+Builder::Builder(QWidget* parent_, bool runtime_lock_)
+    : translations{InitializeTranslations(parent_)},
+      combobox_translations{ComboboxEnumeration(parent_)}, parent{parent_}, runtime_lock{
+                                                                                runtime_lock_} {}
+
+Builder::~Builder() = default;
+
+Widget* Builder::BuildWidget(Settings::BasicSetting* setting,
+                             std::forward_list<std::function<void(bool)>>& apply_funcs,
+                             RequestType request, bool managed, float multiplier,
+                             Settings::BasicSetting* other_setting, const QString& string) const {
+    if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
+        return nullptr;
+    }
+
+    return new Widget(setting, *translations, *combobox_translations, parent, runtime_lock,
+                      apply_funcs, request, managed, multiplier, other_setting, string);
+}
+
+Widget* Builder::BuildWidget(Settings::BasicSetting* setting,
+                             std::forward_list<std::function<void(bool)>>& apply_funcs,
+                             Settings::BasicSetting* other_setting, RequestType request,
+                             const QString& string) const {
+    return BuildWidget(setting, apply_funcs, request, true, 1.0f, other_setting, string);
+}
+
+const ComboboxTranslationMap& Builder::ComboboxTranslations() const {
+    return *combobox_translations;
+}
 
 } // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h
index 10d2d353e..e8c281b81 100644
--- a/src/yuzu/configuration/shared_widget.h
+++ b/src/yuzu/configuration/shared_widget.h
@@ -5,6 +5,7 @@
 
 #include <forward_list>
 #include <functional>
+#include <memory>
 #include <string>
 #include <QString>
 #include <QStringLiteral>
@@ -44,28 +45,6 @@ class Widget : public QWidget {
     Q_OBJECT
 
 public:
-    /**
-     * Shorter-hand version of the constructor
-     *
-     * @param setting The primary Setting to create the Widget for
-     * @param translations Map of translations to display on the left side label/checkbox
-     * @param combobox_translations Map of translations for enumerating combo boxes
-     * @param parent Qt parent
-     * @param runtime_lock Emulated guest powered on state, for use on settings that should be
-     * configured during guest execution
-     * @param apply_funcs_ List to append, functions to run to apply the widget state to the setting
-     * @param other_setting Second setting to modify, to replace the label with a checkbox
-     * @param request What type of data representation component to create -- not always respected
-     * for the Setting data type
-     * @param string Set to specify formats for Slider feedback labels or SpinBox
-     */
-    explicit Widget(Settings::BasicSetting* setting, const TranslationMap& translations,
-                    const ComboboxTranslationMap& combobox_translations, QWidget* parent,
-                    bool runtime_lock, std::forward_list<std::function<void(bool)>>& apply_funcs_,
-                    Settings::BasicSetting* other_setting,
-                    RequestType request = RequestType::Default,
-                    const QString& string = QStringLiteral(""));
-
     /**
      * @param setting The primary Setting to create the Widget for
      * @param translations Map of translations to display on the left side label/checkbox
@@ -152,4 +131,31 @@ private:
     bool runtime_lock{false};
 };
 
+class Builder {
+public:
+    explicit Builder(QWidget* parent, bool runtime_lock);
+    ~Builder();
+
+    Widget* BuildWidget(Settings::BasicSetting* setting,
+                        std::forward_list<std::function<void(bool)>>& apply_funcs,
+                        RequestType request = RequestType::Default, bool managed = true,
+                        float multiplier = 1.0f, Settings::BasicSetting* other_setting = nullptr,
+                        const QString& string = QStringLiteral("")) const;
+
+    Widget* BuildWidget(Settings::BasicSetting* setting,
+                        std::forward_list<std::function<void(bool)>>& apply_funcs,
+                        Settings::BasicSetting* other_setting,
+                        RequestType request = RequestType::Default,
+                        const QString& string = QStringLiteral("")) const;
+
+    const ComboboxTranslationMap& ComboboxTranslations() const;
+
+private:
+    std::unique_ptr<TranslationMap> translations;
+    std::unique_ptr<ComboboxTranslationMap> combobox_translations;
+
+    QWidget* parent;
+    const bool runtime_lock;
+};
+
 } // namespace ConfigurationShared