aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--launcher/Application.cpp70
-rw-r--r--launcher/Application.h9
-rw-r--r--launcher/CMakeLists.txt2
-rw-r--r--launcher/ui/themes/CustomTheme.cpp184
-rw-r--r--launcher/ui/themes/CustomTheme.h43
-rw-r--r--launcher/ui/themes/SystemTheme.cpp49
-rw-r--r--launcher/ui/themes/ThemeManager.cpp152
-rw-r--r--launcher/ui/themes/ThemeManager.h44
8 files changed, 436 insertions, 117 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 2da8ac56..7b33361c 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -1,7 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
- * PolyMC - Minecraft Launcher
+ * Prism Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
+ *
+ * PolyMC - Minecraft Launcher
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
*
* This program is free software: you can redistribute it and/or modify
@@ -54,12 +57,6 @@
#include "ui/pages/global/APIPage.h"
#include "ui/pages/global/CustomCommandsPage.h"
-#include "ui/themes/ITheme.h"
-#include "ui/themes/SystemTheme.h"
-#include "ui/themes/DarkTheme.h"
-#include "ui/themes/BrightTheme.h"
-#include "ui/themes/CustomTheme.h"
-
#ifdef Q_OS_WIN
#include "ui/WinDarkmode.h"
#include <versionhelpers.h>
@@ -749,28 +746,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "<> Instance icons intialized.";
}
- // Icon themes
+ // Themes
{
- // TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
- // set icon theme search path!
- auto searchPaths = QIcon::themeSearchPaths();
- searchPaths.append("iconthemes");
- QIcon::setThemeSearchPaths(searchPaths);
- qDebug() << "<> Icon themes initialized.";
- }
+ m_themeManager = new ThemeManager(m_mainWindow);
- // Initialize widget themes
- {
- auto insertTheme = [this](ITheme * theme)
- {
- m_themes.insert(std::make_pair(theme->id(), std::unique_ptr<ITheme>(theme)));
- };
- auto darkTheme = new DarkTheme();
- insertTheme(new SystemTheme());
- insertTheme(darkTheme);
- insertTheme(new BrightTheme());
- insertTheme(new CustomTheme(darkTheme, "custom"));
- qDebug() << "<> Widget themes initialized.";
+ m_themeManager->InitializeThemes();
}
// initialize and load all instances
@@ -880,6 +860,10 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
performMainStartupAction();
}
+ThemeManager* Application::getThemeManager() {
+ return Application::m_themeManager;
+}
+
bool Application::createSetupWizard()
{
bool javaRequired = [&]()
@@ -1127,43 +1111,17 @@ std::shared_ptr<JavaInstallList> Application::javalist()
std::vector<ITheme *> Application::getValidApplicationThemes()
{
- std::vector<ITheme *> ret;
- auto iter = m_themes.cbegin();
- while (iter != m_themes.cend())
- {
- ret.push_back((*iter).second.get());
- iter++;
- }
- return ret;
+ return m_themeManager->getValidApplicationThemes();
}
void Application::setApplicationTheme(const QString& name, bool initial)
{
- auto systemPalette = qApp->palette();
- auto themeIter = m_themes.find(name);
- if(themeIter != m_themes.end())
- {
- auto & theme = (*themeIter).second;
- theme->apply(initial);
-#ifdef Q_OS_WIN
- if (m_mainWindow && IsWindows10OrGreater()) {
- if (QString::compare(theme->id(), "dark") == 0) {
- WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
- } else {
- WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
- }
- }
-#endif
- }
- else
- {
- qWarning() << "Tried to set invalid theme:" << name;
- }
+ m_themeManager->setApplicationTheme(name, initial);
}
void Application::setIconTheme(const QString& name)
{
- QIcon::setThemeName(name);
+ m_themeManager->setIconTheme(name);
}
QIcon Application::getThemedIcon(const QString& name)
diff --git a/launcher/Application.h b/launcher/Application.h
index 8fa0ab10..33d8db29 100644
--- a/launcher/Application.h
+++ b/launcher/Application.h
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
- * PolyMC - Minecraft Launcher
+ * Prism Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,6 +45,8 @@
#include <QUrl>
#include <updater/GoUpdate.h>
+#include "ui/themes/ThemeManager.h"
+
#include <BaseInstance.h>
#include "minecraft/launch/MinecraftServerTarget.h"
@@ -198,6 +201,8 @@ public:
void ShowGlobalSettings(class QWidget * parent, QString open_page = QString());
+ ThemeManager* getThemeManager();
+
signals:
void updateAllowedChanged(bool status);
void globalSettingsAboutToOpen();
@@ -255,9 +260,9 @@ private:
std::shared_ptr<JavaInstallList> m_javalist;
std::shared_ptr<TranslationsModel> m_translations;
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
- std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
QSet<QString> m_features;
+ ThemeManager* m_themeManager;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 0dae47df..5b0d9282 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -650,6 +650,8 @@ SET(LAUNCHER_SOURCES
ui/themes/ITheme.h
ui/themes/SystemTheme.cpp
ui/themes/SystemTheme.h
+ ui/themes/ThemeManager.cpp
+ ui/themes/ThemeManager.h
# Processes
LaunchController.h
diff --git a/launcher/ui/themes/CustomTheme.cpp b/launcher/ui/themes/CustomTheme.cpp
index 3e3e27de..3c35bf37 100644
--- a/launcher/ui/themes/CustomTheme.cpp
+++ b/launcher/ui/themes/CustomTheme.cpp
@@ -1,12 +1,49 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Authors: Andrew Okin
+ * Peterix
+ * Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include "CustomTheme.h"
-#include <QDir>
#include <Json.h>
#include <FileSystem.h>
+#include "ThemeManager.h"
const char * themeFile = "theme.json";
-const char * styleFile = "themeStyle.css";
-static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAmount, QColor &fadeColor, QString &name, QString &widgets)
+static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAmount, QColor &fadeColor, QString &name, QString &widgets, QString &qssFilePath, bool &dataIncomplete)
{
QFileInfo pathInfo(path);
if(pathInfo.exists() && pathInfo.isFile())
@@ -15,8 +52,11 @@ static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAm
{
auto doc = Json::requireDocument(path, "Theme JSON file");
const QJsonObject root = doc.object();
+ dataIncomplete = !root.contains("qssFilePath");
name = Json::requireString(root, "name", "Theme name");
widgets = Json::requireString(root, "widgets", "Qt widget theme");
+ qssFilePath = Json::ensureString(root, "qssFilePath", "themeStyle.css");
+ //auto colorFileList = Json::ensureArray(root, "colorFiles");
auto colorsRoot = Json::requireObject(root, "colors", "colors object");
auto readColor = [&](QString colorName) -> QColor
{
@@ -26,7 +66,7 @@ static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAm
QColor color(colorValue);
if(!color.isValid())
{
- qWarning() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
+ themeWarningLog << "Color value" << colorValue << "for" << colorName << "was not recognized.";
return QColor();
}
return color;
@@ -42,7 +82,7 @@ static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAm
}
else
{
- qDebug() << "Color value for" << colorName << "was not present.";
+ themeDebugLog << "Color value for" << colorName << "was not present.";
}
};
@@ -68,23 +108,24 @@ static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAm
}
catch (const Exception &e)
{
- qWarning() << "Couldn't load theme json: " << e.cause();
+ themeWarningLog << "Couldn't load theme json: " << e.cause();
return false;
}
}
else
{
- qDebug() << "No theme json present.";
+ themeDebugLog << "No theme json present.";
return false;
}
return true;
}
-static bool writeThemeJson(const QString &path, const QPalette &palette, double fadeAmount, QColor fadeColor, QString name, QString widgets)
+static bool writeThemeJson(const QString &path, const QPalette &palette, double fadeAmount, QColor fadeColor, QString name, QString widgets, QString qssFilePath)
{
QJsonObject rootObj;
rootObj.insert("name", name);
rootObj.insert("widgets", widgets);
+ rootObj.insert("qssFilePath", qssFilePath);
QJsonObject colorsObj;
auto insertColor = [&](QPalette::ColorRole role, QString colorName)
@@ -119,75 +160,112 @@ static bool writeThemeJson(const QString &path, const QPalette &palette, double
}
catch (const Exception &e)
{
- qWarning() << "Failed to write theme json to" << path;
+ themeWarningLog << "Failed to write theme json to" << path;
return false;
}
}
-CustomTheme::CustomTheme(ITheme* baseTheme, QString folder)
+/// @brief
+/// @param baseTheme Base Theme
+/// @param fileInfo FileInfo object for file to load
+/// @param isManifest whether to load a theme manifest or a qss file
+CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest)
{
- m_id = folder;
- QString path = FS::PathCombine("themes", m_id);
- QString pathResources = FS::PathCombine("themes", m_id, "resources");
+ if (isManifest) {
+ m_id = fileInfo.dir().dirName();
- qDebug() << "Loading theme" << m_id;
+ QString path = FS::PathCombine("themes", m_id);
+ QString pathResources = FS::PathCombine("themes", m_id, "resources");
- if(!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources))
- {
- qWarning() << "couldn't create folder for theme!";
- m_palette = baseTheme->colorScheme();
- m_styleSheet = baseTheme->appStyleSheet();
- return;
- }
+ if(!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources))
+ {
+ themeWarningLog << "X couldn't create folder for theme!";
+ m_palette = baseTheme->colorScheme();
+ m_styleSheet = baseTheme->appStyleSheet();
+ return;
+ }
- auto themeFilePath = FS::PathCombine(path, themeFile);
+ auto themeFilePath = FS::PathCombine(path, themeFile);
+
+ bool jsonDataIncomplete = false;
- m_palette = baseTheme->colorScheme();
- if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets))
- {
- m_name = "Custom";
m_palette = baseTheme->colorScheme();
- m_fadeColor = baseTheme->fadeColor();
- m_fadeAmount = baseTheme->fadeAmount();
- m_widgets = baseTheme->qtTheme();
+ if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath, jsonDataIncomplete))
+ {
+ themeDebugLog << "Did not read theme json file correctly, writing new one to: " << themeFilePath;
+ m_name = "Custom";
+ m_palette = baseTheme->colorScheme();
+ m_fadeColor = baseTheme->fadeColor();
+ m_fadeAmount = baseTheme->fadeAmount();
+ m_widgets = baseTheme->qtTheme();
+ m_qssFilePath = "themeStyle.css";
- QFileInfo info(themeFilePath);
- if(!info.exists())
+ QFileInfo info(themeFilePath);
+ }
+ else
{
- writeThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, "Custom", m_widgets);
+ m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
}
- }
- else
- {
- m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
- }
- auto cssFilePath = FS::PathCombine(path, styleFile);
- QFileInfo info (cssFilePath);
- if(info.isFile())
- {
- try
+ if(jsonDataIncomplete)
{
- // TODO: validate css?
- m_styleSheet = QString::fromUtf8(FS::read(cssFilePath));
+ writeThemeJson(fileInfo.absoluteFilePath(), m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath);
}
- catch (const Exception &e)
+
+ auto cssFilePath = FS::PathCombine(path, m_qssFilePath);
+ QFileInfo info (cssFilePath);
+ if(info.isFile())
+ {
+ try
+ {
+ // TODO: validate css?
+ m_styleSheet = QString::fromUtf8(FS::read(cssFilePath));
+ }
+ catch (const Exception &e)
+ {
+ themeWarningLog << "X Couldn't load css:" << e.cause() << "from" << cssFilePath;
+ m_styleSheet = baseTheme->appStyleSheet();
+ }
+ }
+ else
{
- qWarning() << "Couldn't load css:" << e.cause() << "from" << cssFilePath;
+ themeDebugLog << "X No theme css present.";
m_styleSheet = baseTheme->appStyleSheet();
+ try
+ {
+ FS::write(cssFilePath, m_styleSheet.toUtf8());
+ }
+ catch (const Exception &e)
+ {
+ themeWarningLog << "X Couldn't write css:" << e.cause() << "to" << cssFilePath;
+ }
}
- }
- else
- {
- qDebug() << "No theme css present.";
- m_styleSheet = baseTheme->appStyleSheet();
+ } else {
+ m_id = fileInfo.fileName();
+ m_name = fileInfo.baseName();
+ QString path = fileInfo.filePath();
+ //themeDebugLog << "Theme ID: " << m_id;
+ //themeDebugLog << "Theme Name: " << m_name;
+ //themeDebugLog << "Theme Path: " << path;
+
+ if(!FS::ensureFilePathExists(path))
+ {
+ themeWarningLog << m_name << " Theme file path doesn't exist!";
+ m_palette = baseTheme->colorScheme();
+ m_styleSheet = baseTheme->appStyleSheet();
+ return;
+ }
+
+ m_palette = baseTheme->colorScheme();
try
{
- FS::write(cssFilePath, m_styleSheet.toUtf8());
+ // TODO: validate qss?
+ m_styleSheet = QString::fromUtf8(FS::read(path));
}
catch (const Exception &e)
{
- qWarning() << "Couldn't write css:" << e.cause() << "to" << cssFilePath;
+ themeWarningLog << "Couldn't load qss:" << e.cause() << "from" << path;
+ m_styleSheet = baseTheme->appStyleSheet();
}
}
}
diff --git a/launcher/ui/themes/CustomTheme.h b/launcher/ui/themes/CustomTheme.h
index d216895d..f4a7b737 100644
--- a/launcher/ui/themes/CustomTheme.h
+++ b/launcher/ui/themes/CustomTheme.h
@@ -1,11 +1,51 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Authors: Andrew Okin
+ * Peterix
+ * Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#pragma once
#include "ITheme.h"
+#include <QFile>
+#include <QDir>
class CustomTheme: public ITheme
{
public:
- CustomTheme(ITheme * baseTheme, QString folder);
+ CustomTheme(ITheme * baseTheme, QFileInfo& file, bool isManifest);
virtual ~CustomTheme() {}
QString id() override;
@@ -27,5 +67,6 @@ private: /* data */
QString m_name;
QString m_id;
QString m_widgets;
+ QString m_qssFilePath;
};
diff --git a/launcher/ui/themes/SystemTheme.cpp b/launcher/ui/themes/SystemTheme.cpp
index 49b1afaa..b8eb2a3c 100644
--- a/launcher/ui/themes/SystemTheme.cpp
+++ b/launcher/ui/themes/SystemTheme.cpp
@@ -1,30 +1,69 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Authors: Andrew Okin
+ * Peterix
+ * Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include "SystemTheme.h"
#include <QApplication>
#include <QStyle>
#include <QStyleFactory>
#include <QDebug>
+#include "ThemeManager.h"
SystemTheme::SystemTheme()
{
- qDebug() << "Determining System Theme...";
+ themeDebugLog << "Determining System Theme...";
const auto & style = QApplication::style();
systemPalette = style->standardPalette();
QString lowerThemeName = style->objectName();
- qDebug() << "System theme seems to be:" << lowerThemeName;
+ themeDebugLog << "System theme seems to be:" << lowerThemeName;
QStringList styles = QStyleFactory::keys();
for(auto &st: styles)
{
- qDebug() << "Considering theme from theme factory:" << st.toLower();
+ themeDebugLog << "Considering theme from theme factory:" << st.toLower();
if(st.toLower() == lowerThemeName)
{
systemTheme = st;
- qDebug() << "System theme has been determined to be:" << systemTheme;
+ themeDebugLog << "System theme has been determined to be:" << systemTheme;
return;
}
}
// fall back to fusion if we can't find the current theme.
systemTheme = "Fusion";
- qDebug() << "System theme not found, defaulted to Fusion";
+ themeDebugLog << "System theme not found, defaulted to Fusion";
}
void SystemTheme::apply(bool initial)
diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp
new file mode 100644
index 00000000..6e1566d2
--- /dev/null
+++ b/launcher/ui/themes/ThemeManager.cpp
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include "ThemeManager.h"
+
+#include "ui/themes/SystemTheme.h"
+#include "ui/themes/DarkTheme.h"
+#include "ui/themes/BrightTheme.h"
+#include "ui/themes/CustomTheme.h"
+#include <QDir>
+#include <QDirIterator>
+#include <QIcon>
+#include <QApplication>
+
+#include "Application.h"
+
+#ifdef Q_OS_WIN
+#include <versionhelpers.h>
+#include "ui/WinDarkmode.h"
+#endif
+
+ThemeManager::ThemeManager(MainWindow* mainWindow) {
+ m_mainWindow = mainWindow;
+}
+
+/// @brief Adds the Theme to the list of themes
+/// @param theme The Theme to add
+/// @return Theme ID
+QString ThemeManager::AddTheme(ITheme * theme) {
+ m_themes.insert(std::make_pair(theme->id(), std::unique_ptr<ITheme>(theme)));
+ return theme->id();
+}
+
+/// @brief Gets the Theme from the List via ID
+/// @param themeId Theme ID of theme to fetch
+/// @return Theme at themeId
+ITheme* ThemeManager::GetTheme(QString themeId) {
+ return m_themes[themeId].get();
+}
+
+void ThemeManager::InitializeThemes() {
+
+
+ // Icon themes
+ {
+ // TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
+ // set icon theme search path!
+ auto searchPaths = QIcon::themeSearchPaths();
+ searchPaths.append("iconthemes");
+ QIcon::setThemeSearchPaths(searchPaths);
+ themeDebugLog << "<> Icon themes initialized.";
+ }
+
+ // Initialize widget themes
+ {
+ themeDebugLog << "<> Initializing Widget Themes";
+ themeDebugLog "✓ Loading Built-in Theme:" << AddTheme(new SystemTheme());
+ auto darkThemeId = AddTheme(new DarkTheme());
+ themeDebugLog "✓ Loading Built-in Theme:" << darkThemeId;
+ themeDebugLog "✓ Loading Built-in Theme:" << AddTheme(new BrightTheme());
+
+ // TODO: need some way to differentiate same name themes in different subdirectories (maybe smaller grey text next to theme name in dropdown? Dunno how to do that though)
+ QString themeFolder = (new QDir("./themes/"))->absoluteFilePath("");
+ themeDebugLog << "Theme Folder Path: " << themeFolder;
+
+ QDirIterator directoryIterator(themeFolder, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
+ while (directoryIterator.hasNext()) {
+ QDir dir(directoryIterator.next());
+ QFileInfo themeJson(dir.absoluteFilePath("theme.json"));
+ if (themeJson.exists()) {
+ // Load "theme.json" based themes
+ themeDebugLog "✓ Loading JSON Theme from:" << themeJson.absoluteFilePath();
+ CustomTheme* theme = new CustomTheme(GetTheme(darkThemeId), themeJson, true);
+ AddTheme(theme);
+ } else {
+ // Load pure QSS Themes
+ QDirIterator stylesheetFileIterator(dir.absoluteFilePath(""), {"*.qss", "*.css"}, QDir::Files);
+ while (stylesheetFileIterator.hasNext()) {
+ QFile customThemeFile(stylesheetFileIterator.next());
+ QFileInfo customThemeFileInfo(customThemeFile);
+ themeDebugLog "✓ Loading QSS Theme from:" << customThemeFileInfo.absoluteFilePath();
+ CustomTheme* theme = new CustomTheme(GetTheme(darkThemeId), customThemeFileInfo, false);
+ AddTheme(theme);
+ }
+ }
+ }
+
+ themeDebugLog << "<> Widget themes initialized.";
+ }
+}
+
+std::vector<ITheme *> ThemeManager::getValidApplicationThemes()
+{
+ std::vector<ITheme *> ret;
+ auto iter = m_themes.cbegin();
+ while (iter != m_themes.cend())
+ {
+ ret.push_back((*iter).second.get());
+ iter++;
+ }
+ return ret;
+}
+
+void ThemeManager::setIconTheme(const QString& name)
+{
+ QIcon::setThemeName(name);
+}
+
+void ThemeManager::applyCurrentlySelectedTheme() {
+ setIconTheme(APPLICATION->settings()->get("IconTheme").toString());
+ themeDebugLog() << "<> Icon theme set.";
+ setApplicationTheme(APPLICATION->settings()->get("ApplicationTheme").toString(), true);
+ themeDebugLog() << "<> Application theme set.";
+}
+
+void ThemeManager::setApplicationTheme(const QString& name, bool initial)
+{
+ auto systemPalette = qApp->palette();
+ auto themeIter = m_themes.find(name);
+ if(themeIter != m_themes.end())
+ {
+ auto & theme = (*themeIter).second;
+ theme->apply(initial);
+#ifdef Q_OS_WIN
+ if (m_mainWindow && IsWindows10OrGreater()) {
+ if (QString::compare(theme->id(), "dark") == 0) {
+ WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
+ } else {
+ WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
+ }
+ }
+#endif
+ }
+ else
+ {
+ qWarning() << "Tried to set invalid theme:" << name;
+ }
+}
diff --git a/launcher/ui/themes/ThemeManager.h b/launcher/ui/themes/ThemeManager.h
new file mode 100644
index 00000000..fa6ea236
--- /dev/null
+++ b/launcher/ui/themes/ThemeManager.h
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher
+ * Copyright (C) 2022 Tayou <tayou@gmx.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <QString>
+
+#include "ui/themes/ITheme.h"
+#include "ui/MainWindow.h"
+
+#define themeDebugLog qDebug() << "[Themes]"
+#define themeWarningLog qWarning() << "[Themes]"
+
+class ThemeManager {
+public:
+ ThemeManager(MainWindow* mainWindow);
+ void InitializeThemes();
+
+ std::vector<ITheme *> getValidApplicationThemes();
+ void setIconTheme(const QString& name);
+ void applyCurrentlySelectedTheme();
+ void setApplicationTheme(const QString& name, bool initial);
+
+private:
+ std::map<QString, std::unique_ptr<ITheme>> m_themes;
+ MainWindow* m_mainWindow;
+
+ QString AddTheme(ITheme * theme);
+ ITheme* GetTheme(QString themeId);
+};
+