Add dark mode configuration setting in UI tab
- Allows to choose "Auto", "Always On" or "Always Off" - Dark mode options are only shown if the style does not support theme - If Auto is chosen, value is retrieved from OS - On Windows, the application needs a restart to apply the settings - Use the default dark palette for Windows, like on Linux
This commit is contained in:
parent
9bba778d15
commit
7c9545c82a
10 changed files with 221 additions and 74 deletions
|
@ -67,6 +67,7 @@ SWITCHABLE(u8, true);
|
||||||
// Used in UISettings
|
// Used in UISettings
|
||||||
// TODO see if we can move this to uisettings.cpp
|
// TODO see if we can move this to uisettings.cpp
|
||||||
SWITCHABLE(ConfirmStop, true);
|
SWITCHABLE(ConfirmStop, true);
|
||||||
|
SWITCHABLE(DarkModeState, true);
|
||||||
|
|
||||||
#undef SETTING
|
#undef SETTING
|
||||||
#undef SWITCHABLE
|
#undef SWITCHABLE
|
||||||
|
|
|
@ -90,6 +90,7 @@ SWITCHABLE(u8, true);
|
||||||
// Used in UISettings
|
// Used in UISettings
|
||||||
// TODO see if we can move this to uisettings.h
|
// TODO see if we can move this to uisettings.h
|
||||||
SWITCHABLE(ConfirmStop, true);
|
SWITCHABLE(ConfirmStop, true);
|
||||||
|
SWITCHABLE(DarkModeState, true);
|
||||||
|
|
||||||
#undef SETTING
|
#undef SETTING
|
||||||
#undef SWITCHABLE
|
#undef SWITCHABLE
|
||||||
|
|
|
@ -155,6 +155,8 @@ ENUM(ConsoleMode, Handheld, Docked);
|
||||||
|
|
||||||
ENUM(AppletMode, HLE, LLE);
|
ENUM(AppletMode, HLE, LLE);
|
||||||
|
|
||||||
|
ENUM(DarkModeState, Off, On, Auto);
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
inline std::string CanonicalizeEnum(Type id) {
|
inline std::string CanonicalizeEnum(Type id) {
|
||||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
|
@ -29,6 +30,8 @@
|
||||||
#include "suyu/uisettings.h"
|
#include "suyu/uisettings.h"
|
||||||
#include "ui_configure_ui.h"
|
#include "ui_configure_ui.h"
|
||||||
|
|
||||||
|
using Settings::DarkModeState;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr std::array default_game_icon_sizes{
|
constexpr std::array default_game_icon_sizes{
|
||||||
std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
|
std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
|
||||||
|
@ -153,6 +156,9 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
|
||||||
&ConfigureUi::RequestGameListUpdate);
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&ConfigureUi::RequestGameListUpdate);
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
|
// Update available dark mode options depending on selected style
|
||||||
|
connect(ui->theme_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
&ConfigureUi::UpdateDarkModeOptions);
|
||||||
|
|
||||||
// Update text ComboBoxes after user interaction.
|
// Update text ComboBoxes after user interaction.
|
||||||
connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated),
|
connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated),
|
||||||
|
@ -185,6 +191,8 @@ ConfigureUi::~ConfigureUi() = default;
|
||||||
void ConfigureUi::ApplyConfiguration() {
|
void ConfigureUi::ApplyConfiguration() {
|
||||||
UISettings::values.theme =
|
UISettings::values.theme =
|
||||||
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
|
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
|
||||||
|
UISettings::values.dark_mode_state =
|
||||||
|
static_cast<DarkModeState>(ui->dark_mode_combobox->currentData().toUInt());
|
||||||
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
|
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
|
||||||
UISettings::values.show_compat = ui->show_compat->isChecked();
|
UISettings::values.show_compat = ui->show_compat->isChecked();
|
||||||
UISettings::values.show_size = ui->show_size->isChecked();
|
UISettings::values.show_size = ui->show_size->isChecked();
|
||||||
|
@ -206,12 +214,71 @@ void ConfigureUi::ApplyConfiguration() {
|
||||||
system.ApplySettings();
|
system.ApplySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureUi::UpdateDarkModeOptions() {
|
||||||
|
ui->dark_mode_combobox->clear();
|
||||||
|
|
||||||
|
QString selected_theme = ui->theme_combobox->currentData().toString();
|
||||||
|
|
||||||
|
/* Dark mode option are added according to the modes the current style supports */
|
||||||
|
bool has_common_style = QFile::exists(selected_theme + QStringLiteral("/style.qss"));
|
||||||
|
bool has_light_style = QFile::exists(selected_theme + QStringLiteral("/light.qss"));
|
||||||
|
bool has_dark_style = QFile::exists(selected_theme + QStringLiteral("/dark.qss"));
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Indicate which option needs a restart to be applied, depending on current environment
|
||||||
|
// variable
|
||||||
|
QByteArray current_qt_qpa = qgetenv("QT_QPA_PLATFORM");
|
||||||
|
if (current_qt_qpa.contains("darkmode=2")) {
|
||||||
|
if (has_common_style || (has_dark_style && has_light_style)) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Auto"), QVariant::fromValue(DarkModeState::Auto));
|
||||||
|
}
|
||||||
|
if (has_common_style || has_dark_style) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Always On") +
|
||||||
|
QStringLiteral(" (%1)").arg(tr("Needs restart")),
|
||||||
|
QVariant::fromValue(DarkModeState::On));
|
||||||
|
}
|
||||||
|
if (has_common_style || has_light_style) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Always Off") +
|
||||||
|
QStringLiteral(" (%1)").arg(tr("Needs restart")),
|
||||||
|
QVariant::fromValue(DarkModeState::Off));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (has_common_style || (has_dark_style && has_light_style)) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Auto") +
|
||||||
|
QStringLiteral(" (%1)").arg(tr("Needs restart")),
|
||||||
|
QVariant::fromValue(DarkModeState::Auto));
|
||||||
|
}
|
||||||
|
if (has_common_style || has_dark_style) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Always On"),
|
||||||
|
QVariant::fromValue(DarkModeState::On));
|
||||||
|
}
|
||||||
|
if (has_common_style || has_light_style) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Always Off"),
|
||||||
|
QVariant::fromValue(DarkModeState::Off));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (has_common_style || (has_dark_style && has_light_style)) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Auto"), QVariant::fromValue(DarkModeState::Auto));
|
||||||
|
}
|
||||||
|
if (has_common_style || has_dark_style) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Always On"), QVariant::fromValue(DarkModeState::On));
|
||||||
|
}
|
||||||
|
if (has_common_style || has_light_style) {
|
||||||
|
ui->dark_mode_combobox->addItem(tr("Always Off"), QVariant::fromValue(DarkModeState::Off));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigureUi::RequestGameListUpdate() {
|
void ConfigureUi::RequestGameListUpdate() {
|
||||||
UISettings::values.is_game_list_reload_pending.exchange(true);
|
UISettings::values.is_game_list_reload_pending.exchange(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureUi::SetConfiguration() {
|
void ConfigureUi::SetConfiguration() {
|
||||||
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
|
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
|
||||||
|
// Dark mode options are populated after the theme is selected, to get the current configuration
|
||||||
|
UpdateDarkModeOptions();
|
||||||
|
ui->dark_mode_combobox->setCurrentIndex(
|
||||||
|
ui->dark_mode_combobox->findData(QVariant::fromValue(UISettings::values.dark_mode_state)));
|
||||||
ui->language_combobox->setCurrentIndex(ui->language_combobox->findData(
|
ui->language_combobox->setCurrentIndex(ui->language_combobox->findData(
|
||||||
QString::fromStdString(UISettings::values.language.GetValue())));
|
QString::fromStdString(UISettings::values.language.GetValue())));
|
||||||
ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
|
ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
|
||||||
|
|
|
@ -34,6 +34,7 @@ signals:
|
||||||
void LanguageChanged(const QString& locale);
|
void LanguageChanged(const QString& locale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void UpdateDarkModeOptions();
|
||||||
void RequestGameListUpdate();
|
void RequestGameListUpdate();
|
||||||
|
|
||||||
void SetConfiguration();
|
void SetConfiguration();
|
||||||
|
|
|
@ -63,6 +63,20 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="dark_mode_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Dark Mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="dark_mode_combobox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -260,8 +260,10 @@ void QtConfig::ReadShortcutValues() {
|
||||||
void QtConfig::ReadUIValues() {
|
void QtConfig::ReadUIValues() {
|
||||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
|
BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
|
||||||
|
|
||||||
UISettings::values.theme = QString::fromStdString(
|
UISettings::values.theme =
|
||||||
ReadStringSetting(std::string("theme"), std::string(UISettings::default_theme)));
|
QString::fromStdString(ReadStringSetting("theme", std::string(UISettings::default_theme)));
|
||||||
|
UISettings::values.dark_mode_state = static_cast<DarkModeState>(
|
||||||
|
ReadIntegerSetting("dark_mode_state", static_cast<int>(DarkModeState::Auto)));
|
||||||
|
|
||||||
ReadUIGamelistValues();
|
ReadUIGamelistValues();
|
||||||
ReadUILayoutValues();
|
ReadUILayoutValues();
|
||||||
|
@ -467,8 +469,10 @@ void QtConfig::SaveUIValues() {
|
||||||
WriteCategory(Settings::Category::Ui);
|
WriteCategory(Settings::Category::Ui);
|
||||||
WriteCategory(Settings::Category::UiGeneral);
|
WriteCategory(Settings::Category::UiGeneral);
|
||||||
|
|
||||||
WriteStringSetting(std::string("theme"), UISettings::values.theme.toStdString(),
|
WriteStringSetting("theme", UISettings::values.theme.toStdString(),
|
||||||
std::make_optional(std::string(UISettings::default_theme)));
|
std::make_optional(std::string(UISettings::default_theme)));
|
||||||
|
WriteIntegerSetting("dark_mode_state", static_cast<int>(UISettings::values.dark_mode_state),
|
||||||
|
std::make_optional(static_cast<int>(DarkModeState::Auto)));
|
||||||
|
|
||||||
SaveUIGamelistValues();
|
SaveUIGamelistValues();
|
||||||
SaveUILayoutValues();
|
SaveUILayoutValues();
|
||||||
|
|
|
@ -3536,6 +3536,7 @@ void GMainWindow::ResetWindowSize1080() {
|
||||||
|
|
||||||
void GMainWindow::OnConfigure() {
|
void GMainWindow::OnConfigure() {
|
||||||
const QString old_theme = UISettings::values.theme;
|
const QString old_theme = UISettings::values.theme;
|
||||||
|
DarkModeState old_dark_mode_state = UISettings::values.dark_mode_state;
|
||||||
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
|
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
|
||||||
const auto old_language_index = Settings::values.language_index.GetValue();
|
const auto old_language_index = Settings::values.language_index.GetValue();
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
|
@ -3594,7 +3595,8 @@ void GMainWindow::OnConfigure() {
|
||||||
}
|
}
|
||||||
InitializeHotkeys();
|
InitializeHotkeys();
|
||||||
|
|
||||||
if (UISettings::values.theme != old_theme) {
|
if (UISettings::values.theme != old_theme ||
|
||||||
|
UISettings::values.dark_mode_state != old_dark_mode_state) {
|
||||||
UpdateUITheme();
|
UpdateUITheme();
|
||||||
}
|
}
|
||||||
if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) {
|
if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) {
|
||||||
|
@ -4791,13 +4793,11 @@ void GMainWindow::filterBarSetChecked(bool state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::UpdateUITheme() {
|
void GMainWindow::UpdateUITheme() {
|
||||||
LOG_DEBUG(Frontend, "Updating UI");
|
const QString default_theme = QString::fromStdString(UISettings::default_theme.data());
|
||||||
QString default_theme = QString::fromStdString(UISettings::default_theme.data());
|
|
||||||
QString current_theme = UISettings::values.theme;
|
QString current_theme = UISettings::values.theme;
|
||||||
if (current_theme.isEmpty()) {
|
if (current_theme.isEmpty()) {
|
||||||
current_theme = default_theme;
|
current_theme = default_theme;
|
||||||
}
|
}
|
||||||
const bool current_dark_mode = CheckDarkMode();
|
|
||||||
|
|
||||||
UpdateIcons(current_theme);
|
UpdateIcons(current_theme);
|
||||||
|
|
||||||
|
@ -4860,7 +4860,7 @@ bool GMainWindow::TryLoadStylesheet(const QString& theme_uri) {
|
||||||
style_path = theme_uri + QStringLiteral("/light.qss");
|
style_path = theme_uri + QStringLiteral("/light.qss");
|
||||||
}
|
}
|
||||||
if (!QFile::exists(style_path)) {
|
if (!QFile::exists(style_path)) {
|
||||||
LOG_INFO(Frontend, "Themed (light/dark) stylesheet could not be found, using default one");
|
LOG_DEBUG(Frontend, "No themed (light/dark) stylesheet, using default one");
|
||||||
// Use common stylesheet if themed one does not exist
|
// Use common stylesheet if themed one does not exist
|
||||||
style_path = theme_uri + QStringLiteral("/style.qss");
|
style_path = theme_uri + QStringLiteral("/style.qss");
|
||||||
}
|
}
|
||||||
|
@ -4871,7 +4871,7 @@ bool GMainWindow::TryLoadStylesheet(const QString& theme_uri) {
|
||||||
// Update the color palette before applying the stylesheet
|
// Update the color palette before applying the stylesheet
|
||||||
UpdateThemePalette();
|
UpdateThemePalette();
|
||||||
|
|
||||||
LOG_INFO(Frontend, "Loading stylesheet in: {}", theme_uri.toStdString());
|
LOG_DEBUG(Frontend, "Loading stylesheet in: {}", theme_uri.toStdString());
|
||||||
QTextStream ts_theme(&style_file);
|
QTextStream ts_theme(&style_file);
|
||||||
qApp->setStyleSheet(ts_theme.readAll());
|
qApp->setStyleSheet(ts_theme.readAll());
|
||||||
setStyleSheet(ts_theme.readAll());
|
setStyleSheet(ts_theme.readAll());
|
||||||
|
@ -4903,12 +4903,34 @@ void GMainWindow::UpdateThemePalette() {
|
||||||
QPalette themePalette(qApp->palette());
|
QPalette themePalette(qApp->palette());
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
QColor dark(25, 25, 25);
|
QColor dark(25, 25, 25);
|
||||||
QColor darkGray(100, 100, 100);
|
QString style_name;
|
||||||
QColor gray(150, 150, 150);
|
|
||||||
QColor light(230, 230, 230);
|
|
||||||
// By default, revert fusion style set for Windows dark theme
|
|
||||||
QString style;
|
|
||||||
if (CheckDarkMode()) {
|
if (CheckDarkMode()) {
|
||||||
|
// We check that the dark mode state is "On" and force a dark palette
|
||||||
|
if (UISettings::values.dark_mode_state == DarkModeState::On) {
|
||||||
|
// Set Default Windows Dark palette on Windows platforms to force Dark mode
|
||||||
|
themePalette.setColor(QPalette::Window, Qt::black);
|
||||||
|
themePalette.setColor(QPalette::WindowText, Qt::white);
|
||||||
|
themePalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
|
||||||
|
themePalette.setColor(QPalette::Base, Qt::black);
|
||||||
|
themePalette.setColor(QPalette::AlternateBase, dark);
|
||||||
|
themePalette.setColor(QPalette::ToolTipBase, Qt::white);
|
||||||
|
themePalette.setColor(QPalette::ToolTipText, Qt::black);
|
||||||
|
themePalette.setColor(QPalette::Text, Qt::white);
|
||||||
|
themePalette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127));
|
||||||
|
themePalette.setColor(QPalette::Dark, QColor(128, 128, 128));
|
||||||
|
themePalette.setColor(QPalette::Shadow, Qt::white);
|
||||||
|
themePalette.setColor(QPalette::Button, Qt::black);
|
||||||
|
themePalette.setColor(QPalette::ButtonText, Qt::white);
|
||||||
|
themePalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127));
|
||||||
|
themePalette.setColor(QPalette::BrightText, QColor(192, 192, 192));
|
||||||
|
themePalette.setColor(QPalette::Link, QColor(0, 140, 200));
|
||||||
|
themePalette.setColor(QPalette::Highlight, QColor(24, 70, 93));
|
||||||
|
themePalette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(0, 85, 255));
|
||||||
|
themePalette.setColor(QPalette::HighlightedText, QColor(239, 240, 241));
|
||||||
|
themePalette.setColor(QPalette::Disabled, QPalette::HighlightedText,
|
||||||
|
QColor(239, 240, 241));
|
||||||
|
}
|
||||||
|
|
||||||
// AlternateBase is kept at rgb(233, 231, 227) or rgb(245, 245, 245) on Windows dark
|
// AlternateBase is kept at rgb(233, 231, 227) or rgb(245, 245, 245) on Windows dark
|
||||||
// palette, fix this. Sometimes, it even is rgb(0, 0, 0), but uses a very light gray for
|
// palette, fix this. Sometimes, it even is rgb(0, 0, 0), but uses a very light gray for
|
||||||
// alternate rows, do not know why
|
// alternate rows, do not know why
|
||||||
|
@ -4919,22 +4941,23 @@ void GMainWindow::UpdateThemePalette() {
|
||||||
alternate_base_modified = true;
|
alternate_base_modified = true;
|
||||||
}
|
}
|
||||||
// Use fusion theme, since its close to windowsvista, but works well with a dark palette
|
// Use fusion theme, since its close to windowsvista, but works well with a dark palette
|
||||||
style = QStringLiteral("fusion");
|
style_name = QStringLiteral("fusion");
|
||||||
} else {
|
} else {
|
||||||
// Reset AlternateBase if it has been modified
|
// Reset AlternateBase if it has been modified
|
||||||
if (alternate_base_modified) {
|
if (alternate_base_modified) {
|
||||||
themePalette.setColor(QPalette::AlternateBase, QColor(245, 245, 245));
|
themePalette.setColor(QPalette::AlternateBase, QColor(245, 245, 245));
|
||||||
alternate_base_modified = false;
|
alternate_base_modified = false;
|
||||||
}
|
}
|
||||||
|
// Reset light palette
|
||||||
|
themePalette = this->style()->standardPalette();
|
||||||
// Reset Windows theme to the default
|
// Reset Windows theme to the default
|
||||||
style = QStringLiteral("windowsvista");
|
style_name = QStringLiteral("windowsvista");
|
||||||
}
|
}
|
||||||
LOG_DEBUG(Frontend, "Using style: {}", style.toStdString());
|
LOG_DEBUG(Frontend, "Using style: {}", style_name.toStdString());
|
||||||
qApp->setStyle(style);
|
qApp->setStyle(style_name);
|
||||||
#else
|
#else
|
||||||
if (CheckDarkMode()) {
|
if (CheckDarkMode()) {
|
||||||
// Set Dark palette on non Windows platforms (that may not have a dark palette)
|
// Set Dark palette on non Windows platforms (that may not have a dark palette)
|
||||||
LOG_INFO(Frontend, "Using custom dark palette");
|
|
||||||
themePalette.setColor(QPalette::Window, QColor(53, 53, 53));
|
themePalette.setColor(QPalette::Window, QColor(53, 53, 53));
|
||||||
themePalette.setColor(QPalette::WindowText, Qt::white);
|
themePalette.setColor(QPalette::WindowText, Qt::white);
|
||||||
themePalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
|
themePalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
|
||||||
|
@ -4956,8 +4979,7 @@ void GMainWindow::UpdateThemePalette() {
|
||||||
themePalette.setColor(QPalette::HighlightedText, Qt::white);
|
themePalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||||
themePalette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127));
|
themePalette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127));
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Frontend, "Using standard palette");
|
// Reset light palette
|
||||||
// Reset light palette on non Windows platforms
|
|
||||||
themePalette = this->style()->standardPalette();
|
themePalette = this->style()->standardPalette();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5018,61 +5040,72 @@ bool GMainWindow::ListenColorSchemeChange() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool GMainWindow::CheckDarkMode() {
|
bool GMainWindow::CheckDarkMode() {
|
||||||
const QPalette current_palette(qApp->palette());
|
bool is_dark_mode_auto;
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Dark mode cannot be changed after the app started on Windows
|
||||||
|
is_dark_mode_auto = qgetenv("QT_QPA_PLATFORM").contains("darkmode=2");
|
||||||
|
#else
|
||||||
|
is_dark_mode_auto = UISettings::values.dark_mode_state == DarkModeState::Auto;
|
||||||
|
#endif
|
||||||
|
if (!is_dark_mode_auto) {
|
||||||
|
return UISettings::values.dark_mode_state == DarkModeState::On;
|
||||||
|
} else {
|
||||||
|
const QPalette current_palette(qApp->palette());
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
QProcess process;
|
QProcess process;
|
||||||
QStringList gdbus_arguments;
|
|
||||||
|
|
||||||
// Using the freedesktop specifications for checking dark mode
|
// Using the freedesktop specifications for checking dark mode
|
||||||
LOG_INFO(Frontend, "Retrieving theme from freedesktop color-scheme...");
|
LOG_DEBUG(Frontend, "Retrieving theme from freedesktop color-scheme...");
|
||||||
gdbus_arguments << QStringLiteral("--dest=org.freedesktop.portal.Desktop")
|
QStringList gdbus_arguments;
|
||||||
<< QStringLiteral("--object-path /org/freedesktop/portal/desktop")
|
gdbus_arguments << QStringLiteral("--dest=org.freedesktop.portal.Desktop")
|
||||||
<< QStringLiteral("--method org.freedesktop.portal.Settings.Read")
|
<< QStringLiteral("--object-path /org/freedesktop/portal/desktop")
|
||||||
<< QStringLiteral("org.freedesktop.appearance color-scheme");
|
<< QStringLiteral("--method org.freedesktop.portal.Settings.Read")
|
||||||
process.start(QStringLiteral("gdbus call --session"), gdbus_arguments);
|
<< QStringLiteral("org.freedesktop.appearance color-scheme");
|
||||||
process.waitForFinished(1000);
|
process.start(QStringLiteral("gdbus call --session"), gdbus_arguments);
|
||||||
QByteArray dbus_output = process.readAllStandardOutput();
|
process.waitForFinished(1000);
|
||||||
|
QByteArray dbus_output = process.readAllStandardOutput();
|
||||||
|
|
||||||
if (!dbus_output.isEmpty()) {
|
if (!dbus_output.isEmpty()) {
|
||||||
const int systemColorSchema = QString::fromUtf8(dbus_output).trimmed().right(1).toInt();
|
const int systemColorSchema = QString::fromUtf8(dbus_output).trimmed().right(1).toInt();
|
||||||
return systemColorSchema == 1;
|
return systemColorSchema == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try alternative for Gnome if the previous one failed
|
// Try alternative for Gnome if the previous one failed
|
||||||
QStringList gsettings_arguments;
|
QStringList gsettings_arguments;
|
||||||
gsettings_arguments << QStringLiteral("get")
|
gsettings_arguments << QStringLiteral("get")
|
||||||
<< QStringLiteral("org.gnome.desktop.interface")
|
<< QStringLiteral("org.gnome.desktop.interface")
|
||||||
<< QStringLiteral("color-scheme");
|
<< QStringLiteral("color-scheme");
|
||||||
|
|
||||||
LOG_DEBUG(Frontend, "failed, retrieving theme from gsettings color-scheme...");
|
|
||||||
process.start(QStringLiteral("gsettings"), gsettings_arguments);
|
|
||||||
process.waitForFinished(1000);
|
|
||||||
QByteArray gsettings_output = process.readAllStandardOutput();
|
|
||||||
|
|
||||||
// Try older gtk-theme method if the previous one failed
|
|
||||||
if (gsettings_output.isEmpty()) {
|
|
||||||
LOG_INFO(Frontend, "failed, retrieving theme from gtk-theme...");
|
|
||||||
gsettings_arguments.takeLast();
|
|
||||||
gsettings_arguments << QStringLiteral("gtk-theme");
|
|
||||||
|
|
||||||
|
LOG_DEBUG(Frontend, "failed, retrieving theme from gsettings color-scheme...");
|
||||||
process.start(QStringLiteral("gsettings"), gsettings_arguments);
|
process.start(QStringLiteral("gsettings"), gsettings_arguments);
|
||||||
process.waitForFinished(1000);
|
process.waitForFinished(1000);
|
||||||
gsettings_output = process.readAllStandardOutput();
|
QByteArray gsettings_output = process.readAllStandardOutput();
|
||||||
}
|
|
||||||
|
|
||||||
// Interpret gsettings value if it succeeded
|
// Try older gtk-theme method if the previous one failed
|
||||||
if (!gsettings_output.isEmpty()) {
|
if (gsettings_output.isEmpty()) {
|
||||||
QString systeme_theme = QString::fromUtf8(gsettings_output);
|
LOG_DEBUG(Frontend, "failed, retrieving theme from gtk-theme...");
|
||||||
LOG_DEBUG(Frontend, "Gsettings output: {}", systeme_theme.toStdString());
|
gsettings_arguments.takeLast();
|
||||||
return systeme_theme.contains(QStringLiteral("dark"), Qt::CaseInsensitive);
|
gsettings_arguments << QStringLiteral("gtk-theme");
|
||||||
}
|
|
||||||
LOG_DEBUG(Frontend, "failed, retrieving theme from palette");
|
process.start(QStringLiteral("gsettings"), gsettings_arguments);
|
||||||
|
process.waitForFinished(1000);
|
||||||
|
gsettings_output = process.readAllStandardOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpret gsettings value if it succeeded
|
||||||
|
if (!gsettings_output.isEmpty()) {
|
||||||
|
QString systeme_theme = QString::fromUtf8(gsettings_output);
|
||||||
|
LOG_DEBUG(Frontend, "Gsettings output: {}", systeme_theme.toStdString());
|
||||||
|
return systeme_theme.contains(QStringLiteral("dark"), Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
LOG_DEBUG(Frontend, "failed, retrieving theme from palette");
|
||||||
#endif
|
#endif
|
||||||
// Use default method based on palette swap by OS.
|
// Use default method based on palette swap by OS. It is the only method on Windows with
|
||||||
// It is the only method on Windows with Qt 5.
|
// Qt 5. Windows needs QT_QPA_PLATFORM env variable set to windows:darkmode=2 to force
|
||||||
// Windows needs QT_QPA_PLATFORM env variable set to windows:darkmode=2 to force palette change
|
// palette change
|
||||||
return (current_palette.color(QPalette::WindowText).lightness() >
|
return (current_palette.color(QPalette::WindowText).lightness() >
|
||||||
current_palette.color(QPalette::Window).lightness());
|
current_palette.color(QPalette::Window).lightness());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::changeEvent(QEvent* event) {
|
void GMainWindow::changeEvent(QEvent* event) {
|
||||||
|
@ -5080,9 +5113,9 @@ void GMainWindow::changeEvent(QEvent* event) {
|
||||||
// UpdateUITheme is a decent work around
|
// UpdateUITheme is a decent work around
|
||||||
if (event->type() == QEvent::PaletteChange ||
|
if (event->type() == QEvent::PaletteChange ||
|
||||||
event->type() == QEvent::ApplicationPaletteChange) {
|
event->type() == QEvent::ApplicationPaletteChange) {
|
||||||
LOG_INFO(Frontend,
|
LOG_DEBUG(Frontend,
|
||||||
"Window color palette changed by event: {} (QEvent::PaletteChange is: {})",
|
"Window color palette changed by event: {} (QEvent::PaletteChange is: {})",
|
||||||
event->type(), QEvent::PaletteChange);
|
event->type(), QEvent::PaletteChange);
|
||||||
const QPalette test_palette(qApp->palette());
|
const QPalette test_palette(qApp->palette());
|
||||||
// Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too
|
// Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too
|
||||||
const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
|
const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
|
||||||
|
@ -5274,6 +5307,31 @@ int main(int argc, char* argv[]) {
|
||||||
QCoreApplication::setApplicationName(QStringLiteral("suyu"));
|
QCoreApplication::setApplicationName(QStringLiteral("suyu"));
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
QByteArray current_qt_qpa = qgetenv("QT_QPA_PLATFORM");
|
||||||
|
// Follow dark mode setting, if the "-platform" launch option is not set.
|
||||||
|
// Otherwise, just follow dark mode for the window decoration (title bar).
|
||||||
|
if (!current_qt_qpa.contains(":darkmode=")) {
|
||||||
|
if (UISettings::values.dark_mode_state == DarkModeState::Auto) {
|
||||||
|
// When setting is Auto, force adapting window decoration and stylesheet palette to use
|
||||||
|
// Windows theme. Default is darkmode:0, which always uses light palette
|
||||||
|
if (current_qt_qpa.isEmpty()) {
|
||||||
|
// Set the value
|
||||||
|
qputenv("QT_QPA_PLATFORM", QByteArray("windows:darkmode=2"));
|
||||||
|
} else {
|
||||||
|
// Concatenate to the existing value
|
||||||
|
qputenv("QT_QPA_PLATFORM", current_qt_qpa + ",darkmode=2");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When setting is no Auto, adapt window decoration to the palette used
|
||||||
|
if (current_qt_qpa.isEmpty()) {
|
||||||
|
// Set the value
|
||||||
|
qputenv("QT_QPA_PLATFORM", QByteArray("windows:darkmode=1"));
|
||||||
|
} else {
|
||||||
|
// Concatenate to the existing value
|
||||||
|
qputenv("QT_QPA_PLATFORM", current_qt_qpa + ",darkmode=1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Increases the maximum open file limit to 8192
|
// Increases the maximum open file limit to 8192
|
||||||
_setmaxstdio(8192);
|
_setmaxstdio(8192);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QtGlobal>
|
|
||||||
#include <processthreadsapi.h>
|
#include <processthreadsapi.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#elif defined(SUYU_UNIX)
|
#elif defined(SUYU_UNIX)
|
||||||
|
@ -38,9 +37,6 @@ void CheckVulkan() {
|
||||||
|
|
||||||
bool CheckEnvVars(bool* is_child) {
|
bool CheckEnvVars(bool* is_child) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Force adapting theme to follow Windows dark mode
|
|
||||||
qputenv("QT_QPA_PLATFORM", QByteArray("windows:darkmode=2"));
|
|
||||||
|
|
||||||
// Check environment variable to see if we are the child
|
// Check environment variable to see if we are the child
|
||||||
char variable_contents[8];
|
char variable_contents[8];
|
||||||
const DWORD startup_check_var =
|
const DWORD startup_check_var =
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
using Settings::Category;
|
using Settings::Category;
|
||||||
using Settings::ConfirmStop;
|
using Settings::ConfirmStop;
|
||||||
|
using Settings::DarkModeState;
|
||||||
using Settings::Setting;
|
using Settings::Setting;
|
||||||
using Settings::SwitchableSetting;
|
using Settings::SwitchableSetting;
|
||||||
|
|
||||||
|
@ -144,6 +145,7 @@ struct Values {
|
||||||
Setting<std::string> language{linkage, {}, "language", Category::Paths};
|
Setting<std::string> language{linkage, {}, "language", Category::Paths};
|
||||||
|
|
||||||
QString theme;
|
QString theme;
|
||||||
|
DarkModeState dark_mode_state;
|
||||||
|
|
||||||
// Shortcut name <Shortcut, context>
|
// Shortcut name <Shortcut, context>
|
||||||
std::vector<Shortcut> shortcuts;
|
std::vector<Shortcut> shortcuts;
|
||||||
|
@ -261,3 +263,4 @@ Q_DECLARE_METATYPE(Settings::RendererBackend);
|
||||||
Q_DECLARE_METATYPE(Settings::ShaderBackend);
|
Q_DECLARE_METATYPE(Settings::ShaderBackend);
|
||||||
Q_DECLARE_METATYPE(Settings::AstcRecompression);
|
Q_DECLARE_METATYPE(Settings::AstcRecompression);
|
||||||
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
|
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
|
||||||
|
Q_DECLARE_METATYPE(Settings::DarkModeState);
|
||||||
|
|
Loading…
Reference in a new issue