Skip to content

Commit 4b94557

Browse files
committed
initial implementation of runtime theme switching
1 parent de60a20 commit 4b94557

File tree

4 files changed

+165
-12
lines changed

4 files changed

+165
-12
lines changed

gui/qt/mainwindow.cpp

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include <QtCore/QRegularExpression>
2828
#include <QtCore/QTemporaryFile>
2929
#include <QtGui/QFont>
30+
#include <QtGui/QPalette>
31+
#include <QtGui/QColor>
3032
#include <QtGui/QWindow>
3133
#include <QtGui/QDesktopServices>
3234
#include <QtGui/QClipboard>
@@ -37,11 +39,40 @@
3739
#include <QtWidgets/QComboBox>
3840
#include <QtWidgets/QScrollBar>
3941
#include <QtWidgets/QMessageBox>
42+
#include <QtWidgets/QStyle>
43+
#include <QtWidgets/QStyleFactory>
4044
#include <QtNetwork/QNetworkReply>
45+
#include <QtCore/QSignalBlocker>
46+
#include <QtCore/QScopedValueRollback>
4147
#include <fstream>
4248
#include <iostream>
4349
#include <cmath>
4450

51+
namespace {
52+
QPalette createFusionDarkPalette(const QPalette &base) {
53+
QPalette palette = base;
54+
palette.setColor(QPalette::Window, QColor(53, 53, 53));
55+
palette.setColor(QPalette::WindowText, Qt::white);
56+
palette.setColor(QPalette::Base, QColor(25, 25, 25));
57+
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
58+
palette.setColor(QPalette::ToolTipBase, Qt::white);
59+
palette.setColor(QPalette::ToolTipText, Qt::white);
60+
palette.setColor(QPalette::Text, Qt::white);
61+
palette.setColor(QPalette::Button, QColor(53, 53, 53));
62+
palette.setColor(QPalette::ButtonText, Qt::white);
63+
palette.setColor(QPalette::BrightText, Qt::red);
64+
palette.setColor(QPalette::Link, QColor(42, 130, 218));
65+
palette.setColor(QPalette::Highlight, QColor(76, 163, 224));
66+
palette.setColor(QPalette::HighlightedText, Qt::black);
67+
68+
static constexpr QColor disabledColor(127, 127, 127);
69+
palette.setColor(QPalette::Disabled, QPalette::Text, disabledColor);
70+
palette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor);
71+
palette.setColor(QPalette::PlaceholderText, disabledColor);
72+
return palette;
73+
}
74+
}
75+
4576
#ifdef Q_OS_MACOS
4677
# include "os/mac/kdmactouchbar.h"
4778
#endif
@@ -71,8 +102,30 @@ MainWindow::MainWindow(CEmuOpts &cliOpts, QWidget *p) : QMainWindow(p), ui(new U
71102

72103
ui->setupUi(this);
73104

74-
m_styleForMode[0] = m_styleForMode[1] = QApplication::style()->name();
75-
darkModeSwitch(isSystemInDarkMode());
105+
m_styleForMode[0] = QApplication::style()->objectName();
106+
if (m_styleForMode[0].isEmpty()) {
107+
m_styleForMode[0] = QApplication::style()->name();
108+
}
109+
if (m_styleForMode[0].isEmpty()) {
110+
m_styleForMode[0] = QStringLiteral("fusion");
111+
}
112+
m_styleForMode[1] = QStringLiteral("fusion");
113+
114+
if (const QStyle *fusionStyle = QStyleFactory::create(QStringLiteral("Fusion"))) {
115+
m_fusionLightPalette = fusionStyle->standardPalette();
116+
delete fusionStyle;
117+
} else {
118+
m_fusionLightPalette = QApplication::style()->standardPalette();
119+
}
120+
m_fusionDarkPalette = createFusionDarkPalette(m_fusionLightPalette);
121+
122+
{
123+
QSignalBlocker blocker(ui->comboTheme);
124+
ui->comboTheme->setCurrentIndex(static_cast<int>(m_themePreference));
125+
}
126+
connect(ui->comboTheme, &QComboBox::currentIndexChanged, this, &MainWindow::setThemePreference);
127+
128+
applyThemeFromPreference();
76129

77130
setStyleSheet(QStringLiteral("QMainWindow::separator{ width: 0px; height: 0px; }"));
78131

@@ -598,6 +651,7 @@ MainWindow::MainWindow(CEmuOpts &cliOpts, QWidget *p) : QMainWindow(p), ui(new U
598651
}
599652

600653
setAutoUpdates(m_config->value(SETTING_AUTOUPDATE, CEMU_RELEASE).toBool());
654+
setThemePreference(m_config->value(SETTING_UI_THEME, static_cast<int>(ThemePreference::System)).toInt());
601655
checkVersion();
602656

603657
#ifdef Q_OS_WIN
@@ -1130,14 +1184,40 @@ void MainWindow::translateExtras(int init) {
11301184
}
11311185
}
11321186

