2022-10-29 18:27:20 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
/*
|
2022-11-03 03:54:57 +00:00
|
|
|
* Prism Launcher - Minecraft Launcher
|
2022-10-29 18:27:20 +01:00
|
|
|
* 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"
|
|
|
|
|
2022-11-03 04:05:07 +00:00
|
|
|
#include <QApplication>
|
2022-10-29 18:27:20 +01:00
|
|
|
#include <QDir>
|
|
|
|
#include <QDirIterator>
|
|
|
|
#include <QIcon>
|
2022-11-03 04:05:07 +00:00
|
|
|
#include "ui/themes/BrightTheme.h"
|
|
|
|
#include "ui/themes/CustomTheme.h"
|
|
|
|
#include "ui/themes/DarkTheme.h"
|
|
|
|
#include "ui/themes/SystemTheme.h"
|
2022-10-29 18:27:20 +01:00
|
|
|
|
|
|
|
#include "Application.h"
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
2022-11-03 04:05:07 +00:00
|
|
|
#include <windows.h>
|
|
|
|
// this is needed for versionhelpers.h, it is also included in WinDarkmode, but we can't rely on that.
|
2022-11-01 14:41:08 +00:00
|
|
|
// Ultimately this should be included in versionhelpers, but that is outside of the project.
|
2022-10-29 18:27:20 +01:00
|
|
|
#include "ui/WinDarkmode.h"
|
2022-11-01 14:41:08 +00:00
|
|
|
#include <versionhelpers.h>
|
2022-10-29 18:27:20 +01:00
|
|
|
#endif
|
|
|
|
|
2022-11-03 04:05:07 +00:00
|
|
|
ThemeManager::ThemeManager(MainWindow* mainWindow)
|
|
|
|
{
|
2022-10-29 18:27:20 +01:00
|
|
|
m_mainWindow = mainWindow;
|
2022-11-01 14:41:08 +00:00
|
|
|
InitializeThemes();
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Adds the Theme to the list of themes
|
|
|
|
/// @param theme The Theme to add
|
|
|
|
/// @return Theme ID
|
2022-11-03 04:05:07 +00:00
|
|
|
QString ThemeManager::AddTheme(std::unique_ptr<ITheme> theme)
|
|
|
|
{
|
2022-11-01 14:41:08 +00:00
|
|
|
QString id = theme->id();
|
|
|
|
m_themes.emplace(id, std::move(theme));
|
|
|
|
return id;
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Gets the Theme from the List via ID
|
|
|
|
/// @param themeId Theme ID of theme to fetch
|
|
|
|
/// @return Theme at themeId
|
2022-11-03 04:05:07 +00:00
|
|
|
ITheme* ThemeManager::GetTheme(QString themeId)
|
|
|
|
{
|
2022-10-29 18:27:20 +01:00
|
|
|
return m_themes[themeId].get();
|
|
|
|
}
|
|
|
|
|
2022-11-03 04:05:07 +00:00
|
|
|
void ThemeManager::InitializeThemes()
|
|
|
|
{
|
2022-10-29 18:27:20 +01:00
|
|
|
// 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);
|
2022-11-01 14:41:08 +00:00
|
|
|
themeDebugLog() << "<> Icon themes initialized.";
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize widget themes
|
|
|
|
{
|
2022-11-01 14:41:08 +00:00
|
|
|
themeDebugLog() << "<> Initializing Widget Themes";
|
|
|
|
themeDebugLog() << "Loading Built-in Theme:" << AddTheme(std::make_unique<SystemTheme>());
|
|
|
|
auto darkThemeId = AddTheme(std::make_unique<DarkTheme>());
|
|
|
|
themeDebugLog() << "Loading Built-in Theme:" << darkThemeId;
|
|
|
|
themeDebugLog() << "Loading Built-in Theme:" << AddTheme(std::make_unique<BrightTheme>());
|
2022-10-29 18:27:20 +01:00
|
|
|
|
2022-11-03 04:05:07 +00:00
|
|
|
// TODO: need some way to differentiate same name themes in different subdirectories (maybe smaller grey text next to theme name in
|
|
|
|
// dropdown?)
|
2022-11-01 14:41:08 +00:00
|
|
|
QString themeFolder = QDir("./themes/").absoluteFilePath("");
|
|
|
|
themeDebugLog() << "Theme Folder Path: " << themeFolder;
|
2022-10-29 18:27:20 +01:00
|
|
|
|
|
|
|
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
|
2022-11-01 14:41:08 +00:00
|
|
|
themeDebugLog() << "Loading JSON Theme from:" << themeJson.absoluteFilePath();
|
|
|
|
AddTheme(std::make_unique<CustomTheme>(GetTheme(darkThemeId), themeJson, true));
|
2022-10-29 18:27:20 +01:00
|
|
|
} else {
|
|
|
|
// Load pure QSS Themes
|
2022-11-03 04:05:07 +00:00
|
|
|
QDirIterator stylesheetFileIterator(dir.absoluteFilePath(""), { "*.qss", "*.css" }, QDir::Files);
|
2022-10-29 18:27:20 +01:00
|
|
|
while (stylesheetFileIterator.hasNext()) {
|
|
|
|
QFile customThemeFile(stylesheetFileIterator.next());
|
|
|
|
QFileInfo customThemeFileInfo(customThemeFile);
|
2022-11-01 14:41:08 +00:00
|
|
|
themeDebugLog() << "Loading QSS Theme from:" << customThemeFileInfo.absoluteFilePath();
|
|
|
|
AddTheme(std::make_unique<CustomTheme>(GetTheme(darkThemeId), customThemeFileInfo, false));
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 14:41:08 +00:00
|
|
|
themeDebugLog() << "<> Widget themes initialized.";
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-01 14:41:08 +00:00
|
|
|
QList<ITheme*> ThemeManager::getValidApplicationThemes()
|
2022-10-29 18:27:20 +01:00
|
|
|
{
|
2022-11-01 14:41:08 +00:00
|
|
|
QList<ITheme*> ret;
|
|
|
|
ret.reserve(m_themes.size());
|
|
|
|
for (auto&& [id, theme] : m_themes) {
|
|
|
|
ret.append(theme.get());
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeManager::setIconTheme(const QString& name)
|
|
|
|
{
|
|
|
|
QIcon::setThemeName(name);
|
|
|
|
}
|
|
|
|
|
2022-11-03 04:05:07 +00:00
|
|
|
void ThemeManager::applyCurrentlySelectedTheme()
|
|
|
|
{
|
2022-10-29 18:27:20 +01:00
|
|
|
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);
|
2022-11-03 04:05:07 +00:00
|
|
|
if (themeIter != m_themes.end()) {
|
|
|
|
auto& theme = themeIter->second;
|
2022-11-01 14:41:08 +00:00
|
|
|
themeDebugLog() << "applying theme" << theme->name();
|
2022-10-29 18:27:20 +01:00
|
|
|
theme->apply(initial);
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
if (m_mainWindow && IsWindows10OrGreater()) {
|
|
|
|
if (QString::compare(theme->id(), "dark") == 0) {
|
2022-11-03 04:05:07 +00:00
|
|
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
2022-10-29 18:27:20 +01:00
|
|
|
} else {
|
2022-11-03 04:05:07 +00:00
|
|
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-11-03 04:05:07 +00:00
|
|
|
} else {
|
2022-11-01 14:41:08 +00:00
|
|
|
themeWarningLog() << "Tried to set invalid theme:" << name;
|
2022-10-29 18:27:20 +01:00
|
|
|
}
|
|
|
|
}
|