mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-04-18 10:40:48 -04:00
Merge pull request 'fix(UI): Overhaul Rainbow Mode architecture' (#74) from fix/rainbow-mode into main
Reviewed-on: https://git.citron-emu.org/Citron/Emulator/pulls/74
This commit is contained in:
@@ -233,6 +233,8 @@ add_executable(citron
|
|||||||
util/performance_overlay.h
|
util/performance_overlay.h
|
||||||
util/multiplayer_room_overlay.cpp
|
util/multiplayer_room_overlay.cpp
|
||||||
util/multiplayer_room_overlay.h
|
util/multiplayer_room_overlay.h
|
||||||
|
util/rainbow_style.cpp
|
||||||
|
util/rainbow_style.h
|
||||||
util/vram_overlay.cpp
|
util/vram_overlay.cpp
|
||||||
util/vram_overlay.h
|
util/vram_overlay.h
|
||||||
util/sequence_dialog/sequence_dialog.cpp
|
util/sequence_dialog/sequence_dialog.cpp
|
||||||
@@ -455,7 +457,7 @@ endif()
|
|||||||
|
|
||||||
target_link_libraries(citron PRIVATE Vulkan::Headers)
|
target_link_libraries(citron PRIVATE Vulkan::Headers)
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_include_directories(citron PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
target_link_libraries(citron PRIVATE Qt6::GuiPrivate)
|
||||||
endif()
|
endif()
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
target_link_libraries(citron PRIVATE Qt6::DBus)
|
target_link_libraries(citron PRIVATE Qt6::DBus)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "citron/configuration/configure_ui.h"
|
#include "citron/configuration/configure_ui.h"
|
||||||
#include "citron/configuration/configure_web.h"
|
#include "citron/configuration/configure_web.h"
|
||||||
#include "citron/configuration/style_animation_event_filter.h"
|
#include "citron/configuration/style_animation_event_filter.h"
|
||||||
|
#include "citron/util/rainbow_style.h"
|
||||||
#include "citron/game_list.h"
|
#include "citron/game_list.h"
|
||||||
#include "citron/hotkeys.h"
|
#include "citron/hotkeys.h"
|
||||||
#include "citron/main.h"
|
#include "citron/main.h"
|
||||||
@@ -99,7 +100,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
|
|||||||
network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
|
network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
|
||||||
profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
|
profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
|
||||||
system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *builder, this)},
|
system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *builder, this)},
|
||||||
web_tab{std::make_unique<ConfigureWeb>(this)}, rainbow_timer{new QTimer(this)} {
|
web_tab{std::make_unique<ConfigureWeb>(this)} {
|
||||||
|
|
||||||
if (auto* main_window = qobject_cast<GMainWindow*>(parent)) {
|
if (auto* main_window = qobject_cast<GMainWindow*>(parent)) {
|
||||||
connect(filesystem_tab.get(), &ConfigureFilesystem::RequestGameListRefresh,
|
connect(filesystem_tab.get(), &ConfigureFilesystem::RequestGameListRefresh,
|
||||||
@@ -169,7 +170,6 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
|
|||||||
connect(tab_button_group.get(), qOverload<int>(&QButtonGroup::idClicked), this, &ConfigureDialog::AnimateTabSwitch);
|
connect(tab_button_group.get(), qOverload<int>(&QButtonGroup::idClicked), this, &ConfigureDialog::AnimateTabSwitch);
|
||||||
connect(ui_tab.get(), &ConfigureUi::themeChanged, this, &ConfigureDialog::UpdateTheme);
|
connect(ui_tab.get(), &ConfigureUi::themeChanged, this, &ConfigureDialog::UpdateTheme);
|
||||||
connect(ui_tab.get(), &ConfigureUi::UIPositioningChanged, this, &ConfigureDialog::SetUIPositioning);
|
connect(ui_tab.get(), &ConfigureUi::UIPositioningChanged, this, &ConfigureDialog::SetUIPositioning);
|
||||||
connect(rainbow_timer, &QTimer::timeout, this, &ConfigureDialog::UpdateTheme);
|
|
||||||
web_tab->SetWebServiceConfigEnabled(enable_web_config);
|
web_tab->SetWebServiceConfigEnabled(enable_web_config);
|
||||||
hotkeys_tab->Populate(registry);
|
hotkeys_tab->Populate(registry);
|
||||||
input_tab->Initialize(input_subsystem);
|
input_tab->Initialize(input_subsystem);
|
||||||
@@ -192,51 +192,70 @@ ConfigureDialog::~ConfigureDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDialog::UpdateTheme() {
|
void ConfigureDialog::UpdateTheme() {
|
||||||
QString accent_color_str;
|
const bool is_rainbow = UISettings::values.enable_rainbow_mode.GetValue();
|
||||||
if (UISettings::values.enable_rainbow_mode.GetValue()) {
|
const QString accent = Theme::GetAccentColor();
|
||||||
rainbow_hue += 0.003f;
|
|
||||||
if (rainbow_hue > 1.0f) rainbow_hue = 0.0f;
|
|
||||||
QColor accent_color = QColor::fromHsvF(rainbow_hue, 0.8f, 1.0f);
|
|
||||||
accent_color_str = accent_color.name(QColor::HexRgb);
|
|
||||||
if (!rainbow_timer->isActive()) rainbow_timer->start(150);
|
|
||||||
} else {
|
|
||||||
if (rainbow_timer->isActive()) rainbow_timer->stop();
|
|
||||||
accent_color_str = Theme::GetAccentColor();
|
|
||||||
}
|
|
||||||
QColor accent_color(accent_color_str);
|
|
||||||
const QString accent_color_hover = accent_color.lighter(115).name(QColor::HexRgb);
|
|
||||||
const QString accent_color_pressed = accent_color.darker(120).name(QColor::HexRgb);
|
|
||||||
const bool is_dark = IsDarkMode();
|
const bool is_dark = IsDarkMode();
|
||||||
const QString bg_color = is_dark ? QStringLiteral("#2b2b2b") : QStringLiteral("#ffffff");
|
|
||||||
const QString text_color = is_dark ? QStringLiteral("#ffffff") : QStringLiteral("#000000");
|
const QString bg = is_dark ? QStringLiteral("#2b2b2b") : QStringLiteral("#ffffff");
|
||||||
const QString secondary_bg_color = is_dark ? QStringLiteral("#3d3d3d") : QStringLiteral("#f0f0f0");
|
const QString txt = is_dark ? QStringLiteral("#ffffff") : QStringLiteral("#000000");
|
||||||
const QString tertiary_bg_color = is_dark ? QStringLiteral("#5d5d5d") : QStringLiteral("#d3d3d3");
|
const QString sec = is_dark ? QStringLiteral("#3d3d3d") : QStringLiteral("#f0f0f0");
|
||||||
const QString button_bg_color = is_dark ? QStringLiteral("#383838") : QStringLiteral("#e1e1e1");
|
const QString ter = is_dark ? QStringLiteral("#5d5d5d") : QStringLiteral("#d3d3d3");
|
||||||
const QString hover_bg_color = is_dark ? QStringLiteral("#4d4d4d") : QStringLiteral("#e8f0fe");
|
const QString b_bg = is_dark ? QStringLiteral("#383838") : QStringLiteral("#e1e1e1");
|
||||||
const QString focus_bg_color = is_dark ? QStringLiteral("#404040") : QStringLiteral("#e8f0fe");
|
const QString h_bg = is_dark ? QStringLiteral("#4d4d4d") : QStringLiteral("#e8f0fe");
|
||||||
const QString disabled_text_color = is_dark ? QStringLiteral("#8d8d8d") : QStringLiteral("#a0a0a0");
|
const QString f_bg = is_dark ? QStringLiteral("#404040") : QStringLiteral("#e8f0fe");
|
||||||
static QString cached_template_style_sheet;
|
const QString d_txt = is_dark ? QStringLiteral("#8d8d8d") : QStringLiteral("#a0a0a0");
|
||||||
if (cached_template_style_sheet.isEmpty()) {
|
|
||||||
cached_template_style_sheet = property("templateStyleSheet").toString();
|
static QString cached_template;
|
||||||
}
|
if (cached_template.isEmpty()) cached_template = property("templateStyleSheet").toString();
|
||||||
QString style_sheet = cached_template_style_sheet;
|
QString style_sheet = cached_template;
|
||||||
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%%"), accent);
|
||||||
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), accent_color_pressed);
|
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), Theme::GetAccentColorHover());
|
||||||
style_sheet.replace(QStringLiteral("%%BACKGROUND_COLOR%%"), bg_color);
|
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), Theme::GetAccentColorPressed());
|
||||||
style_sheet.replace(QStringLiteral("%%TEXT_COLOR%%"), text_color);
|
style_sheet.replace(QStringLiteral("%%BACKGROUND_COLOR%%"), bg);
|
||||||
style_sheet.replace(QStringLiteral("%%SECONDARY_BG_COLOR%%"), secondary_bg_color);
|
style_sheet.replace(QStringLiteral("%%TEXT_COLOR%%"), txt);
|
||||||
style_sheet.replace(QStringLiteral("%%TERTIARY_BG_COLOR%%"), tertiary_bg_color);
|
style_sheet.replace(QStringLiteral("%%SECONDARY_BG_COLOR%%"), sec);
|
||||||
style_sheet.replace(QStringLiteral("%%BUTTON_BG_COLOR%%"), button_bg_color);
|
style_sheet.replace(QStringLiteral("%%TERTIARY_BG_COLOR%%"), ter);
|
||||||
style_sheet.replace(QStringLiteral("%%HOVER_BG_COLOR%%"), hover_bg_color);
|
style_sheet.replace(QStringLiteral("%%BUTTON_BG_COLOR%%"), b_bg);
|
||||||
style_sheet.replace(QStringLiteral("%%FOCUS_BG_COLOR%%"), focus_bg_color);
|
style_sheet.replace(QStringLiteral("%%HOVER_BG_COLOR%%"), h_bg);
|
||||||
style_sheet.replace(QStringLiteral("%%DISABLED_TEXT_COLOR%%"), disabled_text_color);
|
style_sheet.replace(QStringLiteral("%%FOCUS_BG_COLOR%%"), f_bg);
|
||||||
|
style_sheet.replace(QStringLiteral("%%DISABLED_TEXT_COLOR%%"), d_txt);
|
||||||
|
|
||||||
|
style_sheet += QStringLiteral(
|
||||||
|
"QSlider::handle:horizontal { background-color: %1; }"
|
||||||
|
"QCheckBox::indicator:checked { background-color: %1; border-color: %1; }"
|
||||||
|
).arg(accent);
|
||||||
|
|
||||||
setStyleSheet(style_sheet);
|
setStyleSheet(style_sheet);
|
||||||
|
|
||||||
graphics_tab->SetTemplateStyleSheet(style_sheet);
|
graphics_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
system_tab->SetTemplateStyleSheet(style_sheet);
|
system_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
audio_tab->SetTemplateStyleSheet(style_sheet);
|
audio_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
cpu_tab->SetTemplateStyleSheet(style_sheet);
|
cpu_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
graphics_advanced_tab->SetTemplateStyleSheet(style_sheet);
|
graphics_advanced_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
|
|
||||||
|
if (is_rainbow) {
|
||||||
|
if (!rainbow_timer) {
|
||||||
|
rainbow_timer = new QTimer(this);
|
||||||
|
connect(rainbow_timer, &QTimer::timeout, this, [this] {
|
||||||
|
QString hue_hex = RainbowStyle::GetCurrentHighlightColor().name();
|
||||||
|
QString sidebar_css = QStringLiteral(
|
||||||
|
"QPushButton.tabButton { border: 2px solid transparent; }"
|
||||||
|
"QPushButton.tabButton:checked { color: %1; border: 2px solid %1; }"
|
||||||
|
"QPushButton.tabButton:hover { border: 2px solid %1; }"
|
||||||
|
"QPushButton.tabButton:pressed { background-color: %1; color: #ffffff; }"
|
||||||
|
).arg(hue_hex);
|
||||||
|
|
||||||
|
if (ui->topButtonWidget) ui->topButtonWidget->setStyleSheet(sidebar_css);
|
||||||
|
if (ui->horizontalNavWidget) ui->horizontalNavWidget->setStyleSheet(sidebar_css);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rainbow_timer->start(33);
|
||||||
|
} else if (rainbow_timer) {
|
||||||
|
rainbow_timer->stop();
|
||||||
|
if (ui->topButtonWidget) ui->topButtonWidget->setStyleSheet({});
|
||||||
|
if (ui->horizontalNavWidget) ui->horizontalNavWidget->setStyleSheet({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDialog::SetUIPositioning(const QString& positioning) {
|
void ConfigureDialog::SetUIPositioning(const QString& positioning) {
|
||||||
|
|||||||
@@ -91,6 +91,5 @@ private:
|
|||||||
std::unique_ptr<ConfigureWeb> web_tab;
|
std::unique_ptr<ConfigureWeb> web_tab;
|
||||||
std::unique_ptr<QButtonGroup> tab_button_group;
|
std::unique_ptr<QButtonGroup> tab_button_group;
|
||||||
std::vector<QPushButton*> tab_buttons;
|
std::vector<QPushButton*> tab_buttons;
|
||||||
QTimer* rainbow_timer;
|
QTimer* rainbow_timer{nullptr};
|
||||||
float rainbow_hue = 0.0f;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
#include "citron/configuration/configure_per_game_addons.h"
|
#include "citron/configuration/configure_per_game_addons.h"
|
||||||
#include "citron/configuration/configure_per_game_cheats.h"
|
#include "citron/configuration/configure_per_game_cheats.h"
|
||||||
#include "citron/configuration/configure_system.h"
|
#include "citron/configuration/configure_system.h"
|
||||||
|
#include "citron/util/rainbow_style.h"
|
||||||
#include "citron/theme.h"
|
#include "citron/theme.h"
|
||||||
#include "citron/uisettings.h"
|
#include "citron/uisettings.h"
|
||||||
#include "citron/util/util.h"
|
#include "citron/util/util.h"
|
||||||
@@ -100,8 +101,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
|
|||||||
: QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_},
|
: QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_},
|
||||||
file_name{file_name_}, system{system_},
|
file_name{file_name_}, system{system_},
|
||||||
builder{std::make_unique<ConfigurationShared::Builder>(this, !system_.IsPoweredOn())},
|
builder{std::make_unique<ConfigurationShared::Builder>(this, !system_.IsPoweredOn())},
|
||||||
tab_group{std::make_shared<std::vector<ConfigurationShared::Tab*>>()},
|
tab_group{std::make_shared<std::vector<ConfigurationShared::Tab*>>() } {
|
||||||
rainbow_timer{new QTimer(this)} {
|
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@@ -131,7 +131,6 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateTheme();
|
UpdateTheme();
|
||||||
connect(rainbow_timer, &QTimer::timeout, this, &ConfigurePerGame::UpdateTheme);
|
|
||||||
|
|
||||||
auto* animation_filter = new StyleAnimationEventFilter(this);
|
auto* animation_filter = new StyleAnimationEventFilter(this);
|
||||||
|
|
||||||
@@ -256,68 +255,69 @@ void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file_) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConfigurePerGame::UpdateTheme() {
|
void ConfigurePerGame::UpdateTheme() {
|
||||||
QString accent_color_str;
|
const bool is_rainbow = UISettings::values.enable_rainbow_mode.GetValue();
|
||||||
if (UISettings::values.enable_rainbow_mode.GetValue()) {
|
const QString accent = Theme::GetAccentColor();
|
||||||
rainbow_hue += 0.003f;
|
|
||||||
if (rainbow_hue > 1.0f) {
|
|
||||||
rainbow_hue = 0.0f;
|
|
||||||
}
|
|
||||||
QColor accent_color = QColor::fromHsvF(rainbow_hue, 0.8f, 1.0f);
|
|
||||||
accent_color_str = accent_color.name(QColor::HexRgb);
|
|
||||||
if (!rainbow_timer->isActive()) {
|
|
||||||
rainbow_timer->start(150);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (rainbow_timer->isActive()) {
|
|
||||||
rainbow_timer->stop();
|
|
||||||
}
|
|
||||||
accent_color_str = Theme::GetAccentColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
QColor accent_color(accent_color_str);
|
|
||||||
const QString accent_color_hover = accent_color.lighter(115).name(QColor::HexRgb);
|
|
||||||
const QString accent_color_pressed = accent_color.darker(120).name(QColor::HexRgb);
|
|
||||||
|
|
||||||
const bool is_dark = IsDarkMode();
|
const bool is_dark = IsDarkMode();
|
||||||
const QString bg_color = is_dark ? QStringLiteral("#2b2b2b") : QStringLiteral("#ffffff");
|
|
||||||
const QString text_color = is_dark ? QStringLiteral("#ffffff") : QStringLiteral("#000000");
|
|
||||||
const QString secondary_bg_color = is_dark ? QStringLiteral("#3d3d3d") : QStringLiteral("#f0f0f0");
|
|
||||||
const QString tertiary_bg_color = is_dark ? QStringLiteral("#5d5d5d") : QStringLiteral("#d3d3d3");
|
|
||||||
const QString button_bg_color = is_dark ? QStringLiteral("#383838") : QStringLiteral("#e1e1e1");
|
|
||||||
const QString hover_bg_color = is_dark ? QStringLiteral("#4d4d4d") : QStringLiteral("#e8f0fe");
|
|
||||||
const QString focus_bg_color = is_dark ? QStringLiteral("#404040") : QStringLiteral("#e8f0fe");
|
|
||||||
const QString disabled_text_color = is_dark ? QStringLiteral("#8d8d8d") : QStringLiteral("#a0a0a0");
|
|
||||||
|
|
||||||
static QString cached_template_style_sheet;
|
const QString bg = is_dark ? QStringLiteral("#2b2b2b") : QStringLiteral("#ffffff");
|
||||||
if (cached_template_style_sheet.isEmpty()) {
|
const QString txt = is_dark ? QStringLiteral("#ffffff") : QStringLiteral("#000000");
|
||||||
cached_template_style_sheet = property("templateStyleSheet").toString();
|
const QString sec = is_dark ? QStringLiteral("#3d3d3d") : QStringLiteral("#f0f0f0");
|
||||||
}
|
const QString ter = is_dark ? QStringLiteral("#5d5d5d") : QStringLiteral("#d3d3d3");
|
||||||
|
const QString b_bg = is_dark ? QStringLiteral("#383838") : QStringLiteral("#e1e1e1");
|
||||||
|
const QString h_bg = is_dark ? QStringLiteral("#4d4d4d") : QStringLiteral("#e8f0fe");
|
||||||
|
const QString f_bg = is_dark ? QStringLiteral("#404040") : QStringLiteral("#e8f0fe");
|
||||||
|
const QString d_txt = is_dark ? QStringLiteral("#8d8d8d") : QStringLiteral("#a0a0a0");
|
||||||
|
|
||||||
QString style_sheet = cached_template_style_sheet;
|
static QString cached_template;
|
||||||
|
if (cached_template.isEmpty()) cached_template = property("templateStyleSheet").toString();
|
||||||
|
QString style_sheet = cached_template;
|
||||||
|
|
||||||
// Replace accent colors (existing logic)
|
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR%%"), accent);
|
||||||
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR%%"), accent_color_str);
|
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), Theme::GetAccentColorHover());
|
||||||
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), accent_color_hover);
|
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), Theme::GetAccentColorPressed());
|
||||||
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), accent_color_pressed);
|
style_sheet.replace(QStringLiteral("%%BACKGROUND_COLOR%%"), bg);
|
||||||
|
style_sheet.replace(QStringLiteral("%%TEXT_COLOR%%"), txt);
|
||||||
|
style_sheet.replace(QStringLiteral("%%SECONDARY_BG_COLOR%%"), sec);
|
||||||
|
style_sheet.replace(QStringLiteral("%%TERTIARY_BG_COLOR%%"), ter);
|
||||||
|
style_sheet.replace(QStringLiteral("%%BUTTON_BG_COLOR%%"), b_bg);
|
||||||
|
style_sheet.replace(QStringLiteral("%%HOVER_BG_COLOR%%"), h_bg);
|
||||||
|
style_sheet.replace(QStringLiteral("%%FOCUS_BG_COLOR%%"), f_bg);
|
||||||
|
style_sheet.replace(QStringLiteral("%%DISABLED_TEXT_COLOR%%"), d_txt);
|
||||||
|
|
||||||
// Replace base theme colors (new logic)
|
style_sheet += QStringLiteral(
|
||||||
style_sheet.replace(QStringLiteral("%%BACKGROUND_COLOR%%"), bg_color);
|
"QSlider::handle:horizontal { background-color: %1; }"
|
||||||
style_sheet.replace(QStringLiteral("%%TEXT_COLOR%%"), text_color);
|
"QCheckBox::indicator:checked { background-color: %1; border-color: %1; }"
|
||||||
style_sheet.replace(QStringLiteral("%%SECONDARY_BG_COLOR%%"), secondary_bg_color);
|
"QToolButton { background-color: %1; color: #ffffff; border-radius: 4px; }"
|
||||||
style_sheet.replace(QStringLiteral("%%TERTIARY_BG_COLOR%%"), tertiary_bg_color);
|
).arg(accent);
|
||||||
style_sheet.replace(QStringLiteral("%%BUTTON_BG_COLOR%%"), button_bg_color);
|
|
||||||
style_sheet.replace(QStringLiteral("%%HOVER_BG_COLOR%%"), hover_bg_color);
|
|
||||||
style_sheet.replace(QStringLiteral("%%FOCUS_BG_COLOR%%"), focus_bg_color);
|
|
||||||
style_sheet.replace(QStringLiteral("%%DISABLED_TEXT_COLOR%%"), disabled_text_color);
|
|
||||||
|
|
||||||
setStyleSheet(style_sheet);
|
setStyleSheet(style_sheet);
|
||||||
|
|
||||||
// This part is crucial to pass the theme to child tabs
|
|
||||||
graphics_tab->SetTemplateStyleSheet(style_sheet);
|
graphics_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
system_tab->SetTemplateStyleSheet(style_sheet);
|
system_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
audio_tab->SetTemplateStyleSheet(style_sheet);
|
audio_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
cpu_tab->SetTemplateStyleSheet(style_sheet);
|
cpu_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
graphics_advanced_tab->SetTemplateStyleSheet(style_sheet);
|
graphics_advanced_tab->SetTemplateStyleSheet(style_sheet);
|
||||||
|
|
||||||
|
if (is_rainbow) {
|
||||||
|
if (!rainbow_timer) {
|
||||||
|
rainbow_timer = new QTimer(this);
|
||||||
|
connect(rainbow_timer, &QTimer::timeout, this, [this] {
|
||||||
|
QString hue_hex = RainbowStyle::GetCurrentHighlightColor().name();
|
||||||
|
QString button_css = QStringLiteral(
|
||||||
|
"QPushButton#aestheticTabButton { border: 2px solid transparent; }"
|
||||||
|
"QPushButton#aestheticTabButton:checked { color: %1; border: 2px solid %1; }"
|
||||||
|
"QPushButton#aestheticTabButton:hover { border: 2px solid %1; }"
|
||||||
|
"QPushButton#aestheticTabButton:pressed { background-color: %1; color: #ffffff; }"
|
||||||
|
).arg(hue_hex);
|
||||||
|
|
||||||
|
if (ui->tabButtonsContainer) ui->tabButtonsContainer->setStyleSheet(button_css);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rainbow_timer->start(33);
|
||||||
|
} else if (rainbow_timer) {
|
||||||
|
rainbow_timer->stop();
|
||||||
|
if (ui->tabButtonsContainer) ui->tabButtonsContainer->setStyleSheet({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigurePerGame::LoadConfiguration() {
|
void ConfigurePerGame::LoadConfiguration() {
|
||||||
|
|||||||
@@ -100,9 +100,7 @@ private:
|
|||||||
std::unique_ptr<ConfigureInputPerGame> input_tab;
|
std::unique_ptr<ConfigureInputPerGame> input_tab;
|
||||||
std::unique_ptr<ConfigureLinuxTab> linux_tab;
|
std::unique_ptr<ConfigureLinuxTab> linux_tab;
|
||||||
std::unique_ptr<ConfigureSystem> system_tab;
|
std::unique_ptr<ConfigureSystem> system_tab;
|
||||||
|
QTimer* rainbow_timer{nullptr};
|
||||||
QTimer* rainbow_timer;
|
|
||||||
float rainbow_hue = 0.0f;
|
|
||||||
|
|
||||||
QButtonGroup* button_group;
|
QButtonGroup* button_group;
|
||||||
QPixmap map;
|
QPixmap map;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@
|
|||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QCheckBox" name="rainbowModeCheckBox">
|
<widget class="QCheckBox" name="rainbowModeCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable Rainbow Mode</string>
|
<string>Enable Rainbow Tab Buttons</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
|||||||
#include "citron/main.h"
|
#include "citron/main.h"
|
||||||
#include "citron/play_time_manager.h"
|
#include "citron/play_time_manager.h"
|
||||||
#include "citron/startup_checks.h"
|
#include "citron/startup_checks.h"
|
||||||
|
#include "citron/util/rainbow_style.h"
|
||||||
#include "citron/uisettings.h"
|
#include "citron/uisettings.h"
|
||||||
#ifdef CITRON_USE_AUTO_UPDATER
|
#ifdef CITRON_USE_AUTO_UPDATER
|
||||||
#include "citron/updater/updater_dialog.h"
|
#include "citron/updater/updater_dialog.h"
|
||||||
@@ -6209,7 +6210,9 @@ int main(int argc, char* argv[]) {
|
|||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
|
|
||||||
GMainWindow main_window{std::move(config), has_broken_vulkan};
|
GMainWindow main_window{std::move(config), has_broken_vulkan};
|
||||||
// After settings have been loaded by GMainWindow, apply the filter
|
|
||||||
|
app.setStyle(new RainbowStyle(app.style()));
|
||||||
|
|
||||||
main_window.show();
|
main_window.show();
|
||||||
|
|
||||||
QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
|
QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
|
||||||
|
|||||||
38
src/citron/util/rainbow_style.cpp
Normal file
38
src/citron/util/rainbow_style.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 citron Emulator Project
|
||||||
|
|
||||||
|
#include "citron/util/rainbow_style.h"
|
||||||
|
#include "citron/uisettings.h"
|
||||||
|
#include "citron/theme.h"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
float RainbowStyle::s_hue = 0.0f;
|
||||||
|
|
||||||
|
RainbowStyle::RainbowStyle(QStyle* baseStyle) : QProxyStyle(baseStyle) {
|
||||||
|
m_timer = new QTimer(this);
|
||||||
|
connect(m_timer, &QTimer::timeout, this, &RainbowStyle::UpdateHue);
|
||||||
|
m_timer->start(33);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RainbowStyle::UpdateHue() {
|
||||||
|
if (UISettings::values.enable_rainbow_mode.GetValue()) {
|
||||||
|
s_hue += 0.005f;
|
||||||
|
if (s_hue > 1.0f) s_hue = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor RainbowStyle::GetCurrentHighlightColor() {
|
||||||
|
if (!UISettings::values.enable_rainbow_mode.GetValue()) {
|
||||||
|
return QColor(Theme::GetAccentColor());
|
||||||
|
}
|
||||||
|
return QColor::fromHsvF(s_hue, 0.7f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPalette RainbowStyle::standardPalette() const {
|
||||||
|
QPalette pal = QProxyStyle::standardPalette();
|
||||||
|
QColor highlight = GetCurrentHighlightColor();
|
||||||
|
pal.setColor(QPalette::Highlight, highlight);
|
||||||
|
pal.setColor(QPalette::Link, highlight);
|
||||||
|
return pal;
|
||||||
|
}
|
||||||
27
src/citron/util/rainbow_style.h
Normal file
27
src/citron/util/rainbow_style.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 citron Emulator Project
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QProxyStyle>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
class RainbowStyle : public QProxyStyle {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RainbowStyle(QStyle* baseStyle = nullptr);
|
||||||
|
|
||||||
|
// This intercepts palette requests from every widget in the app
|
||||||
|
QPalette standardPalette() const override;
|
||||||
|
|
||||||
|
// A helper for widgets that need the color directly
|
||||||
|
static QColor GetCurrentHighlightColor();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void UpdateHue();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer* m_timer;
|
||||||
|
static float s_hue;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user