You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
duckstation/src/duckstation-qt/qtthemes.cpp

1051 lines
32 KiB
C++

// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "qthost.h"
#include "core/fullscreenui_widgets.h"
#include "common/path.h"
#include <QtCore/QFile>
#include <QtGui/QPalette>
#include <QtGui/QStyleHints>
#include <QtWidgets/QApplication>
#include <QtWidgets/QStyle>
#include <QtWidgets/QStyleFactory>
namespace QtHost {
static void SetThemeAttributes(bool is_stylesheet_theme, bool is_variable_color_theme, bool is_dark_theme);
static bool NativeThemeStylesheetNeedsUpdate();
static void SetStyleFromSettings();
static void SetStyleSheet(const QString& stylesheet);
static QString GetNativeThemeStylesheet();
namespace {
struct State
{
QString unthemed_style_name;
QPalette unthemed_palette;
bool is_stylesheet_theme = false;
bool is_variable_color_theme = false;
bool is_dark_theme = false;
bool unthemed_style_name_set = false;
};
} // namespace
static State s_state;
} // namespace QtHost
const char* QtHost::GetDefaultThemeName()
{
#ifndef __APPLE__
return "darkerfusion";
#else
return "";
#endif
}
void QtHost::UpdateApplicationTheme()
{
if (!s_state.unthemed_style_name_set)
{
s_state.unthemed_style_name_set = true;
s_state.unthemed_style_name = QApplication::style()->objectName();
s_state.unthemed_palette = QApplication::palette();
}
SetStyleFromSettings();
UpdateThemeOnStyleChange();
}
void QtHost::SetThemeAttributes(bool is_stylesheet_theme, bool is_variable_color_theme, bool is_dark_theme)
{
s_state.is_stylesheet_theme = is_stylesheet_theme;
s_state.is_variable_color_theme = is_variable_color_theme;
s_state.is_dark_theme = is_dark_theme;
if (is_variable_color_theme)
qApp->styleHints()->unsetColorScheme();
else
qApp->styleHints()->setColorScheme(is_dark_theme ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
}
void QtHost::SetStyleSheet(const QString& stylesheet)
{
#ifdef __linux__
// Fonts on Linux are ugly and too large. Unfortunately QApplication::setFont() doesn't seem to apply to
// all widgets, so instead we have to jankily prefix it to all stylesheets.
qApp->setStyleSheet(QStringLiteral("QMenu, QMenuBar { font-family: \"Roboto\"; font-size: 12px; }\n") + stylesheet);
#else
qApp->setStyleSheet(stylesheet);
#endif
}
void QtHost::SetStyleFromSettings()
{
const TinyString theme = Host::GetBaseTinyStringSettingValue("UI", "Theme", QtHost::GetDefaultThemeName());
// Clear any existing stylesheet before applying new. Avoids half-painted windows when changing themes.
if (s_state.is_stylesheet_theme)
SetStyleSheet(QString());
if (theme == "qdarkstyle")
{
SetThemeAttributes(true, false, true);
qApp->setStyle(s_state.unthemed_style_name);
qApp->setPalette(s_state.unthemed_palette);
QFile f(QStringLiteral(":qdarkstyle/style.qss"));
if (f.open(QFile::ReadOnly | QFile::Text))
SetStyleSheet(f.readAll());
}
else if (theme == "fusion")
{
SetThemeAttributes(false, true, false);
qApp->setStyle(QStyleFactory::create("Fusion"));
qApp->setPalette(s_state.unthemed_palette);
}
else if (theme == "darkfusion")
{
// adapted from https://gist.github.com/QuantumCD/6245215
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor lighterGray(75, 75, 75);
static constexpr QColor darkGray(53, 53, 53);
static constexpr QColor gray(128, 128, 128);
static constexpr QColor black(25, 25, 25);
static constexpr QColor blue(198, 238, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, black);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, darkGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, lighterGray);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
}
else if (theme == "darkfusionblue")
{
// adapted from https://gist.github.com/QuantumCD/6245215
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
// static constexpr QColor lighterGray(75, 75, 75);
static constexpr QColor darkGray(53, 53, 53);
static constexpr QColor gray(128, 128, 128);
static constexpr QColor black(25, 25, 25);
static constexpr QColor blue(198, 238, 255);
static constexpr QColor blue2(0, 88, 208);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, black);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, blue2);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, darkGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, blue2);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
}
else if (theme == "darkerfusion")
{
SetThemeAttributes(true, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor window_color(36, 36, 36);
static constexpr QColor base_color(43, 43, 43);
static constexpr QColor button_color(40, 40, 40); // qt makes this lighter
static constexpr QColor text(255, 255, 255);
static constexpr QColor highlight_background(65, 65, 65);
static constexpr QColor highlight_text(255, 255, 255);
static constexpr QColor disabled_text(200, 200, 200);
static constexpr QColor placeholder_text(200, 200, 200);
static constexpr QColor link_text(198, 238, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, window_color);
darkPalette.setColor(QPalette::WindowText, text);
darkPalette.setColor(QPalette::Base, base_color);
darkPalette.setColor(QPalette::AlternateBase, window_color);
darkPalette.setColor(QPalette::ToolTipBase, window_color);
darkPalette.setColor(QPalette::ToolTipText, text);
darkPalette.setColor(QPalette::Text, text);
darkPalette.setColor(QPalette::Button, button_color);
darkPalette.setColor(QPalette::ButtonText, text);
darkPalette.setColor(QPalette::Link, link_text);
darkPalette.setColor(QPalette::Highlight, highlight_background);
darkPalette.setColor(QPalette::HighlightedText, highlight_text);
darkPalette.setColor(QPalette::PlaceholderText, placeholder_text);
darkPalette.setColor(QPalette::Active, QPalette::Button, button_color);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabled_text);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, disabled_text);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabled_text);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, window_color);
qApp->setPalette(darkPalette);
// menus are by far the ugliest part of fusion, so we style them manually
const QString stylesheet = QStringLiteral(R"(
QMenu {
border: 1px solid #444;
border-radius: 8px;
padding: 6px 10px;
background-color: #232323;
}
QMenu::icon,
QMenu::indicator {
left: 8px;
}
QMenu::item {
padding: 6px 18px;
border-radius: 8px;
}
QMenu::item:selected {
background-color: #414141;
}
QMenu::icon:checked {
background: #414141;
border: 1px solid #777;
border-radius: 4px;
}
QMenuBar::item {
padding: 4px 6px;
border-radius: 6px;
}
QMenuBar::item:selected, QMenuBar::item:pressed {
background: #303030;
border-radius: 4px;
}
QToolTip {
color: #ffffff;
background-color: #232323;
border: 1px solid #444;
border-radius: 6px;
padding: 2px;
}
QToolBar {
border: none;
}
QToolButton {
border: none;
background: transparent;
padding: 3px;
border-radius: 8px;
}
QToolButton:checked {
background-color: #303030;
}
QToolButton:hover {
background-color: #414141;
}
QToolButton:pressed {
background-color: #515151;
}
QPushButton {
border: none;
background-color: #303030;
padding: 5px 10px;
border-radius: 8px;
color: #ffffff;
}
QPushButton:checked {
background-color: #414141;
}
QPushButton:hover {
background-color: #484848;
}
QPushButton:pressed {
background-color: #515151;
}
QPushButton:disabled {
background-color: #2d2d2d;
color: #777777;
}
QDialog QPushButton {
min-width: 50px;
padding: 6px 12px;
}
QLineEdit {
border: none;
border-radius: 8px;
padding: 4px 8px;
background-color: #2d2d2d;
selection-background-color: #414141;
selection-color: #ffffff;
color: #ffffff;
}
QLineEdit::hover {
background-color: #3a3a3a;
}
QLineEdit:disabled {
background-color: #1e1e1e;
color: #777777;
}
QCheckBox {
spacing: 4px;
padding: 2px 0;
}
QCheckBox::indicator {
width: 14px;
height: 14px;
}
QCheckBox::indicator::unchecked {
image: url(":/icons/white/svg/checkbox-unchecked.svg");
}
QCheckBox::indicator::unchecked:pressed {
image: url(":/icons/white/svg/checkbox-unchecked-pressed.svg");
}
QCheckBox::indicator::unchecked:disabled {
image: url(":/icons/white/svg/checkbox-unchecked-disabled.svg");
}
QCheckBox::indicator::checked {
image: url(":/icons/white/svg/checkbox-checked.svg");
}
QCheckBox::indicator::checked:pressed {
image: url(":/icons/white/svg/checkbox-checked-pressed.svg");
}
QCheckBox::indicator::checked:disabled {
image: url(":/icons/white/svg/checkbox-checked-disabled.svg");
}
QCheckBox::indicator::indeterminate {
image: url(":/icons/white/svg/checkbox-indeterminate.svg");
}
QCheckBox::indicator::indeterminate:pressed {
image: url(":/icons/white/svg/checkbox-indeterminate-pressed.svg");
}
QCheckBox::indicator::indeterminate:disabled {
image: url(":/icons/white/svg/checkbox-indeterminate-disabled.svg");
}
QAbstractSpinBox {
border: none;
border-radius: 8px;
padding: 3px 8px;
background-color: #2d2d2d;
selection-background-color: #414141;
selection-color: #ffffff;
color: #ffffff;
}
QAbstractSpinBox::hover {
background-color: #3a3a3a;
}
QAbstractSpinBox:disabled {
background-color: #1e1e1e;
color: #777777;
}
QAbstractSpinBox::up-button,
QAbstractSpinBox::down-button {
subcontrol-origin: border;
width: 8px;
border: none;
padding: 0 8px;
}
QAbstractSpinBox::up-button {
subcontrol-position: top right; /* position at the top right corner */
}
QAbstractSpinBox::up-arrow {
width: 8px;
height: 8px;
image: url(":/qdarkstyle/arrow_up.png");
}
QAbstractSpinBox::up-arrow:disabled {
image: url(":/qdarkstyle/arrow_up_disabled.png");
}
QAbstractSpinBox::down-button {
subcontrol-position: bottom right; /* position at the top right corner */
}
QAbstractSpinBox::down-arrow {
width: 8px;
height: 8px;
image: url(":/qdarkstyle/arrow_down.png");
}
QAbstractSpinBox::down-arrow:disabled {
image: url(":/qdarkstyle/arrow_down_disabled.png");
}
QComboBox {
border: none;
border-radius: 8px;
padding: 4px 10px 4px 8px; /* leave space for drop-down */
background-color: #2d2d2d;
color: #ffffff;
selection-background-color: #414141;
selection-color: #ffffff;
}
QComboBox:hover {
background-color: #3a3a3a;
}
QComboBox:disabled {
background-color: #1e1e1e;
color: #777777;
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 16px;
border: none;
padding: 0 6px;
background: transparent;
}
QComboBox::down-arrow {
width: 10px;
height: 10px;
image: url(":/qdarkstyle/arrow_down.png");
}
QComboBox::down-arrow:disabled {
image: url(":/qdarkstyle/arrow_down_disabled.png");
}
QScrollBar {
background: #2d2d2d;
width: 12px;
margin: 0px;
border-radius: 6px;
}
QScrollBar::handle {
background-color: #414141;
min-height: 20px;
border-radius: 6px;
}
QScrollBar::handle:hover {
background: #515151;
}
QScrollBar::add-line:vertical,
QScrollBar::sub-line:vertical,
QScrollBar::add-line:horizontal,
QScrollBar::sub-line:horizontal {
height: 0;
}
QHeaderView {
background-color: #2d2d2d;
}
QHeaderView::section {
background-color: #303030;
padding: 2px 4px;
color: #ffffff;
border: none;
}
QHeaderView::section:middle,
QHeaderView::section:last {
border-left: 1px solid #3d3d3d;
}
QHeaderView::section:hover {
background-color: #414141;
}
QHeaderView::section:pressed {
background-color: #515151;
}
QTabBar::tab {
background: #303030;
padding: 6px 12px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-right: 1px solid transparent;
color: #ffffff;
}
QTabBar::tab:selected {
background: #414141;
}
QTabBar::tab:hover {
background: #3a3a3a;
}
QProgressBar {
border: none;
border-radius: 8px;
background-color: #2d2d2d;
color: #ffffff;
text-align: center;
}
QProgressBar::chunk {
background-color: #1464a0;
border-radius: 8px;
}
QSlider {
margin: 2px 0; /* to make room for the handle */
}
QSlider::groove {
border: none;
height: 8px;
background-color: #2d2d2d;
border-radius: 4px;
}
QSlider::handle {
background-color: #808080;
border: none;
width: 16px;
margin: -4px 0; /* handle is placed by default on the groove, so we need to offset it */
border-radius: 8px;
}
QSlider::handle:hover {
background-color: #909090;
}
QSlider::handle:pressed {
background-color: #a0a0a0;
}
QTextBrowser {
border: none;
border-radius: 8px;
padding: 2px 4px;
background-color: #2d2d2d;
selection-background-color: #414141;
selection-color: #ffffff;
color: #ffffff;
}
.settings-window QListView {
border: none;
border-radius: 8px;
background-color: #2d2d2d;
color: #ffffff;
selection-background-color: #414141;
selection-color: #ffffff;
padding: 4px;
}
.settings-window QListView::item {
border: none;
padding: 2px 4px;
border-radius: 8px;
}
.settings-window QListView::item:hover {
background-color: #3a3a3a;
}
.settings-window QListView::item:selected {
background-color: #414141;
color: #ffffff;
}
/* Remove dotted focus rectangle / outline around QListView items when focused/selected */
.settings-window QListView:focus,
.settings-window QListView::item:focus,
.settings-window QListView::item:selected:focus {
outline: none;
border: none;
}
.settings-window QTreeView {
border: none;
border-radius: 8px;
background-color: #2d2d2d;
color: #ffffff;
selection-background-color: #414141;
selection-color: #ffffff;
padding: 4px;
}
.settings-window QTreeView::item {
border: none;
padding: 2px 4px;
}
.settings-window QTreeView::item:hover {
background-color: #3a3a3a;
}
.settings-window QTreeView::item:selected {
background-color: #414141;
color: #ffffff;
}
.settings-window GamePatchSettingsWidget QScrollArea,
.settings-window GamePatchSettingsWidget #patches_container {
border: none;
border-radius: 8px;
background: #2d2d2d;
}
.settings-window GamePatchSettingsWidget #patches_container > QFrame {
border: none;
border-bottom: 1px solid #414141;
margin: 0px 8px;
}
)");
SetStyleSheet(stylesheet);
}
else if (theme == "cobaltsky")
{
// Custom palette by KamFretoZ, A soothing deep royal blue
// that are meant to be easy on the eyes as the main color.
// Alternative dark theme.
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor gray(150, 150, 150);
static constexpr QColor royalBlue(29, 41, 81);
static constexpr QColor darkishBlue(17, 30, 108);
static constexpr QColor lighterBlue(25, 32, 130);
static constexpr QColor highlight(36, 93, 218);
static constexpr QColor link(0, 202, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, royalBlue);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, lighterBlue);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, link);
darkPalette.setColor(QPalette::Highlight, highlight);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, lighterBlue);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
qApp->setPalette(darkPalette);
}
else if (theme == "greymatter")
{
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor darkGray(46, 52, 64);
static constexpr QColor lighterGray(59, 66, 82);
static constexpr QColor gray(111, 111, 111);
static constexpr QColor blue(198, 238, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, lighterGray);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, lighterGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, lighterGray.lighter());
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, lighterGray);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
}
else if (theme == "greengiant")
{
// Custom palette by RedDevilus, Tame (Light/Washed out) Green as main color and Grayish Blue as complimentary.
// Alternative white theme.
SetThemeAttributes(false, false, false);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor black(25, 25, 25);
static constexpr QColor gray(111, 111, 111);
static constexpr QColor limerick(176, 196, 0);
static constexpr QColor brown(135, 100, 50);
static constexpr QColor pear(213, 222, 46);
QPalette greenGiantPalette;
greenGiantPalette.setColor(QPalette::Window, pear);
greenGiantPalette.setColor(QPalette::WindowText, black);
greenGiantPalette.setColor(QPalette::Base, limerick);
greenGiantPalette.setColor(QPalette::AlternateBase, brown.lighter());
greenGiantPalette.setColor(QPalette::ToolTipBase, brown);
greenGiantPalette.setColor(QPalette::ToolTipText, Qt::white);
greenGiantPalette.setColor(QPalette::Text, black);
greenGiantPalette.setColor(QPalette::Button, brown.lighter());
greenGiantPalette.setColor(QPalette::ButtonText, black.lighter());
greenGiantPalette.setColor(QPalette::Link, brown.lighter());
greenGiantPalette.setColor(QPalette::Highlight, brown);
greenGiantPalette.setColor(QPalette::HighlightedText, Qt::white);
greenGiantPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
greenGiantPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
greenGiantPalette.setColor(QPalette::Disabled, QPalette::Text, gray.darker());
greenGiantPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
qApp->setPalette(greenGiantPalette);
}
else if (theme == "pinkypals")
{
SetThemeAttributes(false, false, false);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor black(25, 25, 25);
static constexpr QColor pink(255, 174, 201);
static constexpr QColor darkerPink(214, 145, 168);
static constexpr QColor brightPink(224, 88, 133);
static constexpr QColor congoPink(255, 127, 121);
QPalette PinkyPalsPalette;
PinkyPalsPalette.setColor(QPalette::Window, pink);
PinkyPalsPalette.setColor(QPalette::WindowText, black);
PinkyPalsPalette.setColor(QPalette::Base, darkerPink);
PinkyPalsPalette.setColor(QPalette::AlternateBase, brightPink);
PinkyPalsPalette.setColor(QPalette::ToolTipBase, pink);
PinkyPalsPalette.setColor(QPalette::ToolTipText, darkerPink);
PinkyPalsPalette.setColor(QPalette::Text, black);
PinkyPalsPalette.setColor(QPalette::Button, pink);
PinkyPalsPalette.setColor(QPalette::ButtonText, black);
PinkyPalsPalette.setColor(QPalette::Link, black);
PinkyPalsPalette.setColor(QPalette::Highlight, congoPink);
PinkyPalsPalette.setColor(QPalette::HighlightedText, black);
PinkyPalsPalette.setColor(QPalette::Active, QPalette::Button, pink);
PinkyPalsPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(Qt::white).darker());
PinkyPalsPalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(Qt::white).darker());
PinkyPalsPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(Qt::white).darker());
PinkyPalsPalette.setColor(QPalette::Disabled, QPalette::Light, QColor(Qt::white).darker());
qApp->setPalette(PinkyPalsPalette);
}
else if (theme == "AMOLED")
{
// Custom palette by KamFretoZ, A pure concentrated darkness
// of a theme designed for maximum eye comfort and benefits
// OLED screens.
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor black(0, 0, 0);
static constexpr QColor gray(25, 25, 25);
static constexpr QColor lighterGray(75, 75, 75);
static constexpr QColor blue(198, 238, 255);
QPalette AMOLEDPalette;
AMOLEDPalette.setColor(QPalette::Window, black);
AMOLEDPalette.setColor(QPalette::WindowText, Qt::white);
AMOLEDPalette.setColor(QPalette::Base, gray);
AMOLEDPalette.setColor(QPalette::AlternateBase, black);
AMOLEDPalette.setColor(QPalette::ToolTipBase, gray);
AMOLEDPalette.setColor(QPalette::ToolTipText, Qt::white);
AMOLEDPalette.setColor(QPalette::Text, Qt::white);
AMOLEDPalette.setColor(QPalette::Button, gray);
AMOLEDPalette.setColor(QPalette::ButtonText, Qt::white);
AMOLEDPalette.setColor(QPalette::Link, blue);
AMOLEDPalette.setColor(QPalette::Highlight, lighterGray);
AMOLEDPalette.setColor(QPalette::HighlightedText, Qt::white);
AMOLEDPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
AMOLEDPalette.setColor(QPalette::Active, QPalette::Button, gray);
AMOLEDPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(Qt::white).darker());
AMOLEDPalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(Qt::white).darker());
AMOLEDPalette.setColor(QPalette::Disabled, QPalette::Text, QColor(Qt::white).darker());
AMOLEDPalette.setColor(QPalette::Disabled, QPalette::Light, QColor(Qt::white).darker());
qApp->setPalette(AMOLEDPalette);
}
else if (theme == "darkruby")
{
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor gray(128, 128, 128);
static constexpr QColor slate(18, 18, 18);
static constexpr QColor rubyish(172, 21, 31);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, slate);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, slate.lighter());
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
darkPalette.setColor(QPalette::ToolTipBase, slate);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, slate);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, Qt::white);
darkPalette.setColor(QPalette::Highlight, rubyish);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(darkPalette);
}
else if (theme == "purplerain")
{
SetThemeAttributes(false, false, true);
qApp->setStyle(QStyleFactory::create("Fusion"));
static constexpr QColor darkPurple(73, 41, 121);
static constexpr QColor darkerPurple(53, 29, 87);
static constexpr QColor gold(250, 207, 0);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkPurple);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, darkerPurple);
darkPalette.setColor(QPalette::AlternateBase, darkPurple);
darkPalette.setColor(QPalette::ToolTipBase, darkPurple);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, darkerPurple);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, gold);
darkPalette.setColor(QPalette::Highlight, gold);
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, darkerPurple);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkPurple);
qApp->setPalette(darkPalette);
}
#ifdef _WIN32
else if (theme == "windowsvista")
{
SetThemeAttributes(false, false, false);
qApp->setStyle(QStyleFactory::create("windowsvista"));
qApp->setPalette(s_state.unthemed_palette);
}
#endif
else
{
const QString stylesheet = GetNativeThemeStylesheet();
SetThemeAttributes(!stylesheet.isEmpty(), true, false);
qApp->setStyle(s_state.unthemed_style_name);
qApp->setPalette(s_state.unthemed_palette);
// Cleared above.
if (!stylesheet.isEmpty())
SetStyleSheet(stylesheet);
}
}
bool QtHost::IsDarkApplicationTheme()
{
if (!s_state.is_variable_color_theme)
return s_state.is_dark_theme;
const Qt::ColorScheme system_color_scheme = qApp->styleHints()->colorScheme();
if (system_color_scheme != Qt::ColorScheme::Unknown) [[likely]]
return (system_color_scheme == Qt::ColorScheme::Dark);
const QPalette palette = qApp->palette();
return (palette.windowText().color().value() > palette.window().color().value());
}
bool QtHost::HasGlobalStylesheet()
{
return s_state.is_stylesheet_theme;
}
void QtHost::UpdateThemeOnStyleChange()
{
const QString new_theme_name = IsDarkApplicationTheme() ? QStringLiteral("white") : QStringLiteral("black");
if (QIcon::themeName() != new_theme_name)
QIcon::setThemeName(new_theme_name);
if (NativeThemeStylesheetNeedsUpdate())
{
const QString stylesheet = GetNativeThemeStylesheet();
if (qApp->styleSheet() != stylesheet)
qApp->setStyleSheet(stylesheet);
}
}
const char* Host::GetDefaultFullscreenUITheme()
{
using namespace QtHost;
const TinyString theme = Host::GetBaseTinyStringSettingValue("UI", "Theme", QtHost::GetDefaultThemeName());
if (theme == "cobaltsky")
return "CobaltSky";
else if (theme == "greymatter")
return "GreyMatter";
else if (theme == "greengiant")
return "GreenGiant";
else if (theme == "pinkypals")
return "PinkyPals";
else if (theme == "purplerain")
return "PurpleRain";
else if (theme == "darkruby")
return "DarkRuby";
else if (theme == "AMOLED")
return "AMOLED";
else
return IsDarkApplicationTheme() ? "Dark" : "Light";
}
bool QtHost::NativeThemeStylesheetNeedsUpdate()
{
#ifdef __APPLE__
// See below, only used on MacOS.
// objectName() is empty after applying stylesheet.
return (s_state.is_variable_color_theme && QApplication::style()->objectName().isEmpty());
#else
return false;
#endif
}
QString QtHost::GetNativeThemeStylesheet()
{
QString ret;
#ifdef __APPLE__
// Qt's native style on MacOS is... not great.
// We re-theme the tool buttons to look like Cocoa tool buttons, and fix up popup menus.
ret = QStringLiteral(R"(
QMenu {
border-radius: 10px;
padding: 4px 0;
}
QMenu::item {
padding: 4px 15px;
border-radius: 8px;
margin: 0 2px;
}
QMenu::icon,
QMenu::indicator {
left: 8px;
}
QMenu::icon:checked {
border-radius: 4px;
}
QMenu::separator {
height: 1px;
margin: 4px 8px;
}
QToolButton {
border: none;
background: transparent;
padding: 5px;
border-radius: 10px;
}
.settings-window GamePatchSettingsWidget QScrollArea,
.settings-window GamePatchSettingsWidget #patches_container {
border: none;
}
.settings-window GamePatchSettingsWidget #patches_container > QFrame {
border: none;
margin: 0px 8px;
})");
if (IsDarkApplicationTheme())
{
ret += QStringLiteral(R"(
QMenu {
background-color: #161616;
border: 1px solid #2c2c2c;
}
QMenu::item {
color: #dcdcdc;
}
QMenu::item:selected {
background-color: #2b4ab3;
color: #ffffff;
}
QMenu::item:disabled {
color: #585858;
}
QMenu::icon:checked {
background: #414141;
border: 1px solid #777;
}
QMenu::separator {
background: #3b3b3b;
}
QToolButton:checked {
background-color: #454645;
}
QToolButton:hover {
background-color: #393c3c;
}
QToolButton:pressed {
background-color: #808180;
}
.settings-window GamePatchSettingsWidget QScrollArea,
.settings-window GamePatchSettingsWidget #patches_container {
background: #171717;
}
.settings-window GamePatchSettingsWidget #patches_container > QFrame {
border-bottom: 1px solid #414141;
})");
}
else
{
ret += QStringLiteral(R"(
QMenu {
background-color: #bdbdbd;
border: 1px solid #d5d5d4;
}
QMenu::item {
color: #1d1d1d;
}
QMenu::item:selected {
background-color: #2e5dc9;
color: #ffffff;
}
QMenu::icon:checked {
background: #414141;
border: 1px solid #777;
}
QMenu::item:disabled {
color: #909090;
}
QMenu::separator {
background: #a9a9a9;
}
QToolButton:checked {
background-color: #e2e2e2;
}
QToolButton:hover {
background-color: #f0f0f0;
}
QToolButton:pressed {
background-color: #8c8c8c;
}
.settings-window GamePatchSettingsWidget QScrollArea,
.settings-window GamePatchSettingsWidget #patches_container {
background: #ffffff;
}
.settings-window GamePatchSettingsWidget #patches_container > QFrame {
border-bottom: 1px solid #414141;
})");
}
#endif
return ret;
}