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();