mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 10:43:33 +00:00
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:
31
dist/qt_themes/default/style.qss
vendored
31
dist/qt_themes/default/style.qss
vendored
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
72
dist/qt_themes/qdarkstyle/style.qss
vendored
72
dist/qt_themes/qdarkstyle/style.qss
vendored
@@ -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 {
|
||||||
|
|||||||
107
dist/qt_themes/qdarkstyle_midnight_blue/style.qss
vendored
107
dist/qt_themes/qdarkstyle_midnight_blue/style.qss
vendored
@@ -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 ------------------------------------------------------
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -246,4 +246,25 @@ void MultiplayerRoomOverlay::UpdatePosition() {
|
|||||||
QPoint main_window_pos = main_window->mapToGlobal(QPoint(0, 0));
|
QPoint main_window_pos = main_window->mapToGlobal(QPoint(0, 0));
|
||||||
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user