1133-
void MainWindow::darkModeSwitch(bool darkMode) {
1134-
QApplication::setStyle(m_styleForMode[darkMode]);
1135-
if (darkMode != isRunningInDarkMode()) {
1136-
m_styleForMode[darkMode] = QStringLiteral("fusion");
1137-
QApplication::setStyle(m_styleForMode[darkMode]);
1138-
darkMode = isRunningInDarkMode();
1187+
static void repolishAfterThemeChanged() {
1188+
const auto widgets = QApplication::allWidgets();
1189+
for (QWidget *w : widgets) {
1190+
if (QStyle *st = w->style()) {
1191+
st->unpolish(w);
1192+
st->polish(w);
1193+
}
1194+
w->update();
1195+
}
1196+
}
1197+
1198+
void MainWindow::applyThemeFromPreference() {
1199+
switch (m_themePreference) {
1200+
case ThemePreference::System:
1201+
QApplication::setStyle(m_styleForMode[0]);
1202+
QApplication::setPalette(QApplication::style()->standardPalette());
1203+
break;
1204+
case ThemePreference::Light:
1205+
QApplication::setStyle(m_styleForMode[1]);
1206+
QApplication::setPalette(m_fusionLightPalette);
1207+
break;
1208+
case ThemePreference::Dark:
1209+
QApplication::setStyle(m_styleForMode[1]);
1210+
QApplication::setPalette(m_fusionDarkPalette);
1211+
break;
11391212
}
11401213

1214+
const bool dark = m_themePreference == ThemePreference::Dark || (m_themePreference == ThemePreference::System && isSystemInDarkMode());
1215+
darkModeSwitch(dark);
1216+
1217+
repolishAfterThemeChanged();
1218+
}
1219+
1220+
void MainWindow::darkModeSwitch(bool darkMode) {
11411221
m_isInDarkMode = darkMode;
11421222
if (darkMode) {
11431223
m_cBack.setColor(QPalette::Base, QColor(Qt::blue).lighter(180));
@@ -1162,13 +1242,27 @@ void MainWindow::changeEvent(QEvent* event) {
11621242
}
11631243
QMainWindow::changeEvent(event);
11641244
if (eventType == QEvent::ThemeChange) {
1165-
bool darkMode = isSystemInDarkMode();
1166-
if (darkMode != m_isInDarkMode) {
1167-
darkModeSwitch(darkMode);
1168-
}
1245+
applyThemeFromPreference();
11691246
}
11701247
}
11711248

1249+
void MainWindow::setThemePreference(int index) {
1250+
const auto pref = static_cast<ThemePreference>(index);
1251+
1252+
if (ui && ui->comboTheme && ui->comboTheme->currentIndex() != index) {
1253+
QSignalBlocker blocker(ui->comboTheme);
1254+
ui->comboTheme->setCurrentIndex(index);
1255+
}
1256+
1257+
m_themePreference = pref;
1258+
1259+
if (m_config && opts.useSettings) {
1260+
m_config->setValue(SETTING_UI_THEME, index);
1261+
}
1262+
1263+
applyThemeFromPreference();
1264+
}
1265+
11721266
void MainWindow::showEvent(QShowEvent *e) {
11731267
if (!m_setup) {
11741268
e->ignore();
@@ -1486,6 +1580,7 @@ void MainWindow::resetGui() {
14861580
m_config->remove(SETTING_WINDOW_STATUSBAR);
14871581
m_config->remove(SETTING_WINDOW_SEPARATOR);
14881582
m_config->remove(SETTING_UI_EDIT_MODE);
1583+
m_config->remove(SETTING_UI_THEME);
14891584
m_needReload = true;
14901585
close();
14911586
}

gui/qt/mainwindow.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <QtCore/QTimer>
2929
#include <QtCore/QPointer>
3030
#include <QtGui/QShortcut>
31+
#include <QtGui/QPalette>
3132
#include <QtGui/QTextCursor>
3233
#include <QtCore/QTranslator>
3334
#include <QtCore/QStandardPaths>
@@ -38,6 +39,9 @@
3839
QT_BEGIN_NAMESPACE
3940
class QButtonGroup;
4041
class QLocale;
42+
class QEvent;
43+
class QCloseEvent;
44+
class QObject;
4145
QT_END_NAMESPACE
4246

4347
#ifdef LIBUSB_SUPPORT
@@ -99,6 +103,7 @@ private slots:
99103
#ifdef LIBUSB_SUPPORT
100104
void usbConnectPhysical(QVariant userData);
101105
#endif
106+
void setThemePreference(int index);
102107

103108
protected:
104109
virtual void changeEvent(QEvent* event) override;
@@ -227,6 +232,12 @@ private slots:
227232
FULLSCREEN_LCD
228233
};
229234

235+
enum class ThemePreference {
236+
System = 0,
237+
Light = 1,
238+
Dark = 2
239+
};
240+
230241
// emu keypresses
231242
void sendEmuKey(uint16_t key);
232243
void sendEmuLetterKey(char letter);
@@ -257,6 +268,7 @@ private slots:
257268
void translateExtras(int init);
258269
void translateSwitch(const QLocale &locale);
259270

271+
void applyThemeFromPreference();
260272
// dark mode
261273
void darkModeSwitch(bool darkMode);
262274

@@ -763,6 +775,8 @@ private slots:
763775
int m_fullscreen = FULLSCREEN_NONE;
764776
uint32_t m_runUntilAddr;
765777

778+
ThemePreference m_themePreference = ThemePreference::System;
779+
766780
QPushButton *m_btnCancelTranser;
767781
QProgressBar *m_progressBar;
768782
QStringList m_docksMemory;
@@ -785,6 +799,8 @@ private slots:
785799
bool m_timerFpsTriggered = false;
786800

787801
QString m_styleForMode[2];
802+
QPalette m_fusionLightPalette;
803+
QPalette m_fusionDarkPalette;
788804

789805
static const char *m_varExtensions[];
790806

@@ -850,6 +866,7 @@ private slots:
850866
static const QString SETTING_STATUS_INTERVAL;
851867
static const QString SETTING_FIRST_RUN;
852868
static const QString SETTING_UI_EDIT_MODE;
869+
static const QString SETTING_UI_THEME;
853870
static const QString SETTING_PAUSE_FOCUS;
854871
static const QString SETTING_SAVE_ON_CLOSE;
855872
static const QString SETTING_RESTORE_ON_OPEN;

gui/qt/mainwindow.ui

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7771,6 +7771,45 @@
77717771
</property>
77727772
</spacer>
77737773
</item>
7774+
<item row="1" column="0">
7775+
<widget class="QLabel" name="labelTheme">
7776+
<property name="text">
7777+
<string>Theme:</string>
7778+
</property>
7779+
</widget>
7780+
</item>
7781+
<item row="1" column="1" colspan="7">
7782+
<widget class="QComboBox" name="comboTheme">
7783+
<item>
7784+
<property name="text">
7785+
<string>System Default</string>
7786+
</property>
7787+
</item>
7788+
<item>
7789+
<property name="text">
7790+
<string>Light</string>
7791+
</property>
7792+
</item>
7793+
<item>
7794+
<property name="text">
7795+
<string>Dark</string>
7796+
</property>
7797+
</item>
7798+
</widget>
7799+
</item>
7800+
<item row="1" column="8">
7801+
<spacer name="horizontalSpacerTheme">
7802+
<property name="orientation">
7803+
<enum>Qt::Horizontal</enum>
7804+
</property>
7805+
<property name="sizeHint" stdset="0">
7806+
<size>
7807+
<width>0</width>
7808+
<height>20</height>
7809+
</size>
7810+
</property>
7811+
</spacer>
7812+
</item>
77747813
</layout>
77757814
</widget>
77767815
</item>

gui/qt/settings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ const QString MainWindow::SETTING_ROM_PATH = QStringLiteral("ro
9494
const QString MainWindow::SETTING_STATUS_INTERVAL = QStringLiteral("status_interval");
9595
const QString MainWindow::SETTING_FIRST_RUN = QStringLiteral("first_run");
9696
const QString MainWindow::SETTING_UI_EDIT_MODE = QStringLiteral("ui_edit_mode");
97+
const QString MainWindow::SETTING_UI_THEME = QStringLiteral("ui_theme");
9798
const QString MainWindow::SETTING_PAUSE_FOCUS = QStringLiteral("pause_on_focus_change");
9899
const QString MainWindow::SETTING_SAVE_ON_CLOSE = QStringLiteral("save_on_close");
99100
const QString MainWindow::SETTING_RESTORE_ON_OPEN = QStringLiteral("restore_on_open");
@@ -1277,6 +1278,7 @@ void MainWindow::saveSettings() {
12771278
m_config->setValue(SETTING_WINDOW_VISUALIZER_CONFIG, m_docksVisualizerConfig);
12781279
m_config->setValue(SETTING_WINDOW_KEYHISTORY_DOCKS, m_docksKeyHistory);
12791280
m_config->setValue(SETTING_WINDOW_KEYHISTORY_CONFIG, QVariant::fromValue(m_docksKeyHistorySize));
1281+
m_config->setValue(SETTING_UI_THEME, static_cast<int>(m_themePreference));
12801282

12811283
// Disassembly Goto history
12821284
{

0 commit comments

Comments
 (0)