Merge pull request 'feat(ui): Implement theme-aware overlays and fix UI color bugs' (#16) from fix/stylesheets-overlays-themes into main

Reviewed-on: https://git.citron-emu.org/Citron/Emulator/pulls/16
This commit is contained in:
Collecting
2025-11-02 04:48:14 +00:00
14 changed files with 277 additions and 172 deletions

View File

@@ -11,7 +11,7 @@ QPushButton#TogglableStatusBarButton {
} }
QPushButton#TogglableStatusBarButton:checked { QPushButton#TogglableStatusBarButton:checked {
color: #000000; color: palette(text); /* ADAPTIVE */
} }
QPushButton#TogglableStatusBarButton:hover { QPushButton#TogglableStatusBarButton:hover {
@@ -60,7 +60,7 @@ QPushButton#GPUStatusBarButton:!checked {
QPushButton#DockingStatusBarButton { QPushButton#DockingStatusBarButton {
min-width: 0px; min-width: 0px;
color: #000000; color: palette(text); /* ADAPTIVE */
border: 1px solid transparent; border: 1px solid transparent;
background-color: transparent; background-color: transparent;
padding: 0px 3px 0px 3px; padding: 0px 3px 0px 3px;
@@ -690,3 +690,30 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled { QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
image: url(:/overlay/osk_button_Y_disabled.png); image: url(:/overlay/osk_button_Y_disabled.png);
} }
/*
* Adaptive Dropdown Menu Styling
*/
QMenu {
background-color: palette(window);
color: palette(text);
border: 1px solid palette(midlight);
padding: 5px;
}
QMenu::item {
padding: 5px 25px;
border: 1px solid transparent;
}
QMenu::item:selected {
background-color: palette(highlight);
color: palette(highlighted-text);
}
QMenu::separator {
height: 1px;
background-color: palette(midlight);
margin: 4px;
}

View File

