diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index b681f3fd..59a51ce7 100644 --- a/application/CMakeLists.txt +++ b/application/CMakeLists.txt @@ -106,6 +106,13 @@ SET(MULTIMC_SOURCES InstanceWindow.h InstanceWindow.cpp + # GUI - themes + themes/DarkTheme.cpp + themes/DarkTheme.h + themes/ITheme.h + themes/SystemTheme.cpp + themes/SystemTheme.h + # GUI - settings-specific wrappers for paged dialog SettingsUI.h diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index f53d05e1..093d03b4 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -9,6 +9,10 @@ #include "pages/global/AccountListPage.h" #include "pages/global/PasteEEPage.h" +#include "themes/ITheme.h" +#include "themes/SystemTheme.h" +#include "themes/DarkTheme.h" + #include #include #include @@ -241,6 +245,9 @@ MultiMC::MultiMC(int &argc, char **argv, bool test_mode) : QApplication(argc, ar // load icons initIcons(); + // load themes + initThemes(); + // and instances auto InstDirSetting = m_settings->getSetting("InstanceDir"); // instance path: check for problems with '!' in instance path and warn the user in the log @@ -442,7 +449,10 @@ void MultiMC::initGlobalSettings(bool test_mode) // Updates m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL); m_settings->registerSetting("AutoUpdate", true); + + // Theming m_settings->registerSetting("IconTheme", QString("multimc")); + m_settings->registerSetting("ApplicationTheme", QString("system")); // Notifications m_settings->registerSetting("ShownNotifications", QString()); @@ -943,6 +953,45 @@ FAILED: QMessageBox::critical(nullptr, tr("Update failed!"), msg); } +std::vector MultiMC::getValidApplicationThemes() +{ + std::vector ret; + auto iter = m_themes.cbegin(); + while (iter != m_themes.cend()) + { + ret.push_back((*iter).second.get()); + iter++; + } + return ret; +} + +void MultiMC::initThemes() +{ + auto insertTheme = [this](ITheme * theme) + { + m_themes.insert(std::make_pair(theme->id(), std::unique_ptr(theme))); + }; + insertTheme(new SystemTheme()); + insertTheme(new DarkTheme()); +} + +void MultiMC::setApplicationTheme(const QString& name) +{ + auto systemPalette = qApp->palette(); + auto themeIter = m_themes.find(name); + if(themeIter != m_themes.end()) + { + auto & theme = (*themeIter).second; + setPalette(theme->colorScheme()); + setStyleSheet(theme->appStyleSheet()); + //setStyle(QStyleFactory::create("Fusion")); + } + else + { + qWarning() << "Tried to set invalid theme:" << name; + } +} + void MultiMC::setIconTheme(const QString& name) { XdgIcon::setThemeName(name); diff --git a/application/MultiMC.h b/application/MultiMC.h index 887f9c2d..3b8751c1 100644 --- a/application/MultiMC.h +++ b/application/MultiMC.h @@ -25,6 +25,7 @@ class UpdateChecker; class BaseProfilerFactory; class BaseDetachedToolFactory; class TranslationDownloader; +class ITheme; #if defined(MMC) #undef MMC @@ -69,6 +70,9 @@ public: void setIconTheme(const QString& name); + std::vector getValidApplicationThemes(); + void setApplicationTheme(const QString& name); + // DownloadUpdateTask std::shared_ptr updateChecker() { @@ -145,6 +149,7 @@ private slots: private: void initLogger(); void initIcons(); + void initThemes(); void initGlobalSettings(bool test_mode); void initTranslations(); void initSSL(); @@ -169,6 +174,7 @@ private: std::shared_ptr m_javalist; std::shared_ptr m_translationChecker; std::shared_ptr m_globalSettingsProvider; + std::map> m_themes; QMap> m_profilers; QMap> m_tools; diff --git a/application/main.cpp b/application/main.cpp index a996ef3b..f22cd732 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -28,6 +28,8 @@ int launchInstance(MultiMC &app, InstancePtr inst) int main_gui(MultiMC &app) { app.setIconTheme(MMC->settings()->get("IconTheme").toString()); + app.setApplicationTheme(MMC->settings()->get("ApplicationTheme").toString()); + // show main window auto inst = app.instances()->getInstanceById(app.launchId); if(inst) diff --git a/application/pages/global/MultiMCPage.cpp b/application/pages/global/MultiMCPage.cpp index c1a24a56..9694fab5 100644 --- a/application/pages/global/MultiMCPage.cpp +++ b/application/pages/global/MultiMCPage.cpp @@ -28,6 +28,7 @@ #include #include "MultiMC.h" #include "BuildConfig.h" +#include "themes/ITheme.h" // FIXME: possibly move elsewhere enum InstSortMode @@ -305,6 +306,14 @@ void MultiMCPage::applySettings() MMC->setIconTheme(s->get("IconTheme").toString()); } + auto originalAppTheme = s->get("ApplicationTheme").toString(); + auto newAppTheme = ui->themeComboBoxColors->currentData().toString(); + if(originalAppTheme != newAppTheme) + { + s->set("ApplicationTheme", newAppTheme); + MMC->setApplicationTheme(newAppTheme); + } + // Console settings s->set("ShowConsole", ui->showConsoleCheck->isChecked()); s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked()); @@ -386,6 +395,21 @@ void MultiMCPage::loadSettings() ui->themeComboBox->setCurrentIndex(0); } + { + auto currentTheme = s->get("ApplicationTheme").toString(); + auto themes = MMC->getValidApplicationThemes(); + int idx = 0; + for(auto &theme: themes) + { + ui->themeComboBoxColors->addItem(theme->name(), theme->id()); + if(currentTheme == theme->id()) + { + ui->themeComboBoxColors->setCurrentIndex(idx); + } + idx++; + } + } + // Console settings ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool()); ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool()); diff --git a/application/pages/global/MultiMCPage.ui b/application/pages/global/MultiMCPage.ui index 943b30ac..2d6f45f0 100644 --- a/application/pages/global/MultiMCPage.ui +++ b/application/pages/global/MultiMCPage.ui @@ -329,13 +329,23 @@ - Icon Theme + Theme - - + + + + + &Icons + + + themeComboBox + + + + - + 0 0 @@ -380,6 +390,29 @@ + + + + + 0 + 0 + + + + Qt::StrongFocus + + + + + + + Colors + + + themeComboBoxColors + + + @@ -552,6 +585,7 @@ sortByNameBtn languageBox themeComboBox + themeComboBoxColors showConsoleCheck autoCloseConsoleCheck lineLimitSpinBox diff --git a/application/themes/DarkTheme.cpp b/application/themes/DarkTheme.cpp new file mode 100644 index 00000000..7445dedf --- /dev/null +++ b/application/themes/DarkTheme.cpp @@ -0,0 +1,37 @@ +#include "DarkTheme.h" + +QString DarkTheme::id() +{ + return "dark"; +} + +QString DarkTheme::name() +{ + return QObject::tr("Dark"); +} + +QPalette DarkTheme::colorScheme() +{ + QPalette darkPalette; + darkPalette.setColor(QPalette::Window, QColor(49,54,59)); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, QColor(35,38,41)); + darkPalette.setColor(QPalette::AlternateBase, QColor(49,54,59)); + darkPalette.setColor(QPalette::ToolTipBase, Qt::white); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, QColor(49,54,59)); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); + + darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + darkPalette.setColor(QPalette::HighlightedText, Qt::black); + return darkPalette; +} + + +QString DarkTheme::appStyleSheet() +{ + return "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"; +} diff --git a/application/themes/DarkTheme.h b/application/themes/DarkTheme.h new file mode 100644 index 00000000..11e621a6 --- /dev/null +++ b/application/themes/DarkTheme.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ITheme.h" + +class DarkTheme: public ITheme +{ +public: + virtual ~DarkTheme() {} + + QString id() override; + QString name() override; + QString appStyleSheet() override; + QPalette colorScheme() override; +}; diff --git a/application/themes/ITheme.h b/application/themes/ITheme.h new file mode 100644 index 00000000..8e0836eb --- /dev/null +++ b/application/themes/ITheme.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +class ITheme +{ +public: + virtual ~ITheme() {} + virtual QString id() = 0; + virtual QString name() = 0; + virtual QString appStyleSheet() = 0; + virtual QPalette colorScheme() = 0; +}; diff --git a/application/themes/SystemTheme.cpp b/application/themes/SystemTheme.cpp new file mode 100644 index 00000000..6ced6843 --- /dev/null +++ b/application/themes/SystemTheme.cpp @@ -0,0 +1,28 @@ +#include "SystemTheme.h" +#include +#include + +SystemTheme::SystemTheme() +{ + systemPalette = QApplication::style()->standardPalette(); +} + +QString SystemTheme::id() +{ + return "system"; +} + +QString SystemTheme::name() +{ + return QObject::tr("System"); +} + +QPalette SystemTheme::colorScheme() +{ + return systemPalette; +} + +QString SystemTheme::appStyleSheet() +{ + return QString(); +} diff --git a/application/themes/SystemTheme.h b/application/themes/SystemTheme.h new file mode 100644 index 00000000..90fd8ed9 --- /dev/null +++ b/application/themes/SystemTheme.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ITheme.h" + +class SystemTheme: public ITheme +{ +public: + SystemTheme(); + virtual ~SystemTheme() {} + + QString id() override; + QString name() override; + QString appStyleSheet() override; + QPalette colorScheme() override; +private: + QPalette systemPalette; + QString systemTheme; +}; +