Merge pull request #1407 from TheKodeToad/icon-indexing

This commit is contained in:
Sefa Eyeoglu
2023-08-15 10:43:29 +02:00
committed by GitHub
21 changed files with 454 additions and 189 deletions

View File

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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 "IconTheme.h"
#include <QFile>
#include <QSettings>
IconTheme::IconTheme(const QString& id, const QString& path) : m_id(id), m_path(path) {}
bool IconTheme::load()
{
const QString path = m_path + "/index.theme";
if (!QFile::exists(path))
return false;
QSettings settings(path, QSettings::IniFormat);
settings.beginGroup("Icon Theme");
m_name = settings.value("Name").toString();
settings.endGroup();
return !m_name.isNull();
}
QString IconTheme::id()
{
return m_id;
}
QString IconTheme::path()
{
return m_path;
}
QString IconTheme::name()
{
return m_name;
}

View File

@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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/>.
*/
#pragma once
#include <QString>
class IconTheme {
public:
IconTheme(const QString& id, const QString& path);
IconTheme() = default;
bool load();
QString id();
QString path();
QString name();
private:
QString m_id;
QString m_path;
QString m_name;
};

View File

@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Tayou <git@tayou.org>
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@ -31,9 +32,8 @@
#include "Application.h"
ThemeManager::ThemeManager(MainWindow* mainWindow)
ThemeManager::ThemeManager()
{
m_mainWindow = mainWindow;
initializeThemes();
initializeCatPacks();
}
@ -59,53 +59,110 @@ ITheme* ThemeManager::getTheme(QString themeId)
return m_themes[themeId].get();
}
QString ThemeManager::addIconTheme(IconTheme theme)
{
QString id = theme.id();
if (m_icons.find(id) == m_icons.end())
m_icons.emplace(id, std::move(theme));
else
themeWarningLog() << "IconTheme(" << id << ") not added to prevent id duplication";
return id;
}
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.";
}
initializeIcons();
// Initialize widget themes
{
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>());
initializeWidgets();
}
// TODO: need some way to differentiate same name themes in different subdirectories (maybe smaller grey text next to theme name in
// dropdown?)
QString themeFolder = QDir("./themes/").absoluteFilePath("");
themeDebugLog() << "Theme Folder Path: " << themeFolder;
void ThemeManager::initializeIcons()
{
// TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
// set icon theme search path!
themeDebugLog() << "<> Initializing Icon Themes";
QDirIterator directoryIterator(themeFolder, QDir::Dirs | QDir::NoDotAndDotDot);
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();
addTheme(std::make_unique<CustomTheme>(getTheme(darkThemeId), themeJson, true));
} 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();
addTheme(std::make_unique<CustomTheme>(getTheme(darkThemeId), customThemeFileInfo, false));
}
}
auto searchPaths = QIcon::themeSearchPaths();
searchPaths.append(m_iconThemeFolder.path());
QIcon::setThemeSearchPaths(searchPaths);
for (const QString& id : builtinIcons) {
IconTheme theme(id, QString(":/icons/%1").arg(id));
if (!theme.load()) {
themeWarningLog() << "Couldn't load built-in icon theme" << id;
continue;
}
themeDebugLog() << "<> Widget themes initialized.";
addIconTheme(std::move(theme));
themeDebugLog() << "Loaded Built-In Icon Theme" << id;
}
if (!m_iconThemeFolder.mkpath("."))
themeWarningLog() << "Couldn't create icon theme folder";
themeDebugLog() << "Icon Theme Folder Path: " << m_iconThemeFolder.absolutePath();
QDirIterator directoryIterator(m_iconThemeFolder.path(), QDir::Dirs | QDir::NoDotAndDotDot);
while (directoryIterator.hasNext()) {
QDir dir(directoryIterator.next());
IconTheme theme(dir.dirName(), dir.path());
if (!theme.load())
continue;
addIconTheme(std::move(theme));
themeDebugLog() << "Loaded Custom Icon Theme from" << dir.path();
}
themeDebugLog() << "<> Icon themes initialized.";
}
void ThemeManager::initializeWidgets()
{
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>());
// TODO: need some way to differentiate same name themes in different subdirectories (maybe smaller grey text next to theme name in
// dropdown?)
if (!m_applicationThemeFolder.mkpath("."))
themeWarningLog() << "Couldn't create theme folder";
themeDebugLog() << "Theme Folder Path: " << m_applicationThemeFolder.absolutePath();
QDirIterator directoryIterator(m_applicationThemeFolder.path(), QDir::Dirs | QDir::NoDotAndDotDot);
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();
addTheme(std::make_unique<CustomTheme>(getTheme(darkThemeId), themeJson, true));
} 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();
addTheme(std::make_unique<CustomTheme>(getTheme(darkThemeId), customThemeFileInfo, false));
}
}
}
themeDebugLog() << "<> Widget themes initialized.";
}
QList<IconTheme*> ThemeManager::getValidIconThemes()
{
QList<IconTheme*> ret;
ret.reserve(m_icons.size());
for (auto&& [id, theme] : m_icons) {
ret.append(&theme);
}
return ret;
}
QList<ITheme*> ThemeManager::getValidApplicationThemes()
@ -128,17 +185,39 @@ QList<CatPack*> ThemeManager::getValidCatPacks()
return ret;
}
void ThemeManager::setIconTheme(const QString& name)
bool ThemeManager::isValidIconTheme(const QString& id)
{
QIcon::setThemeName(name);
return !id.isEmpty() && m_icons.find(id) != m_icons.end();
}
void ThemeManager::applyCurrentlySelectedTheme(bool initial)
bool ThemeManager::isValidApplicationTheme(const QString& id)
{
setIconTheme(APPLICATION->settings()->get("IconTheme").toString());
themeDebugLog() << "<> Icon theme set.";
setApplicationTheme(APPLICATION->settings()->get("ApplicationTheme").toString(), initial);
themeDebugLog() << "<> Application theme set.";
return !id.isEmpty() && m_themes.find(id) != m_themes.end();
}
QDir ThemeManager::getIconThemesFolder()
{
return m_iconThemeFolder;
}
QDir ThemeManager::getApplicationThemesFolder()
{
return m_applicationThemeFolder;
}
QDir ThemeManager::getCatPacksFolder()
{
return m_catPacksFolder;
}
void ThemeManager::setIconTheme(const QString& name)
{
if (m_icons.find(name) == m_icons.end()) {
themeWarningLog() << "Tried to set invalid icon theme:" << name;
return;
}
QIcon::setThemeName(name);
}
void ThemeManager::setApplicationTheme(const QString& name, bool initial)
@ -154,6 +233,15 @@ void ThemeManager::setApplicationTheme(const QString& name, bool initial)
}
}
void ThemeManager::applyCurrentlySelectedTheme(bool initial)
{
auto settings = APPLICATION->settings();
setIconTheme(settings->get("IconTheme").toString());
themeDebugLog() << "<> Icon theme set.";
setApplicationTheme(settings->get("ApplicationTheme").toString(), initial);
themeDebugLog() << "<> Application theme set.";
}
QString ThemeManager::getCatPack(QString catName)
{
auto catIter = m_catPacks.find(!catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString());
@ -187,9 +275,9 @@ void ThemeManager::initializeCatPacks()
for (auto [id, name] : defaultCats) {
addCatPack(std::unique_ptr<CatPack>(new BasicCatPack(id, name)));
}
QDir catpacksDir("catpacks");
QString catpacksFolder = catpacksDir.absoluteFilePath("");
themeDebugLog() << "CatPacks Folder Path:" << catpacksFolder;
if (!m_catPacksFolder.mkpath("."))
themeWarningLog() << "Couldn't create catpacks folder";
themeDebugLog() << "CatPacks Folder Path:" << m_catPacksFolder.absolutePath();
QStringList supportedImageFormats;
for (auto format : QImageReader::supportedImageFormats()) {
@ -206,9 +294,9 @@ void ThemeManager::initializeCatPacks()
}
};
loadFiles(catpacksDir);
loadFiles(m_catPacksFolder);
QDirIterator directoryIterator(catpacksFolder, QDir::Dirs | QDir::NoDotAndDotDot);
QDirIterator directoryIterator(m_catPacksFolder.path(), QDir::Dirs | QDir::NoDotAndDotDot);
while (directoryIterator.hasNext()) {
QDir dir(directoryIterator.next());
QFileInfo manifest(dir.absoluteFilePath("catpack.json"));

View File

@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Tayou <git@tayou.org>
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@ -19,6 +20,7 @@
#include <QString>
#include "IconTheme.h"
#include "ui/MainWindow.h"
#include "ui/themes/CatPack.h"
#include "ui/themes/ITheme.h"
@ -34,11 +36,17 @@ inline auto themeWarningLog()
class ThemeManager {
public:
ThemeManager(MainWindow* mainWindow);
ThemeManager();
QList<IconTheme*> getValidIconThemes();
QList<ITheme*> getValidApplicationThemes();
void setIconTheme(const QString& name);
bool isValidIconTheme(const QString& id);
bool isValidApplicationTheme(const QString& id);
QDir getIconThemesFolder();
QDir getApplicationThemesFolder();
QDir getCatPacksFolder();
void applyCurrentlySelectedTheme(bool initial = false);
void setIconTheme(const QString& name);
void setApplicationTheme(const QString& name, bool initial = false);
/// @brief Returns the background based on selected and with events (Birthday, XMas, etc.)
@ -49,12 +57,21 @@ class ThemeManager {
private:
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::map<QString, IconTheme> m_icons;
QDir m_iconThemeFolder{ "iconthemes" };
QDir m_applicationThemeFolder{ "themes" };
QDir m_catPacksFolder{ "catpacks" };
std::map<QString, std::unique_ptr<CatPack>> m_catPacks;
MainWindow* m_mainWindow;
void initializeThemes();
void initializeCatPacks();
QString addTheme(std::unique_ptr<ITheme> theme);
ITheme* getTheme(QString themeId);
QString addIconTheme(IconTheme theme);
QString addCatPack(std::unique_ptr<CatPack> catPack);
void initializeIcons();
void initializeWidgets();
const QStringList builtinIcons{ "pe_colored", "pe_light", "pe_dark", "pe_blue", "breeze_light", "breeze_dark",
"OSX", "iOS", "flat", "flat_white", "multimc" };
};