diff --git a/gui/qt/mainwindow.cpp b/gui/qt/mainwindow.cpp index 8e44ae8d..4a01ee35 100644 --- a/gui/qt/mainwindow.cpp +++ b/gui/qt/mainwindow.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,11 +38,15 @@ #include #include #include +#include +#include +#include #include +#include +#include #include #include #include - #ifdef Q_OS_MACOS # include "os/mac/kdmactouchbar.h" #endif @@ -56,6 +62,8 @@ Q_DECLARE_METATYPE(emu_data_t) # include #endif +using namespace Qt::StringLiterals; + MainWindow::MainWindow(CEmuOpts &cliOpts, QWidget *p) : QMainWindow(p), ui(new Ui::MainWindow), opts(cliOpts) { keypadBridge = new QtKeypadBridge(this); // This must be before setupUi for some reason >.> @@ -70,8 +78,13 @@ MainWindow::MainWindow(CEmuOpts &cliOpts, QWidget *p) : QMainWindow(p), ui(new U ui->setupUi(this); - m_styleForMode[0] = m_styleForMode[1] = QApplication::style()->name(); - darkModeSwitch(isSystemInDarkMode()); + { + QSignalBlocker blocker(ui->comboTheme); + ui->comboTheme->setCurrentIndex(static_cast(m_themePreference)); + } + connect(ui->comboTheme, &QComboBox::currentIndexChanged, this, &MainWindow::setThemePreference); + + applyThemeFromPreference(); setStyleSheet(QStringLiteral("QMainWindow::separator{ width: 0px; height: 0px; }")); @@ -597,6 +610,7 @@ MainWindow::MainWindow(CEmuOpts &cliOpts, QWidget *p) : QMainWindow(p), ui(new U } setAutoUpdates(m_config->value(SETTING_AUTOUPDATE, CEMU_RELEASE).toBool()); + setThemePreference(m_config->value(SETTING_UI_THEME, static_cast(ThemePreference::System)).toInt()); checkVersion(); #ifdef Q_OS_WIN @@ -1129,14 +1143,52 @@ void MainWindow::translateExtras(int init) { } } -void MainWindow::darkModeSwitch(bool darkMode) { - QApplication::setStyle(m_styleForMode[darkMode]); - if (darkMode != isRunningInDarkMode()) { - m_styleForMode[darkMode] = QStringLiteral("fusion"); - QApplication::setStyle(m_styleForMode[darkMode]); - darkMode = isRunningInDarkMode(); +void MainWindow::applyThemeFromPreference() { + Qt::ColorScheme scheme = Qt::ColorScheme::Unknown; + bool explicitScheme = false; + switch (m_themePreference) { + case ThemePreference::System: + scheme = Qt::ColorScheme::Unknown; + break; + case ThemePreference::Light: + scheme = Qt::ColorScheme::Light; + explicitScheme = true; + break; + case ThemePreference::Dark: + scheme = Qt::ColorScheme::Dark; + explicitScheme = true; + break; + } + qApp->styleHints()->setColorScheme(scheme); + +#if defined(Q_OS_WIN) + if (explicitScheme) { + if (QStyle *fusion = QStyleFactory::create("Fusion"_L1)) { + QApplication::setStyle(fusion); + } + } else { + const auto available = QStyleFactory::keys(); + if (available.contains("WindowsVista"_L1, Qt::CaseInsensitive)) { + if (QStyle *vista = QStyleFactory::create("WindowsVista"_L1)) { + QApplication::setStyle(vista); + } + } + } +#elif defined(Q_OS_MACOS) + Q_UNUSED(explicitScheme); +#else + if (explicitScheme) { + if (QStyle *fusion = QStyleFactory::create("Fusion"_L1)) { + QApplication::setStyle(fusion); + } } +#endif + + const bool dark = (qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark); + darkModeSwitch(dark); +} +void MainWindow::darkModeSwitch(bool darkMode) { m_isInDarkMode = darkMode; if (darkMode) { m_cBack.setColor(QPalette::Base, QColor(Qt::blue).lighter(180)); @@ -1160,12 +1212,29 @@ void MainWindow::changeEvent(QEvent* event) { translateSwitch(QLocale::system()); } QMainWindow::changeEvent(event); - if (eventType == QEvent::ThemeChange) { - bool darkMode = isSystemInDarkMode(); - if (darkMode != m_isInDarkMode) { - darkModeSwitch(darkMode); - } + if (eventType == QEvent::ThemeChange || + eventType == QEvent::ApplicationPaletteChange || + eventType == QEvent::PaletteChange) { + const bool dark = (qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark); + darkModeSwitch(dark); + } +} + +void MainWindow::setThemePreference(int index) { + const auto pref = static_cast(index); + + if (ui && ui->comboTheme && ui->comboTheme->currentIndex() != index) { + QSignalBlocker blocker(ui->comboTheme); + ui->comboTheme->setCurrentIndex(index); } + + m_themePreference = pref; + + if (m_config && opts.useSettings) { + m_config->setValue(SETTING_UI_THEME, index); + } + + applyThemeFromPreference(); } void MainWindow::showEvent(QShowEvent *e) { @@ -1485,6 +1554,7 @@ void MainWindow::resetGui() { m_config->remove(SETTING_WINDOW_STATUSBAR); m_config->remove(SETTING_WINDOW_SEPARATOR); m_config->remove(SETTING_UI_EDIT_MODE); + m_config->remove(SETTING_UI_THEME); m_needReload = true; close(); } diff --git a/gui/qt/mainwindow.h b/gui/qt/mainwindow.h index dc13adf4..cc11cd03 100644 --- a/gui/qt/mainwindow.h +++ b/gui/qt/mainwindow.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,9 @@ QT_BEGIN_NAMESPACE class QButtonGroup; class QLocale; +class QEvent; +class QCloseEvent; +class QObject; QT_END_NAMESPACE #ifdef LIBUSB_SUPPORT @@ -100,6 +104,7 @@ private slots: #ifdef LIBUSB_SUPPORT void usbConnectPhysical(QVariant userData); #endif + void setThemePreference(int index); protected: virtual void changeEvent(QEvent* event) override; @@ -228,6 +233,12 @@ private slots: FULLSCREEN_LCD }; + enum class ThemePreference { + System = 0, + Light = 1, + Dark = 2 + }; + // emu keypresses void sendEmuKey(uint16_t key); void sendEmuLetterKey(char letter); @@ -258,6 +269,7 @@ private slots: void translateExtras(int init); void translateSwitch(const QLocale &locale); + void applyThemeFromPreference(); // dark mode void darkModeSwitch(bool darkMode); @@ -769,6 +781,8 @@ private slots: int m_fullscreen = FULLSCREEN_NONE; uint32_t m_runUntilAddr; + ThemePreference m_themePreference = ThemePreference::System; + QPushButton *m_btnCancelTranser; QProgressBar *m_progressBar; QStringList m_docksMemory; @@ -790,7 +804,7 @@ private slots: bool m_timerEmuTriggered = false; bool m_timerFpsTriggered = false; - QString m_styleForMode[2]; + static const char *m_varExtensions[]; @@ -856,6 +870,7 @@ private slots: static const QString SETTING_STATUS_INTERVAL; static const QString SETTING_FIRST_RUN; static const QString SETTING_UI_EDIT_MODE; + static const QString SETTING_UI_THEME; static const QString SETTING_PAUSE_FOCUS; static const QString SETTING_SAVE_ON_CLOSE; static const QString SETTING_RESTORE_ON_OPEN; diff --git a/gui/qt/mainwindow.ui b/gui/qt/mainwindow.ui index 9f8b5b9f..4595f4a9 100644 --- a/gui/qt/mainwindow.ui +++ b/gui/qt/mainwindow.ui @@ -7682,7 +7682,7 @@ - + Qt::Horizontal @@ -7771,6 +7771,47 @@ + + + + Theme: + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + 200 + 16777215 + + + + + System Default + + + + + Light + + + + + Dark + + + + diff --git a/gui/qt/settings.cpp b/gui/qt/settings.cpp index 9ecb06da..c915a5e6 100644 --- a/gui/qt/settings.cpp +++ b/gui/qt/settings.cpp @@ -94,6 +94,7 @@ const QString MainWindow::SETTING_ROM_PATH = QStringLiteral("ro const QString MainWindow::SETTING_STATUS_INTERVAL = QStringLiteral("status_interval"); const QString MainWindow::SETTING_FIRST_RUN = QStringLiteral("first_run"); const QString MainWindow::SETTING_UI_EDIT_MODE = QStringLiteral("ui_edit_mode"); +const QString MainWindow::SETTING_UI_THEME = QStringLiteral("ui_theme"); const QString MainWindow::SETTING_PAUSE_FOCUS = QStringLiteral("pause_on_focus_change"); const QString MainWindow::SETTING_SAVE_ON_CLOSE = QStringLiteral("save_on_close"); const QString MainWindow::SETTING_RESTORE_ON_OPEN = QStringLiteral("restore_on_open"); @@ -1277,6 +1278,7 @@ void MainWindow::saveSettings() { m_config->setValue(SETTING_WINDOW_VISUALIZER_CONFIG, m_docksVisualizerConfig); m_config->setValue(SETTING_WINDOW_KEYHISTORY_DOCKS, m_docksKeyHistory); m_config->setValue(SETTING_WINDOW_KEYHISTORY_CONFIG, QVariant::fromValue(m_docksKeyHistorySize)); + m_config->setValue(SETTING_UI_THEME, static_cast(m_themePreference)); // Disassembly Goto history {