From 691c3d6b11d6095a274409a52b529b658f87efce Mon Sep 17 00:00:00 2001 From: collecting <217662237+CollectingW@users.noreply.github.com> Date: Wed, 20 May 2026 02:25:46 -0400 Subject: [PATCH] citron: Add background image history/reset, fix custom icon/poster override & Permanent Dark Theme --- dist/qt_themes/default_dark/style.qss | 4 +- .../configuration/configure_neo_themes.cpp | 57 ++++++++++++++++++- .../configuration/configure_neo_themes.h | 1 + src/citron/configuration/configure_ui.cpp | 37 +++++++++--- src/citron/configuration/qt_config.cpp | 7 +++ src/citron/main.cpp | 38 +++++++++---- src/citron/uisettings.h | 1 + 7 files changed, 122 insertions(+), 23 deletions(-) diff --git a/dist/qt_themes/default_dark/style.qss b/dist/qt_themes/default_dark/style.qss index 5e1256a332..809c672f64 100644 --- a/dist/qt_themes/default_dark/style.qss +++ b/dist/qt_themes/default_dark/style.qss @@ -94,7 +94,7 @@ QGroupBox#groupPlayer5Connected:checked, QGroupBox#groupPlayer6Connected:checked, QGroupBox#groupPlayer7Connected:checked, QGroupBox#groupPlayer8Connected:checked { - background-color: #f5f5f5; + background-color: #24242a; } QWidget#topControllerApplet { @@ -108,7 +108,7 @@ QWidget#bottomControllerApplet { QWidget#topPerGameInput, QWidget#middleControllerApplet { - background-color: #fff; + background-color: #1e1e24; } QWidget#topPerGameInput QComboBox, diff --git a/src/citron/configuration/configure_neo_themes.cpp b/src/citron/configuration/configure_neo_themes.cpp index d0df197587..0814ef331f 100644 --- a/src/citron/configuration/configure_neo_themes.cpp +++ b/src/citron/configuration/configure_neo_themes.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -119,13 +120,23 @@ ConfigureNeoThemes::ConfigureNeoThemes(QWidget* parent) : QWidget(parent) { bg_layout->setSpacing(10); button_bg_path = new QPushButton(tr("Select Image..."), bg_group); + auto* button_bg_reset = new QPushButton(tr("Reset"), bg_group); + + auto* bg_btn_layout = new QHBoxLayout(); + bg_btn_layout->addWidget(button_bg_path); + bg_btn_layout->addWidget(button_bg_reset); + label_bg_path = new QLabel(bg_group); label_bg_path->setWordWrap(true); label_bg_path->setStyleSheet(QStringLiteral("font-size: 10px; color: gray;")); - bg_layout->addRow(tr("Background Image:"), button_bg_path); + bg_layout->addRow(tr("Background Image:"), bg_btn_layout); bg_layout->addRow(label_bg_path); - connect(button_bg_path, &QPushButton::clicked, this, &ConfigureNeoThemes::OnSelectBG); + UpdateBGButtonMenu(); + + connect(button_bg_reset, &QPushButton::clicked, this, [this] { + label_bg_path->setText(tr("No background image selected.")); + }); slider_bg_opacity = new QSlider(Qt::Horizontal, bg_group); slider_bg_opacity->setRange(0, 255); @@ -322,6 +333,7 @@ void ConfigureNeoThemes::SetConfiguration() { m_rainbow_mode = UISettings::values.enable_rainbow_mode.GetValue(); checkbox_rainbow_mode->setChecked(m_rainbow_mode); + UpdateBGButtonMenu(); } void ConfigureNeoThemes::OnSelectBG() { @@ -372,8 +384,47 @@ void ConfigureNeoThemes::ApplyConfiguration() { UISettings::values.custom_selection_color.SetValue(m_selection_color); UISettings::values.custom_list_bg_color.SetValue(m_list_bg_color); UISettings::values.custom_header_opacity.SetValue(static_cast(slider_header_opacity->value())); - UISettings::values.custom_game_list_bg_path.SetValue(label_bg_path->text().toStdString()); + std::string new_bg_path = label_bg_path->text().toStdString(); + if (new_bg_path == tr("No background image selected.").toStdString()) { + new_bg_path = ""; + } + if (!new_bg_path.empty()) { + QString q_path = QString::fromStdString(new_bg_path); + UISettings::values.recent_backgrounds.removeAll(q_path); + UISettings::values.recent_backgrounds.prepend(q_path); + while (UISettings::values.recent_backgrounds.size() > 5) { + UISettings::values.recent_backgrounds.removeLast(); + } + } + UISettings::values.custom_game_list_bg_path.SetValue(new_bg_path); UISettings::values.custom_game_list_bg_opacity.SetValue( static_cast(slider_bg_opacity->value())); UISettings::values.enable_rainbow_mode.SetValue(checkbox_rainbow_mode->isChecked()); + UpdateBGButtonMenu(); +} + +void ConfigureNeoThemes::UpdateBGButtonMenu() { + auto* menu = button_bg_path->menu(); + if (!menu) { + menu = new QMenu(button_bg_path); + button_bg_path->setMenu(menu); + } + menu->clear(); + + auto* select_action = menu->addAction(tr("Select New Image...")); + connect(select_action, &QAction::triggered, this, &ConfigureNeoThemes::OnSelectBG); + + auto* previous_menu = menu->addMenu(tr("Previous")); + const auto& recents = UISettings::values.recent_backgrounds; + if (recents.isEmpty()) { + auto* empty_action = previous_menu->addAction(tr("No previous images")); + empty_action->setEnabled(false); + } else { + for (const auto& path : recents) { + auto* path_action = previous_menu->addAction(path); + connect(path_action, &QAction::triggered, this, [this, path] { + label_bg_path->setText(path); + }); + } + } } diff --git a/src/citron/configuration/configure_neo_themes.h b/src/citron/configuration/configure_neo_themes.h index 9b725a5364..a24fcac97a 100644 --- a/src/citron/configuration/configure_neo_themes.h +++ b/src/citron/configuration/configure_neo_themes.h @@ -24,6 +24,7 @@ private: void SetConfiguration(); void OnSelectBG(); void OnSelectColor(QPushButton* button, const QString& title, std::string& setting); + void UpdateBGButtonMenu(); QComboBox* ui_theme_combo{nullptr}; diff --git a/src/citron/configuration/configure_ui.cpp b/src/citron/configuration/configure_ui.cpp index d33d619035..0e56c1d6b5 100644 --- a/src/citron/configuration/configure_ui.cpp +++ b/src/citron/configuration/configure_ui.cpp @@ -261,10 +261,21 @@ void ConfigureUi::SetConfiguration() { ui->show_play_time->setChecked(UISettings::values.show_play_time.GetValue()); ui->show_online_column->setChecked(UISettings::values.show_online_column.GetValue()); ui->game_list_poster_view->setChecked(UISettings::values.game_list_poster_view.GetValue()); - ui->game_icon_size_combobox->setCurrentIndex( - ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue())); - ui->folder_icon_size_combobox->setCurrentIndex( - ui->folder_icon_size_combobox->findData(UISettings::values.folder_icon_size.GetValue())); + int game_icon_index = ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue()); + if (game_icon_index == -1) { + u32 custom_size = UISettings::values.game_icon_size.GetValue(); + ui->game_icon_size_combobox->addItem(tr("Custom (%1x%1)").arg(custom_size), custom_size); + game_icon_index = ui->game_icon_size_combobox->findData(custom_size); + } + ui->game_icon_size_combobox->setCurrentIndex(game_icon_index); + + int folder_icon_index = ui->folder_icon_size_combobox->findData(UISettings::values.folder_icon_size.GetValue()); + if (folder_icon_index == -1) { + u32 custom_size = UISettings::values.folder_icon_size.GetValue(); + ui->folder_icon_size_combobox->addItem(tr("Custom (%1x%1)").arg(custom_size), custom_size); + folder_icon_index = ui->folder_icon_size_combobox->findData(custom_size); + } + ui->folder_icon_size_combobox->setCurrentIndex(folder_icon_index); ui->enable_screenshot_save_as->setChecked( UISettings::values.enable_screenshot_save_as.GetValue()); @@ -298,13 +309,23 @@ void ConfigureUi::RetranslateUI() { for (int i = 0; i < ui->game_icon_size_combobox->count(); i++) { - ui->game_icon_size_combobox->setItemText(i, - GetTranslatedGameIconSize(static_cast(i))); + if (static_cast(i) < default_game_icon_sizes.size()) { + ui->game_icon_size_combobox->setItemText(i, + GetTranslatedGameIconSize(static_cast(i))); + } else { + u32 custom_size = ui->game_icon_size_combobox->itemData(i).toUInt(); + ui->game_icon_size_combobox->setItemText(i, tr("Custom (%1x%1)").arg(custom_size)); + } } for (int i = 0; i < ui->folder_icon_size_combobox->count(); i++) { - ui->folder_icon_size_combobox->setItemText( - i, GetTranslatedFolderIconSize(static_cast(i))); + if (static_cast(i) < default_folder_icon_sizes.size()) { + ui->folder_icon_size_combobox->setItemText( + i, GetTranslatedFolderIconSize(static_cast(i))); + } else { + u32 custom_size = ui->folder_icon_size_combobox->itemData(i).toUInt(); + ui->folder_icon_size_combobox->setItemText(i, tr("Custom (%1x%1)").arg(custom_size)); + } } for (int i = 0; i < ui->row_1_text_combobox->count(); i++) { diff --git a/src/citron/configuration/qt_config.cpp b/src/citron/configuration/qt_config.cpp index 3ab2fffb46..1cf26e3861 100644 --- a/src/citron/configuration/qt_config.cpp +++ b/src/citron/configuration/qt_config.cpp @@ -248,6 +248,10 @@ void QtConfig::ReadPathValues() { QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); + UISettings::values.recent_backgrounds = + QString::fromStdString(ReadStringSetting(std::string("recentBackgrounds"))) + .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); + ReadCategory(Settings::Category::Paths); EndGroup(); @@ -479,6 +483,9 @@ void QtConfig::SavePathValues() { WriteStringSetting(std::string("recentFiles"), UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); + WriteStringSetting(std::string("recentBackgrounds"), + UISettings::values.recent_backgrounds.join(QStringLiteral(", ")).toStdString()); + EndGroup(); } diff --git a/src/citron/main.cpp b/src/citron/main.cpp index 75cd33537d..c23ecf0019 100644 --- a/src/citron/main.cpp +++ b/src/citron/main.cpp @@ -6339,15 +6339,33 @@ void GMainWindow::filterBarSetChecked(bool state) { } static void AdjustLinkColor() { - QPalette new_pal(qApp->palette()); - if (UISettings::IsDarkTheme()) { - new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255)); - } else { - new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255)); - } - if (qApp->palette().color(QPalette::Link) != new_pal.color(QPalette::Link)) { - qApp->setPalette(new_pal); - } + QPalette darkPalette; + + QColor darkColor(36, 36, 42); // #24242a - Onyx bg + QColor grayColor(30, 30, 35); // #1e1e23 - darker bg + QColor baseColor(25, 25, 28); // #19191c - even darker base + + darkPalette.setColor(QPalette::Window, darkColor); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, baseColor); + darkPalette.setColor(QPalette::AlternateBase, grayColor); + darkPalette.setColor(QPalette::ToolTipBase, darkColor); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, darkColor); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Link, QColor(0, 190, 255)); + darkPalette.setColor(QPalette::Highlight, QColor(60, 120, 216)); + darkPalette.setColor(QPalette::HighlightedText, Qt::white); + + // Disabled states + darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(128, 128, 128)); + darkPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(128, 128, 128)); + darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); + darkPalette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80, 80, 80)); + + qApp->setPalette(darkPalette); } void GMainWindow::UpdateUITheme() { @@ -6383,8 +6401,8 @@ void GMainWindow::UpdateUITheme() { // For explicit themes, use the dedicated icon sets. QIcon::setThemeName(current_theme); QIcon::setThemeSearchPaths(QStringList(QStringLiteral(":/icons"))); - AdjustLinkColor(); } + AdjustLinkColor(); // Always load the stylesheet unless the theme is the true default (no explicit QSS) if (current_theme != QStringLiteral("default")) { diff --git a/src/citron/uisettings.h b/src/citron/uisettings.h index ebebc6fa77..01c8561e14 100644 --- a/src/citron/uisettings.h +++ b/src/citron/uisettings.h @@ -176,6 +176,7 @@ namespace UISettings { bool game_dir_deprecated_deepscan; QVector game_dirs; QStringList recent_files; + QStringList recent_backgrounds; Setting language{linkage, {}, "language", Category::Paths}; std::string theme;