diff --git a/src/citron/CMakeLists.txt b/src/citron/CMakeLists.txt
index 21e3ffbb2..1b18cd17d 100644
--- a/src/citron/CMakeLists.txt
+++ b/src/citron/CMakeLists.txt
@@ -209,6 +209,7 @@ add_executable(citron
qt_common.h
startup_checks.cpp
startup_checks.h
+ theme.h
uisettings.cpp
uisettings.h
util/clickable_label.cpp
diff --git a/src/citron/configuration/configure.ui b/src/citron/configuration/configure.ui
index 522be83cb..7d1558662 100644
--- a/src/citron/configuration/configure.ui
+++ b/src/citron/configuration/configure.ui
@@ -16,15 +16,16 @@
0
-
Qt::ApplicationModal
-
citron Configuration
+
+
+
QDialog {
background-color: #2b2b2b;
color: #ffffff;
@@ -68,7 +69,7 @@
}
QScrollBar::handle:vertical:hover {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
@@ -92,7 +93,7 @@
}
QScrollBar::handle:horizontal:hover {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
}
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
@@ -118,10 +119,10 @@
}
QPushButton.tabButton:checked {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
color: #ffffff;
font-weight: bold;
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
}
QPushButton.tabButton:hover:!checked {
@@ -130,7 +131,7 @@
}
QPushButton.tabButton:pressed {
- background-color: #2980b9;
+ background-color: %%ACCENT_COLOR_PRESSED%%;
}
QTabWidget {
@@ -170,10 +171,10 @@
}
QTabBar::tab:selected {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
color: #ffffff;
font-weight: bold;
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
}
QTabBar::tab:hover:!selected {
@@ -191,7 +192,7 @@
QTabBar QToolButton:hover {
background-color: #4d4d4d;
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
}
QTabBar::scroller {
@@ -232,12 +233,12 @@
}
QCheckBox::indicator:checked {
- background-color: #4a9eff;
- border-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
+ border-color: %%ACCENT_COLOR%%;
}
QCheckBox::indicator:hover {
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
}
QComboBox {
@@ -248,16 +249,16 @@
color: #ffffff;
min-width: 120px;
min-height: 28px;
- selection-background-color: #4a9eff;
+ selection-background-color: %%ACCENT_COLOR%%;
}
QComboBox:hover {
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
background-color: #404040;
}
QComboBox:focus {
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
background-color: #404040;
}
@@ -277,8 +278,8 @@
QComboBox QAbstractItemView {
background-color: #3d3d3d;
- border: 1px solid #4a9eff;
- selection-background-color: #4a9eff;
+ border: 1px solid %%ACCENT_COLOR%%;
+ selection-background-color: %%ACCENT_COLOR%%;
color: #ffffff;
outline: none;
}
@@ -290,12 +291,12 @@
}
QComboBox QAbstractItemView::item:selected {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
color: #ffffff;
}
QComboBox QAbstractItemView::item:hover {
- background-color: #5dafff;
+ background-color: %%ACCENT_COLOR_HOVER%%;
color: #ffffff;
}
@@ -306,16 +307,16 @@
padding: 8px 12px;
color: #ffffff;
min-height: 20px;
- selection-background-color: #4a9eff;
+ selection-background-color: %%ACCENT_COLOR%%;
}
QLineEdit:focus {
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
background-color: #404040;
}
QPushButton {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
color: #ffffff;
border: none;
padding: 10px 20px;
@@ -325,11 +326,11 @@
}
QPushButton:hover {
- background-color: #5dafff;
+ background-color: %%ACCENT_COLOR_HOVER%%;
}
QPushButton:pressed {
- background-color: #2980b9;
+ background-color: %%ACCENT_COLOR_PRESSED%%;
}
QPushButton:disabled {
@@ -338,7 +339,7 @@
}
QToolButton {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
color: #ffffff;
border: none;
padding: 8px 12px;
@@ -349,11 +350,11 @@
}
QToolButton:hover {
- background-color: #5dafff;
+ background-color: %%ACCENT_COLOR_HOVER%%;
}
QToolButton:pressed {
- background-color: #2980b9;
+ background-color: %%ACCENT_COLOR_PRESSED%%;
}
QLabel {
@@ -377,7 +378,7 @@
}
QListWidget::item:selected {
- background-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
color: #ffffff;
}
@@ -393,15 +394,15 @@
}
QSlider::handle:horizontal {
- background-color: #4a9eff;
- border: 1px solid #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
+ border: 1px solid %%ACCENT_COLOR%%;
width: 18px;
margin: -5px 0;
border-radius: 9px;
}
QSlider::handle:horizontal:hover {
- background-color: #5dafff;
+ background-color: %%ACCENT_COLOR_HOVER%%;
}
QSpinBox, QDoubleSpinBox {
@@ -414,7 +415,7 @@
}
QSpinBox:focus, QDoubleSpinBox:focus {
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
background-color: #404040;
}
@@ -433,12 +434,12 @@
}
QRadioButton::indicator:checked {
- background-color: #4a9eff;
- border-color: #4a9eff;
+ background-color: %%ACCENT_COLOR%%;
+ border-color: %%ACCENT_COLOR%%;
}
QRadioButton::indicator:hover {
- border-color: #4a9eff;
+ border-color: %%ACCENT_COLOR%%;
}
/* High DPI specific styles */
@@ -511,8 +512,8 @@
height: 20px;
}
}
-
-
+
+
8
diff --git a/src/citron/configuration/configure_dialog.cpp b/src/citron/configuration/configure_dialog.cpp
index df97c42a3..85f4d66cd 100644
--- a/src/citron/configuration/configure_dialog.cpp
+++ b/src/citron/configuration/configure_dialog.cpp
@@ -2,24 +2,27 @@
// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "citron/configuration/configure_dialog.h"
#include
+#include
+#include
#include
#include
#include
-#include
-#include
#include
+#include
+#include
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "core/core.h"
#include "ui_configure.h"
#include "vk_device_info.h"
+#include "citron/configuration/configuration_shared.h" // <-- Full definition included here
#include "citron/configuration/configure_applets.h"
#include "citron/configuration/configure_audio.h"
#include "citron/configuration/configure_cpu.h"
#include "citron/configuration/configure_debug_tab.h"
-#include "citron/configuration/configure_dialog.h"
#include "citron/configuration/configure_filesystem.h"
#include "citron/configuration/configure_general.h"
#include "citron/configuration/configure_graphics.h"
@@ -33,9 +36,9 @@
#include "citron/configuration/configure_ui.h"
#include "citron/configuration/configure_web.h"
#include "citron/hotkeys.h"
+#include "citron/theme.h"
#include "citron/uisettings.h"
-// Helper function to create a scroll area for a widget
static QScrollArea* CreateScrollArea(QWidget* widget) {
auto* scroll_area = new QScrollArea();
scroll_area->setWidget(widget);
@@ -43,60 +46,6 @@ static QScrollArea* CreateScrollArea(QWidget* widget) {
scroll_area->setFrameShape(QFrame::NoFrame);
scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
-
- // High DPI support: Scroll area will inherit scaling from parent
-
- // Set style with high DPI aware styling
- scroll_area->setStyleSheet(QLatin1String(
- "QScrollArea { "
- "border: none; "
- "background-color: #2b2b2b; "
- "}"
- "QScrollArea > QWidget > QWidget { "
- "background-color: #2b2b2b; "
- "}"
- "QScrollBar:vertical { "
- "background-color: #3d3d3d; "
- "width: 14px; "
- "border-radius: 7px; "
- "margin: 2px; "
- "}"
- "QScrollBar::handle:vertical { "
- "background-color: #5d5d5d; "
- "border-radius: 6px; "
- "min-height: 30px; "
- "margin: 1px; "
- "}"
- "QScrollBar::handle:vertical:hover { "
- "background-color: #4a9eff; "
- "}"
- "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { "
- "border: none; "
- "background: none; "
- "height: 0px; "
- "}"
- "QScrollBar:horizontal { "
- "background-color: #3d3d3d; "
- "height: 14px; "
- "border-radius: 7px; "
- "margin: 2px; "
- "}"
- "QScrollBar::handle:horizontal { "
- "background-color: #5d5d5d; "
- "border-radius: 6px; "
- "min-width: 30px; "
- "margin: 1px; "
- "}"
- "QScrollBar::handle:horizontal:hover { "
- "background-color: #4a9eff; "
- "}"
- "QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { "
- "border: none; "
- "background: none; "
- "width: 0px; "
- "}"
- ));
-
return scroll_area;
}
@@ -104,66 +53,60 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
InputCommon::InputSubsystem* input_subsystem,
std::vector& vk_device_records,
Core::System& system_, bool enable_web_config)
- : QDialog(parent), ui{std::make_unique()},
- registry(registry_), system{system_}, builder{std::make_unique(
- this, !system_.IsPoweredOn())},
- applets_tab{std::make_unique(system_, nullptr, *builder, this)},
- audio_tab{std::make_unique(system_, nullptr, *builder, this)},
- cpu_tab{std::make_unique(system_, nullptr, *builder, this)},
- debug_tab_tab{std::make_unique(system_, this)},
- filesystem_tab{std::make_unique(this)},
- general_tab{std::make_unique(system_, nullptr, *builder, this)},
- graphics_advanced_tab{
- std::make_unique(system_, nullptr, *builder, this)},
- ui_tab{std::make_unique(system_, this)},
- graphics_tab{std::make_unique(
- system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
- [this](Settings::AspectRatio ratio, Settings::ResolutionSetup setup) {
- ui_tab->UpdateScreenshotInfo(ratio, setup);
- },
- nullptr, *builder, this)},
- hotkeys_tab{std::make_unique(system_.HIDCore(), this)},
- input_tab{std::make_unique(system_, this)},
- network_tab{std::make_unique(system_, this)},
- profile_tab{std::make_unique(system_, this)},
- system_tab{std::make_unique(system_, nullptr, *builder, this)},
- web_tab{std::make_unique(this)} {
+: QDialog(parent), ui{std::make_unique()},
+registry(registry_), system{system_}, builder{std::make_unique(
+ this, !system_.IsPoweredOn())},
+ applets_tab{std::make_unique(system_, nullptr, *builder, this)},
+ audio_tab{std::make_unique(system_, nullptr, *builder, this)},
+ cpu_tab{std::make_unique(system_, nullptr, *builder, this)},
+ debug_tab_tab{std::make_unique(system_, this)},
+ filesystem_tab{std::make_unique(this)},
+ general_tab{std::make_unique(system_, nullptr, *builder, this)},
+ graphics_advanced_tab{
+ std::make_unique(system_, nullptr, *builder, this)},
+ ui_tab{std::make_unique(system_, this)},
+ graphics_tab{std::make_unique(
+ system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
+ [this](Settings::AspectRatio ratio, Settings::ResolutionSetup setup) {
+ ui_tab->UpdateScreenshotInfo(ratio, setup);
+ },
+ nullptr, *builder, this)},
+hotkeys_tab{std::make_unique(system_.HIDCore(), this)},
+input_tab{std::make_unique(system_, this)},
+network_tab{std::make_unique(system_, this)},
+profile_tab{std::make_unique(system_, this)},
+system_tab{std::make_unique(system_, nullptr, *builder, this)},
+web_tab{std::make_unique(this)},
+rainbow_timer{new QTimer(this)} {
+
Settings::SetConfiguringGlobal(true);
- // Set window flags to include maximize button and make it resizable
setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
- Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+ Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
- // High DPI support: Set proper attributes for scaling
setAttribute(Qt::WA_TranslucentBackground, false);
setAttribute(Qt::WA_NoSystemBackground, false);
setAttribute(Qt::WA_DontShowOnScreen, false);
ui->setupUi(this);
- // Set size policy and enable resizing
+ UpdateTheme();
+
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- // Get screen geometry and set to fullscreen with high DPI awareness
QScreen* screen = QApplication::primaryScreen();
if (screen) {
QRect screenGeometry = screen->availableGeometry();
-
- // Calculate logical size based on device pixel ratio for high DPI support
qreal devicePixelRatio = screen->devicePixelRatio();
int logicalWidth = static_cast(screenGeometry.width() / devicePixelRatio);
int logicalHeight = static_cast(screenGeometry.height() / devicePixelRatio);
-
- // Set geometry using logical units
setGeometry(0, 0, logicalWidth, logicalHeight);
- showMaximized(); // Start maximized/fullscreen
+ showMaximized();
}
- // Create button group for exclusive tab selection
tab_button_group = std::make_unique(this);
tab_button_group->setExclusive(true);
- // Add tab buttons to the button group and connect to stacked widget
tab_button_group->addButton(ui->generalTabButton, 0);
tab_button_group->addButton(ui->uiTabButton, 1);
tab_button_group->addButton(ui->systemTabButton, 2);
@@ -180,31 +123,31 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
tab_button_group->addButton(ui->appletsTabButton, 13);
tab_button_group->addButton(ui->loggingTabButton, 14);
- // Add pages to stacked widget wrapped in scroll areas in the same order as button group
- ui->stackedWidget->addWidget(CreateScrollArea(general_tab.get())); // 0
- ui->stackedWidget->addWidget(CreateScrollArea(ui_tab.get())); // 1
- ui->stackedWidget->addWidget(CreateScrollArea(system_tab.get())); // 2
- ui->stackedWidget->addWidget(CreateScrollArea(cpu_tab.get())); // 3
- ui->stackedWidget->addWidget(CreateScrollArea(graphics_tab.get())); // 4
- ui->stackedWidget->addWidget(CreateScrollArea(graphics_advanced_tab.get())); // 5
- ui->stackedWidget->addWidget(CreateScrollArea(audio_tab.get())); // 6
- ui->stackedWidget->addWidget(CreateScrollArea(input_tab.get())); // 7
- ui->stackedWidget->addWidget(CreateScrollArea(hotkeys_tab.get())); // 8
- ui->stackedWidget->addWidget(CreateScrollArea(network_tab.get())); // 9
- ui->stackedWidget->addWidget(CreateScrollArea(web_tab.get())); // 10
- ui->stackedWidget->addWidget(CreateScrollArea(filesystem_tab.get()));// 11
- ui->stackedWidget->addWidget(CreateScrollArea(profile_tab.get())); // 12
- ui->stackedWidget->addWidget(CreateScrollArea(applets_tab.get())); // 13
- ui->stackedWidget->addWidget(CreateScrollArea(debug_tab_tab.get())); // 14
+ ui->stackedWidget->addWidget(CreateScrollArea(general_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(ui_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(system_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(cpu_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(graphics_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(graphics_advanced_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(audio_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(input_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(hotkeys_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(network_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(web_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(filesystem_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(profile_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(applets_tab.get()));
+ ui->stackedWidget->addWidget(CreateScrollArea(debug_tab_tab.get()));
- // Connect button group to stacked widget
- connect(tab_button_group.get(), QOverload::of(&QButtonGroup::idClicked),
- [this](int id) {
- ui->stackedWidget->setCurrentIndex(id);
- if (id == 14) { // Logging tab
- debug_tab_tab->SetCurrentIndex(0);
- }
- });
+ connect(tab_button_group.get(), qOverload(&QButtonGroup::idClicked), this, [this](int id) {
+ ui->stackedWidget->setCurrentIndex(id);
+ if (id == 14) {
+ debug_tab_tab->SetCurrentIndex(0);
+ }
+ });
+
+ connect(ui_tab.get(), &ConfigureUi::themeChanged, this, &ConfigureDialog::UpdateTheme);
+ connect(rainbow_timer, &QTimer::timeout, this, &ConfigureDialog::UpdateTheme);
web_tab->SetWebServiceConfigEnabled(enable_web_config);
hotkeys_tab->Populate(registry);
@@ -225,16 +168,43 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
}
}
- // Set initial tab to General (index 0)
ui->stackedWidget->setCurrentIndex(0);
ui->generalTabButton->setChecked(true);
-
- // Focus on the OK button by default
ui->buttonBox->setFocus();
}
+// This line defines the destructor, completing the type for std::unique_ptr
ConfigureDialog::~ConfigureDialog() = default;
+void ConfigureDialog::UpdateTheme() {
+ QString accent_color_str;
+ if (UISettings::values.enable_rainbow_mode.GetValue()) {
+ rainbow_hue += 0.005f;
+ if (rainbow_hue > 1.0f) {
+ rainbow_hue = 0.0f;
+ }
+ accent_color_str = QColor::fromHsvF(rainbow_hue, 0.8, 1.0).name();
+ if (!rainbow_timer->isActive()) {
+ rainbow_timer->start(16); // ~60 FPS
+ }
+ } else {
+ if (rainbow_timer->isActive()) {
+ rainbow_timer->stop();
+ }
+ accent_color_str = Theme::GetAccentColor();
+ }
+
+ QColor accent_color(accent_color_str);
+ QString accent_color_hover = accent_color.lighter(115).name();
+ QString accent_color_pressed = accent_color.darker(120).name();
+
+ QString style_sheet = property("templateStyleSheet").toString();
+ style_sheet.replace(QStringLiteral("%%ACCENT_COLOR%%"), accent_color_str);
+ style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), accent_color_hover);
+ style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), accent_color_pressed);
+ setStyleSheet(style_sheet);
+}
+
void ConfigureDialog::SetConfiguration() {}
void ConfigureDialog::ApplyConfiguration() {
@@ -281,9 +251,7 @@ void ConfigureDialog::HandleApplyButtonClicked() {
void ConfigureDialog::OnLanguageChanged(const QString& locale) {
emit LanguageChanged(locale);
- // Reloading the game list is needed to force retranslation.
UISettings::values.is_game_list_reload_pending = true;
- // first apply the configuration, and then restore the display
ApplyConfiguration();
RetranslateUI();
SetConfiguration();
diff --git a/src/citron/configuration/configure_dialog.h b/src/citron/configuration/configure_dialog.h
index b074541e4..a7e678acf 100644
--- a/src/citron/configuration/configure_dialog.h
+++ b/src/citron/configuration/configure_dialog.h
@@ -7,16 +7,25 @@
#include
#include
#include
-#include
-#include "configuration/shared_widget.h"
-#include "citron/configuration/configuration_shared.h"
-#include "citron/configuration/shared_translation.h"
-#include "citron/vk_device_info.h"
+#include "common/settings_enums.h"
+#include "citron/configuration/shared_widget.h" // <-- Correct header for Builder
-namespace Core {
-class System;
+// Forward declarations for other types
+class HotkeyRegistry;
+class QButtonGroup;
+class QTimer;
+namespace InputCommon {
+ class InputSubsystem;
+}
+namespace Core {
+ class System;
+}
+namespace VkDeviceInfo {
+ struct Record;
+}
+namespace Ui {
+ class ConfigureDialog;
}
-
class ConfigureApplets;
class ConfigureAudio;
class ConfigureCpu;
@@ -27,56 +36,45 @@ class ConfigureGraphics;
class ConfigureGraphicsAdvanced;
class ConfigureHotkeys;
class ConfigureInput;
+class ConfigureNetwork;
class ConfigureProfileManager;
class ConfigureSystem;
-class ConfigureNetwork;
class ConfigureUi;
class ConfigureWeb;
-class HotkeyRegistry;
-
-namespace InputCommon {
-class InputSubsystem;
-}
-
-namespace Ui {
-class ConfigureDialog;
-}
-
-class ConfigureDialog : public QDialog {
+class ConfigureDialog final : public QDialog {
Q_OBJECT
public:
- explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
+ explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
InputCommon::InputSubsystem* input_subsystem,
std::vector& vk_device_records,
- Core::System& system_, bool enable_web_config = true);
+ Core::System& system, bool enable_web_config);
+
~ConfigureDialog() override;
void ApplyConfiguration();
-private slots:
- void OnLanguageChanged(const QString& locale);
+public slots:
+ void UpdateTheme();
signals:
void LanguageChanged(const QString& locale);
private:
+ void SetConfiguration();
+ void HandleApplyButtonClicked();
+
void changeEvent(QEvent* event) override;
void RetranslateUI();
- void HandleApplyButtonClicked();
-
- void SetConfiguration();
+ void OnLanguageChanged(const QString& locale);
+ // All members are now in the EXACT correct order to match the constructor
std::unique_ptr ui;
HotkeyRegistry& registry;
-
Core::System& system;
std::unique_ptr builder;
- std::vector tab_group;
- std::unique_ptr tab_button_group;
-
std::unique_ptr applets_tab;
std::unique_ptr audio_tab;
std::unique_ptr cpu_tab;
@@ -92,4 +90,7 @@ private:
std::unique_ptr profile_tab;
std::unique_ptr system_tab;
std::unique_ptr web_tab;
+ std::unique_ptr tab_button_group;
+ QTimer* rainbow_timer;
+ float rainbow_hue = 0.0f;
};
diff --git a/src/citron/configuration/configure_ui.cpp b/src/citron/configuration/configure_ui.cpp
index a77efffdf..da8e6ba85 100644
--- a/src/citron/configuration/configure_ui.cpp
+++ b/src/citron/configuration/configure_ui.cpp
@@ -12,6 +12,7 @@
#include
#include
+#include
#include
#include
#include
@@ -33,42 +34,42 @@
#include "citron/uisettings.h"
namespace {
-constexpr std::array default_game_icon_sizes{
- std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
- std::make_pair(32, QT_TRANSLATE_NOOP("ConfigureUI", "Small (32x32)")),
- std::make_pair(64, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (64x64)")),
- std::make_pair(128, QT_TRANSLATE_NOOP("ConfigureUI", "Large (128x128)")),
- std::make_pair(256, QT_TRANSLATE_NOOP("ConfigureUI", "Full Size (256x256)")),
-};
+ constexpr std::array default_game_icon_sizes{
+ std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
+ std::make_pair(32, QT_TRANSLATE_NOOP("ConfigureUI", "Small (32x32)")),
+ std::make_pair(64, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (64x64)")),
+ std::make_pair(128, QT_TRANSLATE_NOOP("ConfigureUI", "Large (128x128)")),
+ std::make_pair(256, QT_TRANSLATE_NOOP("ConfigureUI", "Full Size (256x256)")),
+ };
-constexpr std::array default_folder_icon_sizes{
- std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
- std::make_pair(24, QT_TRANSLATE_NOOP("ConfigureUI", "Small (24x24)")),
- std::make_pair(48, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (48x48)")),
- std::make_pair(72, QT_TRANSLATE_NOOP("ConfigureUI", "Large (72x72)")),
-};
+ constexpr std::array default_folder_icon_sizes{
+ std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
+ std::make_pair(24, QT_TRANSLATE_NOOP("ConfigureUI", "Small (24x24)")),
+ std::make_pair(48, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (48x48)")),
+ std::make_pair(72, QT_TRANSLATE_NOOP("ConfigureUI", "Large (72x72)")),
+ };
-// clang-format off
-constexpr std::array row_text_names{
- QT_TRANSLATE_NOOP("ConfigureUI", "Filename"),
- QT_TRANSLATE_NOOP("ConfigureUI", "Filetype"),
- QT_TRANSLATE_NOOP("ConfigureUI", "Title ID"),
- QT_TRANSLATE_NOOP("ConfigureUI", "Title Name"),
- QT_TRANSLATE_NOOP("ConfigureUI", "None"),
-};
-// clang-format on
+ // clang-format off
+ constexpr std::array row_text_names{
+ QT_TRANSLATE_NOOP("ConfigureUI", "Filename"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Filetype"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Title ID"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Title Name"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "None"),
+ };
+ // clang-format on
-QString GetTranslatedGameIconSize(size_t index) {
- return QCoreApplication::translate("ConfigureUI", default_game_icon_sizes[index].second);
-}
+ QString GetTranslatedGameIconSize(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", default_game_icon_sizes[index].second);
+ }
-QString GetTranslatedFolderIconSize(size_t index) {
- return QCoreApplication::translate("ConfigureUI", default_folder_icon_sizes[index].second);
-}
+ QString GetTranslatedFolderIconSize(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", default_folder_icon_sizes[index].second);
+ }
-QString GetTranslatedRowTextName(size_t index) {
- return QCoreApplication::translate("ConfigureUI", row_text_names[index]);
-}
+ QString GetTranslatedRowTextName(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", row_text_names[index]);
+ }
} // Anonymous namespace
static float GetUpFactor(Settings::ResolutionSetup res_setup) {
@@ -81,7 +82,7 @@ static void PopulateResolutionComboBox(QComboBox* screenshot_height, QWidget* pa
screenshot_height->clear();
const auto& enumeration =
- Settings::EnumMetadata::Canonicalizations();
+ Settings::EnumMetadata::Canonicalizations();
std::set resolutions{};
for (const auto& [name, value] : enumeration) {
const float up_factor = GetUpFactor(value);
@@ -102,9 +103,9 @@ static u32 ScreenshotDimensionToInt(const QString& height) {
}
ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
- : QWidget(parent), ui{std::make_unique()},
- ratio{Settings::values.aspect_ratio.GetValue()},
- resolution_setting{Settings::values.resolution_setup.GetValue()}, system{system_} {
+: QWidget(parent), ui{std::make_unique()},
+ratio{Settings::values.aspect_ratio.GetValue()},
+resolution_setting{Settings::values.resolution_setup.GetValue()}, system{system_} {
ui->setupUi(this);
InitializeLanguageComboBox();
@@ -121,34 +122,39 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
SetConfiguration();
+ connect(ui->accentColorButton, &QPushButton::clicked, this, &ConfigureUi::OnAccentColorButtonPressed);
+ connect(ui->rainbowModeCheckBox, &QCheckBox::checkStateChanged, this, [this](int state) {
+ emit themeChanged();
+ });
+
// Force game list reload if any of the relevant settings are changed.
- connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
- connect(ui->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
- connect(ui->show_size, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
- connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
- connect(ui->show_play_time, &QCheckBox::stateChanged, this,
+ connect(ui->show_add_ons, &QCheckBox::checkStateChanged, this, &ConfigureUi::RequestGameListUpdate);
+ connect(ui->show_compat, &QCheckBox::checkStateChanged, this, &ConfigureUi::RequestGameListUpdate);
+ connect(ui->show_size, &QCheckBox::checkStateChanged, this, &ConfigureUi::RequestGameListUpdate);
+ connect(ui->show_types, &QCheckBox::checkStateChanged, this, &ConfigureUi::RequestGameListUpdate);
+ connect(ui->show_play_time, &QCheckBox::checkStateChanged, this,
&ConfigureUi::RequestGameListUpdate);
- connect(ui->game_icon_size_combobox, QOverload::of(&QComboBox::currentIndexChanged), this,
+ connect(ui->game_icon_size_combobox, &QComboBox::currentIndexChanged, this,
&ConfigureUi::RequestGameListUpdate);
- connect(ui->folder_icon_size_combobox, QOverload::of(&QComboBox::currentIndexChanged),
+ connect(ui->folder_icon_size_combobox, &QComboBox::currentIndexChanged,
this, &ConfigureUi::RequestGameListUpdate);
- connect(ui->row_1_text_combobox, QOverload::of(&QComboBox::currentIndexChanged), this,
+ connect(ui->row_1_text_combobox, &QComboBox::currentIndexChanged, this,
&ConfigureUi::RequestGameListUpdate);
- connect(ui->row_2_text_combobox, QOverload::of(&QComboBox::currentIndexChanged), this,
+ connect(ui->row_2_text_combobox, &QComboBox::currentIndexChanged, this,
&ConfigureUi::RequestGameListUpdate);
// Update text ComboBoxes after user interaction.
- connect(ui->row_1_text_combobox, QOverload::of(&QComboBox::activated),
+ connect(ui->row_1_text_combobox, &QComboBox::activated,
[this] { ConfigureUi::UpdateSecondRowComboBox(); });
- connect(ui->row_2_text_combobox, QOverload::of(&QComboBox::activated),
+ connect(ui->row_2_text_combobox, &QComboBox::activated,
[this] { ConfigureUi::UpdateFirstRowComboBox(); });
// Set screenshot path to user specification.
connect(ui->screenshot_path_button, &QToolButton::pressed, this, [this] {
auto dir =
- QFileDialog::getExistingDirectory(this, tr("Select Screenshots Path..."),
- QString::fromStdString(Common::FS::GetCitronPathString(
- Common::FS::CitronPath::ScreenshotsDir)));
+ QFileDialog::getExistingDirectory(this, tr("Select Screenshots Path..."),
+ QString::fromStdString(Common::FS::GetCitronPathString(
+ Common::FS::CitronPath::ScreenshotsDir)));
if (!dir.isEmpty()) {
if (dir.back() != QChar::fromLatin1('/')) {
dir.append(QChar::fromLatin1('/'));
@@ -167,7 +173,8 @@ ConfigureUi::~ConfigureUi() = default;
void ConfigureUi::ApplyConfiguration() {
UISettings::values.theme =
- ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString();
+ ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString();
+ UISettings::values.enable_rainbow_mode = ui->rainbowModeCheckBox->isChecked();
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.show_compat = ui->show_compat->isChecked();
UISettings::values.show_size = ui->show_size->isChecked();
@@ -180,7 +187,7 @@ void ConfigureUi::ApplyConfiguration() {
UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
Common::FS::SetCitronPath(Common::FS::CitronPath::ScreenshotsDir,
- ui->screenshot_path_edit->text().toStdString());
+ ui->screenshot_path_edit->text().toStdString());
const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
UISettings::values.screenshot_height.SetValue(height);
@@ -198,6 +205,7 @@ void ConfigureUi::SetConfiguration() {
ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme)));
ui->language_combobox->setCurrentIndex(ui->language_combobox->findData(
QString::fromStdString(UISettings::values.language.GetValue())));
+ ui->rainbowModeCheckBox->setChecked(UISettings::values.enable_rainbow_mode.GetValue());
ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
ui->show_size->setChecked(UISettings::values.show_size.GetValue());
@@ -221,6 +229,18 @@ void ConfigureUi::SetConfiguration() {
}
}
+void ConfigureUi::OnAccentColorButtonPressed() {
+ const QColor current_color(QString::fromStdString(UISettings::values.accent_color.GetValue()));
+ QColorDialog dialog(current_color, this);
+ if (dialog.exec() == QDialog::Accepted) {
+ const QColor color = dialog.selectedColor();
+ if (color.isValid()) {
+ UISettings::values.accent_color.SetValue(color.name().toStdString());
+ emit themeChanged();
+ }
+ }
+}
+
void ConfigureUi::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
@@ -263,10 +283,7 @@ void ConfigureUi::InitializeLanguageComboBox() {
ui->language_combobox->addItem(QStringLiteral("%1 (%2)").arg(lang, country), locale);
}
- // Unlike other configuration changes, interface language changes need to be reflected on the
- // interface immediately. This is done by passing a signal to the main window, and then
- // retranslating when passing back.
- connect(ui->language_combobox, qOverload(&QComboBox::currentIndexChanged), this,
+ connect(ui->language_combobox, &QComboBox::currentIndexChanged, this,
&ConfigureUi::OnLanguageChanged);
}
@@ -288,8 +305,8 @@ void ConfigureUi::InitializeRowComboBoxes() {
void ConfigureUi::UpdateFirstRowComboBox(bool init) {
const int currentIndex =
- init ? UISettings::values.row_1_text_id.GetValue()
- : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
+ init ? UISettings::values.row_1_text_id.GetValue()
+ : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
ui->row_1_text_combobox->clear();
@@ -307,8 +324,8 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
void ConfigureUi::UpdateSecondRowComboBox(bool init) {
const int currentIndex =
- init ? UISettings::values.row_2_text_id.GetValue()
- : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
+ init ? UISettings::values.row_2_text_id.GetValue()
+ : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
ui->row_2_text_combobox->clear();
@@ -340,10 +357,10 @@ void ConfigureUi::UpdateWidthText() {
const u32 height_undocked = Layout::ScreenUndocked::Height * up_factor;
const u32 width_undocked = UISettings::CalculateWidth(height_undocked, ratio);
ui->screenshot_width->setText(tr("Auto (%1 x %2, %3 x %4)", "Screenshot width value")
- .arg(width_undocked)
- .arg(height_undocked)
- .arg(width_docked)
- .arg(height_docked));
+ .arg(width_undocked)
+ .arg(height_undocked)
+ .arg(width_docked)
+ .arg(height_docked));
} else {
ui->screenshot_width->setText(QStringLiteral("%1 x").arg(width));
}
diff --git a/src/citron/configuration/configure_ui.h b/src/citron/configuration/configure_ui.h
index 2a2563a13..a66c12cb9 100644
--- a/src/citron/configuration/configure_ui.h
+++ b/src/citron/configuration/configure_ui.h
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -8,11 +9,11 @@
#include "common/settings_enums.h"
namespace Core {
-class System;
+ class System;
}
namespace Ui {
-class ConfigureUi;
+ class ConfigureUi;
}
class ConfigureUi : public QWidget {
@@ -27,11 +28,13 @@ public:
void UpdateScreenshotInfo(Settings::AspectRatio ratio,
Settings::ResolutionSetup resolution_info);
-private slots:
- void OnLanguageChanged(int index);
-
signals:
void LanguageChanged(const QString& locale);
+ void themeChanged();
+
+private slots:
+ void OnLanguageChanged(int index);
+ void OnAccentColorButtonPressed();
private:
void RequestGameListUpdate();
diff --git a/src/citron/configuration/configure_ui.ui b/src/citron/configuration/configure_ui.ui
index 0d889fe34..c035ebe3b 100644
--- a/src/citron/configuration/configure_ui.ui
+++ b/src/citron/configuration/configure_ui.ui
@@ -1,659 +1,569 @@
- ConfigureUi
-
-
-
- 0
- 0
- 1200
- 800
-
-
-
-
- 1000
- 600
-
-
-
- Form
-
-
- UI
-
-
- QWidget {
- background-color: #2b2b2b;
- color: #ffffff;
-}
-
-QGroupBox {
- font-weight: bold;
- border: 1px solid #3d3d3d;
- border-radius: 8px;
- margin-top: 12px;
- padding-top: 12px;
- background-color: #2b2b2b;
-}
-
-QGroupBox::title {
- subcontrol-origin: margin;
- left: 12px;
- padding: 0 8px 0 8px;
- color: #ffffff;
-}
-
-QCheckBox {
- color: #ffffff;
- spacing: 12px;
- padding: 6px;
- background-color: transparent;
- min-height: 24px;
-}
-
-QCheckBox::indicator {
- width: 18px;
- height: 18px;
- border: 2px solid #5d5d5d;
- border-radius: 4px;
- background-color: #3d3d3d;
-}
-
-QCheckBox::indicator:checked {
- background-color: #4a9eff;
- border-color: #4a9eff;
-}
-
-QCheckBox::indicator:hover {
- border-color: #4a9eff;
-}
-
-QComboBox {
- background-color: #3d3d3d;
- border: 1px solid #5d5d5d;
- border-radius: 6px;
- padding: 8px 12px;
- color: #ffffff;
- min-width: 160px;
- min-height: 28px;
-}
-
-QComboBox:hover {
- border-color: #4a9eff;
- background-color: #404040;
-}
-
-QComboBox:focus {
- border-color: #4a9eff;
- background-color: #404040;
-}
-
-QComboBox::drop-down {
- border: none;
- width: 24px;
- subcontrol-origin: padding;
- subcontrol-position: top right;
-}
-
-QComboBox::down-arrow {
- width: 12px;
- height: 12px;
-}
-
-QComboBox QAbstractItemView {
- background-color: #3d3d3d;
- border: 1px solid #4a9eff;
- selection-background-color: #4a9eff;
- color: #ffffff;
-}
-
-QLineEdit {
- background-color: #3d3d3d;
- border: 1px solid #5d5d5d;
- border-radius: 6px;
- padding: 8px 12px;
- color: #ffffff;
- min-height: 28px;
-}
-
-QLineEdit:focus {
- border-color: #4a9eff;
- background-color: #404040;
-}
-
-QToolButton {
- background-color: #4a9eff;
- color: #ffffff;
- border: none;
- padding: 8px 12px;
- border-radius: 6px;
- font-weight: bold;
- min-width: 40px;
- min-height: 32px;
-}
-
-QToolButton:hover {
- background-color: #5dafff;
-}
-
-QToolButton:pressed {
- background-color: #2980b9;
-}
-
-QLabel {
- color: #ffffff;
- background-color: transparent;
- padding: 4px;
- min-width: 140px;
-}
-
-
-
-
- 32
-
-
- 32
-
-
- 32
-
-
- 32
-
-
- 32
-
- -
-
-
- 20
-
-
-
-
-
- General
-
-
-
- 500
- 0
-
-
-
-
- 12
+ ConfigureUi
+
+
+
+ 0
+ 0
+ 1200
+ 800
+
-
- 20
+
+
+ 1000
+ 600
+
-
- 20
+
+ Form
-
- 20
+
+ UI
-
- 20
+
+ /* This stylesheet is a template. Placeholders like %%ACCENT_COLOR%% are replaced in C++. */
-
-
-
-
- Note: Changing language will apply your configuration.
-
-
- true
-
-
- color: #cccccc; font-size: 11px;
-
-
-
- -
-
-
- 16
-
-
-
-
-
- Interface language:
+
+
+ 32
-
-
- 140
- 0
-
+
+ 32
-
-
- -
-
-
-
- 0
- 0
-
+
+ 32
-
-
-
-
- -
-
-
- 16
-
-
-
-
-
- Theme:
+
+ 32
-
-
- 140
- 0
-
+
+ 32
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
- -
-
-
- Game List
-
-
-
- 500
- 0
-
-
-
-
- 12
-
-
- 20
-
-
- 20
-
-
- 20
-
-
- 20
-
-
-
-
-
- Show Compatibility List
-
-
-
- 0
- 32
-
-
-
-
- -
-
-
- Show Add-Ons Column
-
-
-
- 0
- 32
-
-
-
-
- -
-
-
- Show Size Column
-
-
-
- 0
- 32
-
-
-
-
- -
-
-
- Show File Types Column
-
-
-
- 0
- 32
-
-
-
-
- -
-
-
- Show Play Time Column
-
-
-
- 0
- 32
-
-
-
-
- -
-
-
- 16
-
-
-
-
-
- Game Icon Size:
-
-
-
- 140
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- -
-
-
- 16
-
-
-
-
-
- Folder Icon Size:
-
-
-
- 140
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- -
-
-
- 16
-
-
-
-
-
- Row 1 Text:
-
-
-
- 140
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- -
-
-
- 16
-
-
-
-
-
- Row 2 Text:
-
-
-
- 140
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
- -
-
-
- 20
-
-
-
-
-
- Screenshots
-
-
-
- 500
- 0
-
-
-
-
- 16
-
-
- 20
-
-
- 20
-
-
- 20
-
-
- 20
-
-
-
-
-
- Ask Where To Save Screenshots (Windows Only)
-
-
-
- 0
- 32
-
-
-
-
- -
-
-
- 12
-
-
-
-
-
- Screenshots Path:
-
-
-
- 140
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- ...
-
-
-
-
-
- -
-
-
- 12
-
-
-
-
-
- Resolution:
-
-
-
- 80
- 0
-
-
-
-
- -
-
-
- TextLabel
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- 120
- 0
-
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
+ -
+
+
+ 20
+
+
-
+
+
+ General
+
+
+
+ 500
+ 0
+
+
+
+
+ 12
+
+
+ 20
+
+
+ 20
+
+
+ 20
+
+
+ 20
+
+
-
+
+
+ Note: Changing language will apply your configuration.
+
+
+ true
+
+
+ color: #cccccc; font-size: 11px;
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Interface language:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Theme:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Accent Color:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+ Choose Color...
+
+
+
+ -
+
+
+ Enable Rainbow Mode
+
+
+
+
+
+
+
+
+ -
+
+
+ Game List
+
+
+
+ 500
+ 0
+
+
+
+
+ 12
+
+
+ 20
+
+
+ 20
+
+
+ 20
+
+
+ 20
+
+
-
+
+
+ Show Compatibility List
+
+
+
+ 0
+ 32
+
+
+
+
+ -
+
+
+ Show Add-Ons Column
+
+
+
+ 0
+ 32
+
+
+
+
+ -
+
+
+ Show Size Column
+
+
+
+ 0
+ 32
+
+
+
+
+ -
+
+
+ Show File Types Column
+
+
+
+ 0
+ 32
+
+
+
+
+ -
+
+
+ Show Play Time Column
+
+
+
+ 0
+ 32
+
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Game Icon Size:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Folder Icon Size:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Row 1 Text:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ 16
+
+
-
+
+
+ Row 2 Text:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+ -
+
+
+ 20
+
+
-
+
+
+ Screenshots
+
+
+
+ 500
+ 0
+
+
+
+
+ 16
+
+
+ 20
+
+
+ 20
+
+
+ 20
+
+
+ 20
+
+
-
+
+
+ Ask Where To Save Screenshots (Windows Only)
+
+
+
+ 0
+ 32
+
+
+
+
+ -
+
+
+ 12
+
+
-
+
+
+ Screenshots Path:
+
+
+
+ 140
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ ...
+
+
+
+
+
+ -
+
+
+ 12
+
+
-
+
+
+ Resolution:
+
+
+
+ 80
+ 0
+
+
+
+
+ -
+
+
+ TextLabel
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ 120
+ 0
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
diff --git a/src/citron/theme.h b/src/citron/theme.h
new file mode 100644
index 000000000..98c350e66
--- /dev/null
+++ b/src/citron/theme.h
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: 2025 citron Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#include
+#include "citron/uisettings.h"
+
+namespace Theme {
+
+ // Gets the user-defined accent color from settings, with a default fallback.
+ inline QString GetAccentColor() {
+ return QString::fromStdString(UISettings::values.accent_color.GetValue());
+ }
+
+ // Gets a lighter version of the accent color for hover effects.
+ inline QString GetAccentColorHover() {
+ QColor color(GetAccentColor());
+ return color.lighter(115).name(); // 115% of original brightness
+ }
+
+ // Gets a darker version of the accent color for pressed effects.
+ inline QString GetAccentColorPressed() {
+ QColor color(GetAccentColor());
+ return color.darker(120).name(); // 120% of original darkness
+ }
+
+} // namespace Theme
diff --git a/src/citron/uisettings.cpp b/src/citron/uisettings.cpp
index 2ac580d0d..f4db1824d 100644
--- a/src/citron/uisettings.cpp
+++ b/src/citron/uisettings.cpp
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
-// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
+// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include
@@ -9,13 +9,13 @@
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
namespace Settings {
-template class Setting;
-template class Setting;
-template class Setting;
-template class Setting;
-template class Setting;
-template class Setting;
-template class Setting;
+ template class Setting;
+ template class Setting;
+ template class Setting;
+ template class Setting;
+ template class Setting;
+ template class Setting;
+ template class Setting;
} // namespace Settings
#endif
@@ -23,93 +23,93 @@ namespace FS = Common::FS;
namespace UISettings {
-const Themes themes{{
- {"Default", "default"},
- {"Default Colorful", "colorful"},
- {"Dark", "qdarkstyle"},
- {"Dark Colorful", "colorful_dark"},
- {"Midnight Blue", "qdarkstyle_midnight_blue"},
- {"Midnight Blue Colorful", "colorful_midnight_blue"},
-}};
+ const Themes themes{{
+ {"Default", "default"},
+ {"Default Colorful", "colorful"},
+ {"Dark", "qdarkstyle"},
+ {"Dark Colorful", "colorful_dark"},
+ {"Midnight Blue", "qdarkstyle_midnight_blue"},
+ {"Midnight Blue Colorful", "colorful_midnight_blue"},
+ }};
-bool IsDarkTheme() {
- const auto& theme = UISettings::values.theme;
- return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") ||
- theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue");
-}
-
-Values values = {};
-
-u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
- switch (ratio) {
- case Settings::AspectRatio::R4_3:
- return height * 4 / 3;
- case Settings::AspectRatio::R21_9:
- return height * 21 / 9;
- case Settings::AspectRatio::R16_10:
- return height * 16 / 10;
- case Settings::AspectRatio::R32_9:
- return height * 32 / 9;
- case Settings::AspectRatio::R16_9:
- case Settings::AspectRatio::Stretch:
- // TODO: Move this function wherever appropriate to implement Stretched aspect
- break;
+ bool IsDarkTheme() {
+ const auto& theme = UISettings::values.theme;
+ return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") ||
+ theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue");
}
- return height * 16 / 9;
-}
-void SaveWindowState() {
- const auto window_state_config_loc =
+ Values values = {};
+
+ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
+ switch (ratio) {
+ case Settings::AspectRatio::R4_3:
+ return height * 4 / 3;
+ case Settings::AspectRatio::R21_9:
+ return height * 21 / 9;
+ case Settings::AspectRatio::R16_10:
+ return height * 16 / 10;
+ case Settings::AspectRatio::R32_9:
+ return height * 32 / 9;
+ case Settings::AspectRatio::R16_9:
+ case Settings::AspectRatio::Stretch:
+ // TODO: Move this function wherever appropriate to implement Stretched aspect
+ break;
+ }
+ return height * 16 / 9;
+ }
+
+ void SaveWindowState() {
+ const auto window_state_config_loc =
FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "window_state.ini");
- void(FS::CreateParentDir(window_state_config_loc));
- QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
+ void(FS::CreateParentDir(window_state_config_loc));
+ QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
- config.setValue(QStringLiteral("geometry"), values.geometry);
- config.setValue(QStringLiteral("state"), values.state);
- config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry);
- config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state);
- config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry);
+ config.setValue(QStringLiteral("geometry"), values.geometry);
+ config.setValue(QStringLiteral("state"), values.state);
+ config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry);
+ config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state);
+ config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry);
- config.sync();
-}
+ config.sync();
+ }
-void RestoreWindowState(std::unique_ptr& qtConfig) {
- const auto window_state_config_loc =
+ void RestoreWindowState(std::unique_ptr& qtConfig) {
+ const auto window_state_config_loc =
FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "window_state.ini");
- // Migrate window state from old location
- if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) {
- const auto config_loc =
+ // Migrate window state from old location
+ if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) {
+ const auto config_loc =
FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "qt-config.ini");
- QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat);
+ QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat);
+
+ config.beginGroup(QStringLiteral("UI"));
+ config.beginGroup(QStringLiteral("UILayout"));
+ values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
+ values.state = config.value(QStringLiteral("state")).toByteArray();
+ values.renderwindow_geometry =
+ config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
+ values.gamelist_header_state =
+ config.value(QStringLiteral("gameListHeaderState")).toByteArray();
+ values.microprofile_geometry =
+ config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
+ config.endGroup();
+ config.endGroup();
+ return;
+ }
+
+ void(FS::CreateParentDir(window_state_config_loc));
+ const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
- config.beginGroup(QStringLiteral("UI"));
- config.beginGroup(QStringLiteral("UILayout"));
values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
values.state = config.value(QStringLiteral("state")).toByteArray();
values.renderwindow_geometry =
- config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
+ config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
values.gamelist_header_state =
- config.value(QStringLiteral("gameListHeaderState")).toByteArray();
+ config.value(QStringLiteral("gameListHeaderState")).toByteArray();
values.microprofile_geometry =
- config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
- config.endGroup();
- config.endGroup();
- return;
+ config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
}
- void(FS::CreateParentDir(window_state_config_loc));
- const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
-
- values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
- values.state = config.value(QStringLiteral("state")).toByteArray();
- values.renderwindow_geometry =
- config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
- values.gamelist_header_state =
- config.value(QStringLiteral("gameListHeaderState")).toByteArray();
- values.microprofile_geometry =
- config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
-}
-
} // namespace UISettings
diff --git a/src/citron/uisettings.h b/src/citron/uisettings.h
index 19b2cfd71..e8bb4445f 100644
--- a/src/citron/uisettings.h
+++ b/src/citron/uisettings.h
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -23,234 +24,237 @@ using Settings::SwitchableSetting;
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
namespace Settings {
-extern template class Setting;
-extern template class Setting;
-extern template class Setting;
-extern template class Setting;
-extern template class Setting;
-extern template class Setting;
-extern template class Setting;
+ extern template class Setting;
+ extern template class Setting;
+ extern template class Setting;
+ extern template class Setting;
+ extern template class Setting;
+ extern template class Setting;
+ extern template class Setting;
} // namespace Settings
#endif
namespace UISettings {
-bool IsDarkTheme();
+ bool IsDarkTheme();
-struct ContextualShortcut {
- std::string keyseq;
- std::string controller_keyseq;
- int context;
- bool repeat;
-};
+ struct ContextualShortcut {
+ std::string keyseq;
+ std::string controller_keyseq;
+ int context;
+ bool repeat;
+ };
-struct Shortcut {
- std::string name;
- std::string group;
- ContextualShortcut shortcut;
-};
+ struct Shortcut {
+ std::string name;
+ std::string group;
+ ContextualShortcut shortcut;
+ };
-enum class Theme {
- Default,
- DefaultColorful,
- Dark,
- DarkColorful,
- MidnightBlue,
- MidnightBlueColorful,
-};
+ enum class Theme {
+ Default,
+ DefaultColorful,
+ Dark,
+ DarkColorful,
+ MidnightBlue,
+ MidnightBlueColorful,
+ };
-static constexpr Theme default_theme{
-#ifdef _WIN32
- Theme::DarkColorful
-#else
- Theme::DefaultColorful
-#endif
-};
+ static constexpr Theme default_theme{
+ #ifdef _WIN32
+ Theme::DarkColorful
+ #else
+ Theme::DefaultColorful
+ #endif
+ };
-using Themes = std::array, 6>;
-extern const Themes themes;
+ using Themes = std::array, 6>;
+ extern const Themes themes;
-struct GameDir {
- std::string path;
- bool deep_scan = false;
- bool expanded = false;
- bool operator==(const GameDir& rhs) const {
- return path == rhs.path;
- }
- bool operator!=(const GameDir& rhs) const {
- return !operator==(rhs);
- }
-};
+ struct GameDir {
+ std::string path;
+ bool deep_scan = false;
+ bool expanded = false;
+ bool operator==(const GameDir& rhs) const {
+ return path == rhs.path;
+ }
+ bool operator!=(const GameDir& rhs) const {
+ return !operator==(rhs);
+ }
+ };
-struct Values {
- Settings::Linkage linkage{1000};
+ struct Values {
+ Settings::Linkage linkage{1000};
- QByteArray geometry;
- QByteArray state;
+ QByteArray geometry;
+ QByteArray state;
- QByteArray renderwindow_geometry;
+ QByteArray renderwindow_geometry;
- QByteArray gamelist_header_state;
+ QByteArray gamelist_header_state;
- QByteArray microprofile_geometry;
- Setting microprofile_visible{linkage, false, "microProfileDialogVisible",
- Category::UiLayout};
+ QByteArray microprofile_geometry;
+ Setting microprofile_visible{linkage, false, "microProfileDialogVisible",
+ Category::UiLayout};
- Setting single_window_mode{linkage, true, "singleWindowMode", Category::Ui};
- Setting fullscreen{linkage, false, "fullscreen", Category::Ui};
- Setting display_titlebar{linkage, true, "displayTitleBars", Category::Ui};
- Setting show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
- Setting show_status_bar{linkage, true, "showStatusBar", Category::Ui};
- Setting show_performance_overlay{linkage, false, "showPerformanceOverlay", Category::Ui};
- Setting show_vram_overlay{linkage, false, "showVramOverlay", Category::Ui};
+ Setting single_window_mode{linkage, true, "singleWindowMode", Category::Ui};
+ Setting fullscreen{linkage, false, "fullscreen", Category::Ui};
+ Setting display_titlebar{linkage, true, "displayTitleBars", Category::Ui};
+ Setting show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
+ Setting show_status_bar{linkage, true, "showStatusBar", Category::Ui};
+ Setting show_performance_overlay{linkage, false, "showPerformanceOverlay", Category::Ui};
+ Setting show_vram_overlay{linkage, false, "showVramOverlay", Category::Ui};
- SwitchableSetting confirm_before_stopping{linkage,
- ConfirmStop::Ask_Always,
- "confirmStop",
- Category::UiGeneral,
- Settings::Specialization::Default,
- true,
- true};
+ SwitchableSetting confirm_before_stopping{linkage,
+ ConfirmStop::Ask_Always,
+ "confirmStop",
+ Category::UiGeneral,
+ Settings::Specialization::Default,
+ true,
+ true};
- Setting first_start{linkage, true, "firstStart", Category::Ui};
- Setting pause_when_in_background{linkage,
- false,
- "pauseWhenInBackground",
- Category::UiGeneral,
- Settings::Specialization::Default,
- true,
- true};
- Setting mute_when_in_background{linkage,
- false,
- "muteWhenInBackground",
- Category::UiAudio,
- Settings::Specialization::Default,
- true,
- true};
- Setting hide_mouse{
- linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
- true, true};
- Setting controller_applet_disabled{linkage, false, "disableControllerApplet",
- Category::UiGeneral};
- // Set when Vulkan is known to crash the application
- bool has_broken_vulkan = false;
+ Setting first_start{linkage, true, "firstStart", Category::Ui};
+ Setting pause_when_in_background{linkage,
+ false,
+ "pauseWhenInBackground",
+ Category::UiGeneral,
+ Settings::Specialization::Default,
+ true,
+ true};
+ Setting mute_when_in_background{linkage,
+ false,
+ "muteWhenInBackground",
+ Category::UiAudio,
+ Settings::Specialization::Default,
+ true,
+ true};
+ Setting hide_mouse{
+ linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
+ true, true};
+ Setting controller_applet_disabled{linkage, false, "disableControllerApplet",
+ Category::UiGeneral};
+ // Set when Vulkan is known to crash the application
+ bool has_broken_vulkan = false;
- Setting select_user_on_boot{linkage,
- false,
- "select_user_on_boot",
- Category::UiGeneral,
- Settings::Specialization::Default,
- true,
- true};
- Setting disable_web_applet{linkage, true, "disable_web_applet", Category::Ui};
+ Setting select_user_on_boot{linkage,
+ false,
+ "select_user_on_boot",
+ Category::UiGeneral,
+ Settings::Specialization::Default,
+ true,
+ true};
+ Setting disable_web_applet{linkage, true, "disable_web_applet", Category::Ui};
- // Discord RPC
- Setting enable_discord_presence{linkage, true, "enable_discord_presence", Category::Ui};
+ // Discord RPC
+ Setting enable_discord_presence{linkage, true, "enable_discord_presence", Category::Ui};
- // logging
- Setting show_console{linkage, false, "showConsole", Category::Ui};
+ // logging
+ Setting show_console{linkage, false, "showConsole", Category::Ui};
- // Screenshots
- Setting enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
- Category::Screenshots};
- Setting screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots};
+ // Screenshots
+ Setting enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
+ Category::Screenshots};
+ Setting screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots};
- std::string roms_path;
- std::string game_dir_deprecated;
- bool game_dir_deprecated_deepscan;
- QVector game_dirs;
- QStringList recent_files;
- Setting language{linkage, {}, "language", Category::Paths};
+ std::string roms_path;
+ std::string game_dir_deprecated;
+ bool game_dir_deprecated_deepscan;
+ QVector game_dirs;
+ QStringList recent_files;
+ Setting language{linkage, {}, "language", Category::Paths};
- std::string theme;
+ std::string theme;
- // Shortcut name
- std::vector shortcuts;
+ Setting accent_color{linkage, "#4a9eff", "accent_color", Category::Ui};
+ Setting enable_rainbow_mode{linkage, false, "enable_rainbow_mode", Category::Ui};
- Setting callout_flags{linkage, 0, "calloutFlags", Category::Ui};
+ // Shortcut name
+ std::vector shortcuts;
- // multiplayer settings
- Setting multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
- Setting multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer};
- Setting multiplayer_filter_games_owned{linkage, false, "filter_games_owned",
- Category::Multiplayer};
- Setting multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty",
+ Setting callout_flags{linkage, 0, "calloutFlags", Category::Ui};
+
+ // multiplayer settings
+ Setting multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
+ Setting multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer};
+ Setting multiplayer_filter_games_owned{linkage, false, "filter_games_owned",
+ Category::Multiplayer};
+ Setting multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty",
Category::Multiplayer};
- Setting multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full",
- Category::Multiplayer};
- Setting multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
- Setting multiplayer_port{linkage, 24872, 0,
- UINT16_MAX, "port", Category::Multiplayer};
- Setting multiplayer_room_nickname{
- linkage, {}, "room_nickname", Category::Multiplayer};
- Setting multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer};
- Setting multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer};
- Setting multiplayer_room_port{linkage, 24872, 0,
- UINT16_MAX, "room_port", Category::Multiplayer};
- Setting multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer};
- Setting multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer};
- Setting multiplayer_room_description{
- linkage, {}, "room_description", Category::Multiplayer};
- std::pair, std::vector> multiplayer_ban_list;
+ Setting multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full",
+ Category::Multiplayer};
+ Setting multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
+ Setting multiplayer_port{linkage, 24872, 0,
+ UINT16_MAX, "port", Category::Multiplayer};
+ Setting multiplayer_room_nickname{
+ linkage, {}, "room_nickname", Category::Multiplayer};
+ Setting multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer};
+ Setting multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer};
+ Setting multiplayer_room_port{linkage, 24872, 0,
+ UINT16_MAX, "room_port", Category::Multiplayer};
+ Setting multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer};
+ Setting multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer};
+ Setting multiplayer_room_description{
+ linkage, {}, "room_description", Category::Multiplayer};
+ std::pair, std::vector> multiplayer_ban_list;
- // Game List
- Setting show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
- Setting game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
- Setting folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
- Setting row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
- Setting row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
- Setting game_list_grid_view{linkage, false, "game_list_grid_view", Category::UiGameList};
- std::atomic_bool is_game_list_reload_pending{false};
- Setting cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
- Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
- QVector favorited_ids;
+ // Game List
+ Setting show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
+ Setting game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
+ Setting folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
+ Setting row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
+ Setting row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
+ Setting game_list_grid_view{linkage, false, "game_list_grid_view", Category::UiGameList};
+ std::atomic_bool is_game_list_reload_pending{false};
+ Setting cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
+ Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
+ QVector favorited_ids;
- // Compatibility List
- Setting show_compat{linkage, false, "show_compat", Category::UiGameList};
+ // Compatibility List
+ Setting show_compat{linkage, false, "show_compat", Category::UiGameList};
- // Size & File Types Column
- Setting show_size{linkage, true, "show_size", Category::UiGameList};
- Setting show_types{linkage, true, "show_types", Category::UiGameList};
+ // Size & File Types Column
+ Setting show_size{linkage, true, "show_size", Category::UiGameList};
+ Setting show_types{linkage, true, "show_types", Category::UiGameList};
- // Play time
- Setting show_play_time{linkage, true, "show_play_time", Category::UiGameList};
+ // Play time
+ Setting show_play_time{linkage, true, "show_play_time", Category::UiGameList};
- bool configuration_applied;
- bool reset_to_defaults;
- bool shortcut_already_warned{false};
-};
+ bool configuration_applied;
+ bool reset_to_defaults;
+ bool shortcut_already_warned{false};
+ };
-extern Values values;
+ extern Values values;
-u32 CalculateWidth(u32 height, Settings::AspectRatio ratio);
+ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio);
-void SaveWindowState();
-void RestoreWindowState(std::unique_ptr& qtConfig);
+ void SaveWindowState();
+ void RestoreWindowState(std::unique_ptr& qtConfig);
-// This shouldn't have anything except static initializers (no functions). So
-// QKeySequence(...).toString() is NOT ALLOWED HERE.
-// This must be in alphabetical order according to action name as it must have the same order as
-// UISetting::values.shortcuts, which is alphabetically ordered.
-// clang-format off
-const std::array default_hotkeys{{
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit citron")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
- {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
+ // This shouldn't have anything except static initializers (no functions). So
+ // QKeySequence(...).toString() is NOT ALLOWED HERE.
+ // This must be in alphabetical order according to action name as it must have the same order as
+ // UISetting::values.shortcuts, which is alphabetically ordered.
+ // clang-format off
+ const std::array default_hotkeys{{
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit citron")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
+ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
@@ -262,7 +266,7 @@ const std::array default_hotkeys{{
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}},
-}};
+ }};
// clang-format on
} // namespace UISettings