@@ -159,105 +159,63 @@ QRadioButton::indicator:unchecked:disabled {
QMenuBar { QMenuBar {
background-color: #31363b; background-color: #31363b;
color: #eff0f1; color: #eff0f1;
border-bottom: 1px solid #403F3F;
} }
QMenuBar::item { QMenuBar::item {
background: transparent; background: transparent;
padding: 4px 10px;
} }
QMenuBar::item:selected { QMenuBar::item:selected {
background: transparent; /* Hover state */
background: #18465d;
border: 1px solid #76797C; border: 1px solid #76797C;
} }
QMenuBar::item:pressed { QMenuBar::item:pressed {
/* When a menu is open */
border: 1px solid #18465d; border: 1px solid #18465d;
background-color: #3daee9; background-color: #3daee9;
color: #eff0f1; color: #eff0f1;
margin-bottom: -1px;
padding-bottom: 1px;
} }
QMenu { QMenu {
border: 1px solid #434242; border: 1px solid #434242;
padding: 2px; background-color: #31363b;
padding: 4px;
color: #eff0f1; color: #eff0f1;
} }
QMenu::icon {
margin: 5px;
}
QMenu::item { QMenu::item {
padding: 5px 16px 5px 40px; padding: 5px 25px 5px 25px;
border: 1px solid transparent; border: 1px solid transparent;
/* reserve space for selection border */
} }
QMenu::item:selected { QMenu::item:selected {
background-color: #3daee9; /* Use the theme's primary accent color */
color: #eff0f1; color: #eff0f1;
} }
QMenu::item:disabled { QMenu::item:disabled {
color: #54575B; color: #76797C;
} }
QMenu::item:disabled:hover, QMenu::separator {
QMenu::item:disabled:selected {
background-color: #393e43;
color: #666;
}
QMenu::separator,
QMenuBar::separator {
height: 1px; height: 1px;
background-color: #54575B; background-color: #54575B;
margin: 2px 4px 2px 40px; margin: 4px 8px;
} }
QMenu::indicator { QMenu::indicator {
margin: 0 -26px 0 8px;
width: 18px; width: 18px;
height: 18px; height: 18px;
} padding-left: 5px;
/* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */
QMenu::indicator:non-exclusive:unchecked {
image: url(:/qss_icons/rc/checkbox_unchecked.png);
}
QMenu::indicator:non-exclusive:unchecked:selected {
image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
}
QMenu::indicator:non-exclusive:checked {
image: url(:/qss_icons/rc/checkbox_checked.png);
}
QMenu::indicator:non-exclusive:checked:selected {
image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
}
/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
QMenu::indicator:exclusive:unchecked {
image: url(:/qss_icons/rc/radio_unchecked.png);
}
QMenu::indicator:exclusive:unchecked:selected {
image: url(:/qss_icons/rc/radio_unchecked_disabled.png);
}
QMenu::indicator:exclusive:checked {
image: url(:/qss_icons/rc/radio_checked.png);
}
QMenu::indicator:exclusive:checked:selected {
image: url(:/qss_icons/rc/radio_checked_disabled.png);
} }
QMenu::right-arrow { QMenu::right-arrow {
margin-right: 10px; margin: 0 5px 0 0;
image: url(:/qss_icons/rc/right_arrow.png) image: url(:/qss_icons/rc/right_arrow.png);
} }
QWidget:disabled { QWidget:disabled {

View File

@@ -367,106 +367,71 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar
--------------------------------------------------------------------------- */ --------------------------------------------------------------------------- */
QMenuBar { QMenuBar {
background-color: #32414B; background-color: #31363b;
color: #F0F0F0; color: #eff0f1; /* Sets the default text color to be light */
border-bottom: 1px solid #403F3F;
} }
QMenuBar::item { QMenuBar::item {
background: transparent; background: transparent;
padding: 4px 10px;
color: #eff0f1; /* Explicitly set item text color */
} }
QMenuBar::item:selected { QMenuBar::item:selected {
background: transparent; /* This is the hover state */
border: 0px solid #32414B; background-color: #18465d;
color: #eff0f1;
} }
QMenuBar::item:pressed { QMenuBar::item:pressed {
border: 0px solid #32414B; /* This is for when a menu is open */
background-color: #148CD2; border: 1px solid #18465d;
color: #F0F0F0; background-color: #3daee9; /* Use the theme's accent blue */
margin-bottom: 0px; color: #eff0f1;
padding-bottom: 0px;
} }
/* QMenu ------------------------------------------------------------------ /* QMenu ------------------------------------------------------------------
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu
--------------------------------------------------------------------------- */ --------------------------------------------------------------------------- */
QMenu { QMenu {
border: 0px solid #32414B; border: 1px solid #434242;
color: #F0F0F0; background-color: #31363b;
margin: 0px; padding: 4px;
} color: #eff0f1; /* Set default text color for menu items */
QMenu::separator {
height: 1px;
background-color: #505F69;
color: #F0F0F0;
}
QMenu::icon {
margin: 0px;
padding-left: 8px;
} }
QMenu::item { QMenu::item {
background-color: #32414B; padding: 5px 25px 5px 25px;
padding: 4px 24px 4px 24px; border: 1px solid transparent;
/* Reserve space for selection border */
border: 1px transparent #32414B;
} }
QMenu::item:selected { QMenu::item:selected {
color: #F0F0F0; background-color: #3daee9; /* Use the theme's accent blue for selection */
color: #eff0f1;
}
QMenu::item:disabled {
color: #76797C;
}
QMenu::separator {
height: 1px;
background-color: #54575B;
margin: 4px 8px;
} }
QMenu::indicator { QMenu::indicator {
width: 12px; width: 18px;
height: 12px; height: 18px;
padding-left: 6px; padding-left: 5px;
/* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */
/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
}
QMenu::indicator:non-exclusive:unchecked {
image: url(":/qss_icons/rc/checkbox_unchecked.png");
}
QMenu::indicator:non-exclusive:unchecked:selected {
image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png");
}
QMenu::indicator:non-exclusive:checked {
image: url(":/qss_icons/rc/checkbox_checked.png");
}
QMenu::indicator:non-exclusive:checked:selected {
image: url(":/qss_icons/rc/checkbox_checked_disabled.png");
}
QMenu::indicator:exclusive:unchecked {
image: url(":/qss_icons/rc/radio_unchecked.png");
}
QMenu::indicator:exclusive:unchecked:selected {
image: url(":/qss_icons/rc/radio_unchecked_disabled.png");
}
QMenu::indicator:exclusive:checked {
image: url(":/qss_icons/rc/radio_checked.png");
}
QMenu::indicator:exclusive:checked:selected {
image: url(":/qss_icons/rc/radio_checked_disabled.png");
} }
QMenu::right-arrow { QMenu::right-arrow {
margin: 5px; margin: 0 5px 0 0;
image: url(":/qss_icons/rc/arrow_right.png"); image: url(:/qss_icons/rc/right_arrow.png);
height: 12px;
width: 12px;
} }
/* QAbstractItemView ------------------------------------------------------ /* QAbstractItemView ------------------------------------------------------

View File

@@ -5800,7 +5800,11 @@ void GMainWindow::UpdateUITheme() {
UISettings::values.theme); UISettings::values.theme);
qApp->setStyleSheet({}); qApp->setStyleSheet({});
setStyleSheet({}); setStyleSheet({});
} }
emit themeChanged();
} }
void GMainWindow::LoadTranslation() { void GMainWindow::LoadTranslation() {

View File

@@ -116,6 +116,7 @@ signals:
void EmulationStarting(EmuThread* emu_thread); void EmulationStarting(EmuThread* emu_thread);
void EmulationStopping(); void EmulationStopping();
void UpdateThemedIcons(); void UpdateThemedIcons();
void themeChanged();
void UpdateInstallProgress(); void UpdateInstallProgress();
void AmiiboSettingsFinished(bool is_success, const std::string& name); void AmiiboSettingsFinished(bool is_success, const std::string& name);
void ControllerSelectorReconfigureFinished(bool is_success); void ControllerSelectorReconfigureFinished(bool is_success);

View File

@@ -21,6 +21,8 @@
#include "citron/game_list_p.h" #include "citron/game_list_p.h"
#include "citron/multiplayer/chat_room.h" #include "citron/multiplayer/chat_room.h"
#include "citron/multiplayer/message.h" #include "citron/multiplayer/message.h"
#include "citron/uisettings.h"
#include "citron/theme.h"
#ifdef ENABLE_WEB_SERVICE #ifdef ENABLE_WEB_SERVICE
#include "web_service/web_backend.h" #include "web_service/web_backend.h"
#endif #endif
@@ -198,6 +200,8 @@ ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::C
connect(ui->chat_message, &QLineEdit::returnPressed, this, &ChatRoom::OnSendChat); connect(ui->chat_message, &QLineEdit::returnPressed, this, &ChatRoom::OnSendChat);
connect(ui->chat_message, &QLineEdit::textChanged, this, &ChatRoom::OnChatTextChanged); connect(ui->chat_message, &QLineEdit::textChanged, this, &ChatRoom::OnChatTextChanged);
connect(ui->send_message, &QPushButton::clicked, this, &ChatRoom::OnSendChat); connect(ui->send_message, &QPushButton::clicked, this, &ChatRoom::OnSendChat);
UpdateTheme();
} }
ChatRoom::~ChatRoom() = default; ChatRoom::~ChatRoom() = default;
@@ -506,3 +510,61 @@ void ChatRoom::PopupContextMenu(const QPoint& menu_location) {
context_menu.exec(ui->player_view->viewport()->mapToGlobal(menu_location)); context_menu.exec(ui->player_view->viewport()->mapToGlobal(menu_location));
} }
void ChatRoom::UpdateTheme() {
QString style_sheet;
const QString accent_color = Theme::GetAccentColor();
if (UISettings::IsDarkTheme()) {
style_sheet = QStringLiteral(R"(
QListView, QTextEdit, QLineEdit {
background-color: #252525;
color: #E0E0E0;
border: 1px solid #4A4A4A;
border-radius: 4px;
}
QListView::item:selected {
background-color: %1;
}
QPushButton {
background-color: #3E3E3E;
color: #E0E0E0;
border: 1px solid #5A5A5A;
padding: 5px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #4A4A4A;
}
QPushButton:pressed {
background-color: #555555;
}
)").arg(accent_color);
} else {
style_sheet = QStringLiteral(R"(
QListView, QTextEdit, QLineEdit {
background-color: #FFFFFF;
color: #000000;
border: 1px solid #CFCFCF;
border-radius: 4px;
}
QListView::item:selected {
background-color: %1;
}
QPushButton {
background-color: #F0F0F0;
color: #000000;
border: 1px solid #BDBDBD;
padding: 5px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #E0E0E0;
}
QPushButton:pressed {
background-color: #D0D0D0;
}
)").arg(accent_color);
}
this->setStyleSheet(style_sheet);
}

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -49,6 +50,7 @@ public slots:
void PopupContextMenu(const QPoint& menu_location); void PopupContextMenu(const QPoint& menu_location);
void Disable(); void Disable();
void Enable(); void Enable();
void UpdateTheme();
signals: signals:
void ChatReceived(const Network::ChatEntry&); void ChatReceived(const Network::ChatEntry&);

View File

@@ -2,6 +2,8 @@
// SPDX-FileCopyrightText: 2025 citron Emulator Project // SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <QApplication>
#include <QPalette>
#include <QSettings> #include <QSettings>
#include "common/fs/fs.h" #include "common/fs/fs.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
@@ -33,34 +35,50 @@ namespace UISettings {
}}; }};
bool IsDarkTheme() { bool IsDarkTheme() {
const auto& theme = UISettings::values.theme; const auto& theme_name = 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"); // Priority 1: Check for explicitly chosen dark themes.
if (theme_name == "qdarkstyle" || theme_name == "colorful_dark" ||
theme_name == "qdarkstyle_midnight_blue" || theme_name == "colorful_midnight_blue") {
return true;
}
// Priority 2: Check for adaptive themes ("default" and "colorful").
if (theme_name == "default" || theme_name == "colorful") {
const QPalette palette = qApp->palette();
const QColor text_color = palette.color(QPalette::WindowText);
const QColor base_color = palette.color(QPalette::Window);
return text_color.value() > base_color.value();
}
// Fallback for any other unknown themes is to assume they are light.
return false;
} }
Values values = {}; Values values = {};
// definition for the function.
u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
switch (ratio) { switch (ratio) {
case Settings::AspectRatio::R4_3: case Settings::AspectRatio::R4_3:
return height * 4 / 3; return height * 4 / 3;
case Settings::AspectRatio::R21_9: case Settings::AspectRatio::R21_9:
return height * 21 / 9; return height * 21 / 9;
case Settings::AspectRatio::R16_10: case Settings::AspectRatio::R16_10:
return height * 16 / 10; return height * 16 / 10;
case Settings::AspectRatio::R32_9: case Settings::AspectRatio::R32_9:
return height * 32 / 9; return height * 32 / 9;
case Settings::AspectRatio::R16_9: case Settings::AspectRatio::R16_9:
case Settings::AspectRatio::Stretch: case Settings::AspectRatio::Stretch:
// TODO: Move this function wherever appropriate to implement Stretched aspect // TODO: Move this function wherever appropriate to implement Stretched aspect
break; break;
} }
return height * 16 / 9; return height * 16 / 9;
} }
void SaveWindowState() { void SaveWindowState() {
const auto window_state_config_loc = const auto window_state_config_loc =
FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "window_state.ini"); FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "window_state.ini");
void(FS::CreateParentDir(window_state_config_loc)); void(FS::CreateParentDir(window_state_config_loc));
QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
@@ -78,12 +96,12 @@ namespace UISettings {
void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) { void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) {
const auto window_state_config_loc = const auto window_state_config_loc =
FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "window_state.ini"); FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "window_state.ini");
// Migrate window state from old location // Migrate window state from old location
if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) { if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) {
const auto config_loc = const auto config_loc =
FS::PathToUTF8String(FS::GetCitronPath(FS::CitronPath::ConfigDir) / "qt-config.ini"); 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("UI"));
@@ -91,11 +109,11 @@ namespace UISettings {
values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
values.state = config.value(QStringLiteral("state")).toByteArray(); values.state = config.value(QStringLiteral("state")).toByteArray();
values.renderwindow_geometry = values.renderwindow_geometry =
config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
values.gamelist_header_state = values.gamelist_header_state =
config.value(QStringLiteral("gameListHeaderState")).toByteArray(); config.value(QStringLiteral("gameListHeaderState")).toByteArray();
values.microprofile_geometry = values.microprofile_geometry =
config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
config.endGroup(); config.endGroup();
config.endGroup(); config.endGroup();
return; return;
@@ -107,15 +125,15 @@ namespace UISettings {
values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
values.state = config.value(QStringLiteral("state")).toByteArray(); values.state = config.value(QStringLiteral("state")).toByteArray();
values.renderwindow_geometry = values.renderwindow_geometry =
config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
values.configure_dialog_geometry = values.configure_dialog_geometry =
config.value(QStringLiteral("configureDialogGeometry")).toByteArray(); config.value(QStringLiteral("configureDialogGeometry")).toByteArray();
values.per_game_configure_geometry = values.per_game_configure_geometry =
config.value(QStringLiteral("perGameConfigureGeometry")).toByteArray(); config.value(QStringLiteral("perGameConfigureGeometry")).toByteArray();
values.gamelist_header_state = values.gamelist_header_state =
config.value(QStringLiteral("gameListHeaderState")).toByteArray(); config.value(QStringLiteral("gameListHeaderState")).toByteArray();
values.microprofile_geometry = values.microprofile_geometry =
config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
} }
} // namespace UISettings } // namespace UISettings

View File

@@ -16,6 +16,7 @@
#include "citron/util/multiplayer_room_overlay.h" #include "citron/util/multiplayer_room_overlay.h"
#include "network/network.h" #include "network/network.h"
#include "network/room.h" #include "network/room.h"
#include "citron/uisettings.h"
MultiplayerRoomOverlay::MultiplayerRoomOverlay(GMainWindow* parent) MultiplayerRoomOverlay::MultiplayerRoomOverlay(GMainWindow* parent)
: QWidget(parent), main_window(parent) { : QWidget(parent), main_window(parent) {
@@ -24,9 +25,6 @@ MultiplayerRoomOverlay::MultiplayerRoomOverlay(GMainWindow* parent)
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
background_color = QColor(20, 20, 20, 180);
border_color = QColor(60, 60, 60, 120);
main_layout = new QGridLayout(this); main_layout = new QGridLayout(this);
main_layout->setContentsMargins(padding, padding, 0, 0); main_layout->setContentsMargins(padding, padding, 0, 0);
main_layout->setSpacing(6); main_layout->setSpacing(6);
@@ -36,7 +34,6 @@ MultiplayerRoomOverlay::MultiplayerRoomOverlay(GMainWindow* parent)
size_grip = new QSizeGrip(this); size_grip = new QSizeGrip(this);
players_online_label->setFont(QFont(QString::fromUtf8("Segoe UI"), 10, QFont::Bold)); players_online_label->setFont(QFont(QString::fromUtf8("Segoe UI"), 10, QFont::Bold));
players_online_label->setStyleSheet(QString::fromUtf8("color: #E0E0E0;"));
players_online_label->setText(QString::fromUtf8("Players Online: 0")); players_online_label->setText(QString::fromUtf8("Players Online: 0"));
players_online_label->setAttribute(Qt::WA_TransparentForMouseEvents, true); players_online_label->setAttribute(Qt::WA_TransparentForMouseEvents, true);
@@ -61,6 +58,9 @@ MultiplayerRoomOverlay::MultiplayerRoomOverlay(GMainWindow* parent)
update_timer.setSingleShot(false); update_timer.setSingleShot(false);
connect(&update_timer, &QTimer::timeout, this, &MultiplayerRoomOverlay::UpdateRoomData); connect(&update_timer, &QTimer::timeout, this, &MultiplayerRoomOverlay::UpdateRoomData);
connect(parent, &GMainWindow::themeChanged, this, &MultiplayerRoomOverlay::UpdateTheme);
UpdateTheme();
setMinimumSize(280, 220); setMinimumSize(280, 220);
resize(320, 280); resize(320, 280);
UpdatePosition(); UpdatePosition();
@@ -247,3 +247,24 @@ void MultiplayerRoomOverlay::UpdatePosition() {
move(main_window_pos.x() + main_window->width() - this->width() - 10, main_window_pos.y() + 10); move(main_window_pos.x() + main_window->width() - this->width() - 10, main_window_pos.y() + 10);
} }
} }
void MultiplayerRoomOverlay::UpdateTheme() {
if (UISettings::IsDarkTheme()) {
// Dark Theme Colors
background_color = QColor(20, 20, 20, 180); // 180 alpha for transparency
border_color = QColor(60, 60, 60, 120);
players_online_label->setStyleSheet(QStringLiteral("color: #E0E0E0;"));
} else {
// Light Theme Colors
background_color = QColor(245, 245, 245, 200); // 200 alpha for transparency
border_color = QColor(200, 200, 200, 120);
players_online_label->setStyleSheet(QStringLiteral("color: #141414;"));
}
// The chat widget is a separate custom widget, so we need to tell it to update its theme too.
if (chat_room_widget) {
chat_room_widget->UpdateTheme();
}
update(); // Force a repaint of the overlay itself
}

View File

@@ -13,6 +13,7 @@
#include "citron/multiplayer/state.h" #include "citron/multiplayer/state.h"
#include "citron/multiplayer/chat_room.h" #include "citron/multiplayer/chat_room.h"
#include "citron/uisettings.h"
class GMainWindow; class GMainWindow;
class QSizeGrip; class QSizeGrip;
@@ -31,6 +32,7 @@ public slots:
// These slots are connected to the main window to prevent crashes. // These slots are connected to the main window to prevent crashes.
void OnEmulationStarting(); void OnEmulationStarting();
void OnEmulationStopping(); void OnEmulationStopping();
void UpdateTheme();
protected: protected:
void paintEvent(QPaintEvent* event) override; void paintEvent(QPaintEvent* event) override;

View File

@@ -31,6 +31,7 @@
#include "citron/main.h" #include "citron/main.h"
#include "citron/util/performance_overlay.h" #include "citron/util/performance_overlay.h"
#include "citron/uisettings.h"
#include "core/core.h" #include "core/core.h"
#include "core/perf_stats.h" #include "core/perf_stats.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
@@ -48,11 +49,6 @@ PerformanceOverlay::PerformanceOverlay(GMainWindow* parent)
value_font = QFont(QString::fromUtf8("Segoe UI"), 11, QFont::Bold); value_font = QFont(QString::fromUtf8("Segoe UI"), 11, QFont::Bold);
small_font = QFont(QString::fromUtf8("Segoe UI"), 8, QFont::Normal); small_font = QFont(QString::fromUtf8("Segoe UI"), 8, QFont::Normal);
// Initialize colors with a more modern palette
background_color = QColor(20, 20, 20, 180); // Darker, more opaque background
border_color = QColor(60, 60, 60, 120); // Subtle border
text_color = QColor(220, 220, 220, 255); // Light gray text
fps_color = QColor(76, 175, 80, 255); // Material Design green
temperature_color = QColor(76, 175, 80, 255); // Default to green temperature_color = QColor(76, 175, 80, 255); // Default to green
// Graph colors // Graph colors
@@ -64,6 +60,11 @@ PerformanceOverlay::PerformanceOverlay(GMainWindow* parent)
update_timer.setSingleShot(false); update_timer.setSingleShot(false);
connect(&update_timer, &QTimer::timeout, this, &PerformanceOverlay::UpdatePerformanceStats); connect(&update_timer, &QTimer::timeout, this, &PerformanceOverlay::UpdatePerformanceStats);
// Connect to the main window's theme change signal
connect(parent, &GMainWindow::themeChanged, this, &PerformanceOverlay::UpdateTheme);
// Set the initial theme colors
UpdateTheme();
// Set initial size - larger to accommodate the graph // Set initial size - larger to accommodate the graph
resize(220, 180); resize(220, 180);
@@ -556,3 +557,20 @@ QString PerformanceOverlay::FormatFrameTime(double frame_time_ms) const {
} }
return QString::number(frame_time_ms, 'f', 2); return QString::number(frame_time_ms, 'f', 2);
} }
void PerformanceOverlay::UpdateTheme() {
if (UISettings::IsDarkTheme()) {
// Dark Theme Colors (your original values)
background_color = QColor(20, 20, 20, 200); // Slightly more opaque
border_color = QColor(60, 60, 60, 120);
text_color = QColor(220, 220, 220, 255);
graph_background_color = QColor(40, 40, 40, 100);
} else {
// Light Theme Colors
background_color = QColor(245, 245, 245, 220);
border_color = QColor(200, 200, 200, 120);
text_color = QColor(20, 20, 20, 255);
graph_background_color = QColor(220, 220, 220, 100);
}
update(); // Force a repaint with the new colors
}

View File

@@ -12,6 +12,7 @@
#include <QColor> #include <QColor>
#include <memory> #include <memory>
#include <deque> #include <deque>
#include "citron/uisettings.h"
class GMainWindow; class GMainWindow;
@@ -25,6 +26,9 @@ public:
void SetVisible(bool visible); void SetVisible(bool visible);
bool IsVisible() const { return is_visible; } bool IsVisible() const { return is_visible; }
public slots:
void UpdateTheme();
protected: protected:
void paintEvent(QPaintEvent* event) override; void paintEvent(QPaintEvent* event) override;
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;

View File

@@ -17,6 +17,7 @@
#include "citron/main.h" #include "citron/main.h"
#include "citron/util/vram_overlay.h" #include "citron/util/vram_overlay.h"
#include "citron/uisettings.h"
#include "core/core.h" #include "core/core.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
@@ -37,12 +38,6 @@ VramOverlay::VramOverlay(GMainWindow* parent)
small_font = QFont(QString::fromUtf8("Segoe UI"), 9, QFont::Normal); small_font = QFont(QString::fromUtf8("Segoe UI"), 9, QFont::Normal);
warning_font = QFont(QString::fromUtf8("Segoe UI"), 10, QFont::Bold); warning_font = QFont(QString::fromUtf8("Segoe UI"), 10, QFont::Bold);
// Modern dark theme colors
background_color = QColor(15, 15, 15, 220);
border_color = QColor(45, 45, 45, 255);
text_color = QColor(240, 240, 240, 255);
secondary_text_color = QColor(180, 180, 180, 255);
// VRAM usage colors - modern palette // VRAM usage colors - modern palette
vram_safe_color = QColor(76, 175, 80, 255); vram_safe_color = QColor(76, 175, 80, 255);
vram_warning_color = QColor(255, 193, 7, 255); vram_warning_color = QColor(255, 193, 7, 255);
@@ -59,6 +54,9 @@ VramOverlay::VramOverlay(GMainWindow* parent)
update_timer.setSingleShot(false); update_timer.setSingleShot(false);
connect(&update_timer, &QTimer::timeout, this, &VramOverlay::UpdateVramStats); connect(&update_timer, &QTimer::timeout, this, &VramOverlay::UpdateVramStats);
connect(parent, &GMainWindow::themeChanged, this, &VramOverlay::UpdateTheme);
UpdateTheme();
// Set clean, compact size // Set clean, compact size
resize(250, 180); resize(250, 180);
@@ -322,3 +320,24 @@ void VramOverlay::AddVramUsage(double percentage) {
max_vram_usage = std::min(100.0, max_vram_usage + range * 0.1); max_vram_usage = std::min(100.0, max_vram_usage + range * 0.1);
} }
} }
void VramOverlay::UpdateTheme() {
if (UISettings::IsDarkTheme()) {
// Dark Theme Colors (your original values)
background_color = QColor(15, 15, 15, 220);
border_color = QColor(45, 45, 45, 255);
text_color = QColor(240, 240, 240, 255);
secondary_text_color = QColor(180, 180, 180, 255);
graph_background_color = QColor(25, 25, 25, 255);
graph_grid_color = QColor(60, 60, 60, 100);
} else {
// Light Theme Colors
background_color = QColor(245, 245, 245, 220);
border_color = QColor(200, 200, 200, 255);
text_color = QColor(20, 20, 20, 255);
secondary_text_color = QColor(80, 80, 80, 255);
graph_background_color = QColor(225, 225, 225, 255);
graph_grid_color = QColor(190, 190, 190, 100);
}
update(); // Force a repaint
}

View File

@@ -12,6 +12,7 @@
#include <QColor> #include <QColor>
#include <memory> #include <memory>
#include <deque> #include <deque>
#include "citron/uisettings.h"
class GMainWindow; class GMainWindow;
@@ -38,6 +39,9 @@ public:
void SetVisible(bool visible); void SetVisible(bool visible);
bool IsVisible() const { return is_visible; } bool IsVisible() const { return is_visible; }
public slots:
void UpdateTheme();
protected: protected:
void paintEvent(QPaintEvent* event) override; void paintEvent(QPaintEvent* event) override;
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;