Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into feature/java-downloader

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2024-08-23 08:16:59 +03:00
commit 92495494ca
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
25 changed files with 251 additions and 374 deletions

View File

@ -25,7 +25,7 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Create backport PRs
uses: korthout/backport-action@v3.0.2
uses: korthout/backport-action@v3.1.0
with:
# Config README: https://github.com/korthout/backport-action#backport-action
pull_description: |-

12
flake.lock generated
View File

@ -75,11 +75,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1723175592,
"narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=",
"lastModified": 1723637854,
"narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5e0ca22929f3342b19569b21b2f3462f053e497b",
"rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9",
"type": "github"
},
"original": {
@ -103,11 +103,11 @@
]
},
"locked": {
"lastModified": 1723202784,
"narHash": "sha256-qbhjc/NEGaDbyy0ucycubq4N3//gDFFH3DOmp1D3u1Q=",
"lastModified": 1723803910,
"narHash": "sha256-yezvUuFiEnCFbGuwj/bQcqg7RykIEqudOy/RBrId0pc=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "c7012d0c18567c889b948781bc74a501e92275d1",
"rev": "bfef0ada09e2c8ac55bbcd0831bd0c9d42e651ba",
"type": "github"
},
"original": {

View File

@ -800,8 +800,6 @@ SET(LAUNCHER_SOURCES
# GUI - windows
ui/GuiUtil.h
ui/GuiUtil.cpp
ui/ColorCache.h
ui/ColorCache.cpp
ui/MainWindow.h
ui/MainWindow.cpp
ui/InstanceWindow.h

View File

@ -46,20 +46,23 @@ void CheckJava::executeTask()
{
auto instance = m_parent->instance();
auto settings = instance->settings();
m_javaPath = FS::ResolveExecutable(settings->get("JavaPath").toString());
bool perInstance = settings->get("OverrideJavaLocation").toBool();
QString javaPathSetting = settings->get("JavaPath").toString();
m_javaPath = FS::ResolveExecutable(javaPathSetting);
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
if (realJavaPath.isEmpty()) {
if (perInstance) {
emit logLine(QString("The java binary \"%1\" couldn't be found. Please fix the java path "
emit logLine(QString("The Java binary \"%1\" couldn't be found. Please fix the Java path "
"override in the instance's settings or disable it.")
.arg(m_javaPath),
.arg(javaPathSetting),
MessageLevel::Warning);
} else {
emit logLine(QString("The java binary \"%1\" couldn't be found. Please set up java in "
emit logLine(QString("The Java binary \"%1\" couldn't be found. Please set up Java in "
"the settings.")
.arg(m_javaPath),
.arg(javaPathSetting),
MessageLevel::Warning);
}
emitFailed(QString("Java path is not valid."));

View File

@ -1,32 +0,0 @@
#include "ColorCache.h"
/**
* Blend the color with the front color, adapting to the back color
*/
QColor ColorCache::blend(QColor color)
{
if (Rainbow::luma(m_front) > Rainbow::luma(m_back)) {
// for dark color schemes, produce a fitting color first
color = Rainbow::tint(m_front, color, 0.5);
}
// adapt contrast
return Rainbow::mix(m_front, color, m_bias);
}
/**
* Blend the color with the back color
*/
QColor ColorCache::blendBackground(QColor color)
{
// adapt contrast
return Rainbow::mix(m_back, color, m_bias);
}
void ColorCache::recolorAll()
{
auto iter = m_colors.begin();
while (iter != m_colors.end()) {
iter->front = blend(iter->original);
iter->back = blendBackground(iter->original);
}
}

View File

@ -1,106 +0,0 @@
#pragma once
#include <MessageLevel.h>
#include <rainbow.h>
#include <QMap>
#include <QtGui/QColor>
class ColorCache {
public:
ColorCache(QColor front, QColor back, qreal bias)
{
m_front = front;
m_back = back;
m_bias = bias;
};
void addColor(int key, QColor color) { m_colors[key] = { color, blend(color), blendBackground(color) }; }
void setForeground(QColor front)
{
if (m_front != front) {
m_front = front;
recolorAll();
}
}
void setBackground(QColor back)
{
if (m_back != back) {
m_back = back;
recolorAll();
}
}
QColor getFront(int key)
{
auto iter = m_colors.find(key);
if (iter == m_colors.end()) {
return QColor();
}
return (*iter).front;
}
QColor getBack(int key)
{
auto iter = m_colors.find(key);
if (iter == m_colors.end()) {
return QColor();
}
return (*iter).back;
}
/**
* Blend the color with the front color, adapting to the back color
*/
QColor blend(QColor color);
/**
* Blend the color with the back color
*/
QColor blendBackground(QColor color);
protected:
void recolorAll();
protected:
struct ColorEntry {
QColor original;
QColor front;
QColor back;
};
protected:
qreal m_bias;
QColor m_front;
QColor m_back;
QMap<int, ColorEntry> m_colors;
};
class LogColorCache : public ColorCache {
public:
LogColorCache(QColor front, QColor back) : ColorCache(front, back, 1.0)
{
addColor((int)MessageLevel::Launcher, QColor("purple"));
addColor((int)MessageLevel::Debug, QColor("green"));
addColor((int)MessageLevel::Warning, QColor("orange"));
addColor((int)MessageLevel::Error, QColor("red"));
addColor((int)MessageLevel::Fatal, QColor("red"));
addColor((int)MessageLevel::Message, front);
}
QColor getFront(MessageLevel::Enum level)
{
if (!m_colors.contains((int)level)) {
return ColorCache::getFront((int)MessageLevel::Message);
}
return ColorCache::getFront((int)level);
}
QColor getBack(MessageLevel::Enum level)
{
if (level == MessageLevel::Fatal) {
return QColor(Qt::black);
}
return QColor(Qt::transparent);
}
};

View File

@ -121,7 +121,7 @@ void VersionSelectDialog::setResizeOn(int column)
int VersionSelectDialog::exec()
{
QDialog::open();
m_versionWidget->initialize(m_vlist);
m_versionWidget->initialize(m_vlist, true);
m_versionWidget->selectSearch();
if (resizeOnColumn != -1) {
m_versionWidget->setResizeOn(resizeOnColumn);

View File

@ -33,7 +33,7 @@ class VersionSelectDialog : public QDialog {
public:
explicit VersionSelectDialog(BaseVersionList* vlist, QString title, QWidget* parent = 0, bool cancelable = true);
virtual ~VersionSelectDialog() {};
virtual ~VersionSelectDialog() = default;
int exec() override;

View File

@ -4,6 +4,7 @@
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (c) 2022 dada513 <dada513@protonmail.com>
* Copyright (C) 2022 Tayou <git@tayou.org>
* Copyright (C) 2024 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
@ -50,6 +51,7 @@
#include "DesktopServices.h"
#include "settings/SettingsObject.h"
#include "ui/themes/ITheme.h"
#include "ui/themes/ThemeManager.h"
#include "updater/ExternalUpdater.h"
#include <QApplication>
@ -66,9 +68,6 @@ enum InstSortMode {
LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::LauncherPage)
{
ui->setupUi(this);
auto origForeground = ui->fontPreview->palette().color(ui->fontPreview->foregroundRole());
auto origBackground = ui->fontPreview->palette().color(ui->fontPreview->backgroundRole());
m_colors.reset(new LogColorCache(origForeground, origBackground));
ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name);
ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch);
@ -80,8 +79,9 @@ LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::Launch
ui->updateSettingsBox->setHidden(!APPLICATION->updater());
connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
connect(ui->fontSizeBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &LauncherPage::refreshFontPreview);
connect(ui->consoleFont, &QFontComboBox::currentFontChanged, this, &LauncherPage::refreshFontPreview);
connect(ui->themeCustomizationWidget, &ThemeCustomizationWidget::currentWidgetThemeChanged, this, &LauncherPage::refreshFontPreview);
connect(ui->themeCustomizationWidget, &ThemeCustomizationWidget::currentCatChanged, APPLICATION, &Application::currentCatChanged);
}
@ -323,37 +323,47 @@ void LauncherPage::loadSettings()
void LauncherPage::refreshFontPreview()
{
const LogColors& colors = APPLICATION->themeManager()->getLogColors();
int fontSize = ui->fontSizeBox->value();
QString fontFamily = ui->consoleFont->currentFont().family();
ui->fontPreview->clear();
defaultFormat->setFont(QFont(fontFamily, fontSize));
{
auto print = [this, colors](const QString& message, MessageLevel::Enum level) {
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Error));
QColor bg = colors.background.value(level);
QColor fg = colors.foreground.value(level);
if (bg.isValid())
format.setBackground(bg);
if (fg.isValid())
format.setForeground(fg);
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Something/ERROR] A spooky error!"), format);
workCursor.insertText(message, format);
workCursor.insertBlock();
}
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Message));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Test/INFO] A harmless message..."), format);
workCursor.insertBlock();
}
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Warning));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Something/WARN] A not so spooky warning."), format);
workCursor.insertBlock();
}
};
print(QString("%1 version: %2 (%3)\n")
.arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString(), BuildConfig.BUILD_PLATFORM),
MessageLevel::Launcher);
QDate today = QDate::currentDate();
if (today.month() == 10 && today.day() == 31)
print(tr("[Test/ERROR] OOoooOOOoooo! A spooky error!"), MessageLevel::Error);
else
print(tr("[Test/ERROR] A spooky error!"), MessageLevel::Error);
print(tr("[Test/INFO] A harmless message..."), MessageLevel::Info);
print(tr("[Test/WARN] A not so spooky warning."), MessageLevel::Warning);
print(tr("[Test/DEBUG] A secret debugging message..."), MessageLevel::Debug);
print(tr("[Test/FATAL] A terrifying fatal error!"), MessageLevel::Fatal);
}
void LauncherPage::retranslate()

View File

@ -41,7 +41,6 @@
#include <Application.h>
#include <translations/TranslationsModel.h>
#include "java/JavaChecker.h"
#include "ui/ColorCache.h"
#include "ui/pages/BasePage.h"
class QTextCharFormat;
@ -94,7 +93,5 @@ class LauncherPage : public QWidget, public BasePage {
// default format for the font preview...
QTextCharFormat* defaultFormat;
std::unique_ptr<LogColorCache> m_colors;
std::shared_ptr<TranslationsModel> m_languageModel;
};

View File

@ -3,7 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* Copyright (C) 2024 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
@ -47,8 +47,8 @@
#include "launch/LaunchTask.h"
#include "settings/Setting.h"
#include "ui/ColorCache.h"
#include "ui/GuiUtil.h"
#include "ui/themes/ThemeManager.h"
#include <BuildConfig.h>
@ -57,26 +57,36 @@ class LogFormatProxyModel : public QIdentityProxyModel {
LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent) {}
QVariant data(const QModelIndex& index, int role) const override
{
const LogColors& colors = APPLICATION->themeManager()->getLogColors();
switch (role) {
case Qt::FontRole:
return m_font;
case Qt::ForegroundRole: {
MessageLevel::Enum level = (MessageLevel::Enum)QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getFront(level);
auto level = static_cast<MessageLevel::Enum>(QIdentityProxyModel::data(index, LogModel::LevelRole).toInt());
QColor result = colors.foreground.value(level);
if (result.isValid())
return result;
break;
}
case Qt::BackgroundRole: {
MessageLevel::Enum level = (MessageLevel::Enum)QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getBack(level);
auto level = static_cast<MessageLevel::Enum>(QIdentityProxyModel::data(index, LogModel::LevelRole).toInt());
QColor result = colors.background.value(level);
if (result.isValid())
return result;
break;
}
default:
return QIdentityProxyModel::data(index, role);
}
return QIdentityProxyModel::data(index, role);
}
void setFont(QFont font) { m_font = font; }
void setColors(LogColorCache* colors) { m_colors.reset(colors); }
QModelIndex find(const QModelIndex& start, const QString& value, bool reverse) const
{
QModelIndex parentIndex = parent(start);
@ -125,7 +135,6 @@ class LogFormatProxyModel : public QIdentityProxyModel {
private:
QFont m_font;
std::unique_ptr<LogColorCache> m_colors;
};
LogPage::LogPage(InstancePtr instance, QWidget* parent) : QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
@ -134,12 +143,6 @@ LogPage::LogPage(InstancePtr instance, QWidget* parent) : QWidget(parent), ui(ne
ui->tabWidget->tabBar()->hide();
m_proxy = new LogFormatProxyModel(this);
// set up text colors in the log proxy and adapt them to the current theme foreground and background
{
auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
m_proxy->setColors(new LogColorCache(origForeground, origBackground));
}
// set up fonts in the log proxy
{

View File

@ -46,11 +46,6 @@ QString BrightTheme::name()
return QObject::tr("Bright");
}
bool BrightTheme::hasColorScheme()
{
return true;
}
QPalette BrightTheme::colorScheme()
{
QPalette brightPalette;

View File

@ -45,7 +45,6 @@ class BrightTheme : public FusionTheme {
QString tooltip() override;
bool hasStyleSheet() override;
QString appStyleSheet() override;
bool hasColorScheme() override;
QPalette colorScheme() override;
double fadeAmount() override;
QColor fadeColor() override;

View File

@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2024 Tayou <git@tayou.org>
* Copyright (C) 2024 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
@ -39,121 +40,6 @@
const char* themeFile = "theme.json";
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()) {
try {
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 colorsRoot = Json::requireObject(root, "colors", "colors object");
auto readColor = [&](QString colorName) -> QColor {
auto colorValue = Json::ensureString(colorsRoot, colorName, QString());
if (!colorValue.isEmpty()) {
QColor color(colorValue);
if (!color.isValid()) {
themeWarningLog() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
return QColor();
}
return color;
}
return QColor();
};
auto readAndSetColor = [&](QPalette::ColorRole role, QString colorName) {
auto color = readColor(colorName);
if (color.isValid()) {
palette.setColor(role, color);
} else {
themeDebugLog() << "Color value for" << colorName << "was not present.";
}
};
// palette
readAndSetColor(QPalette::Window, "Window");
readAndSetColor(QPalette::WindowText, "WindowText");
readAndSetColor(QPalette::Base, "Base");
readAndSetColor(QPalette::AlternateBase, "AlternateBase");
readAndSetColor(QPalette::ToolTipBase, "ToolTipBase");
readAndSetColor(QPalette::ToolTipText, "ToolTipText");
readAndSetColor(QPalette::Text, "Text");
readAndSetColor(QPalette::Button, "Button");
readAndSetColor(QPalette::ButtonText, "ButtonText");
readAndSetColor(QPalette::BrightText, "BrightText");
readAndSetColor(QPalette::Link, "Link");
readAndSetColor(QPalette::Highlight, "Highlight");
readAndSetColor(QPalette::HighlightedText, "HighlightedText");
// fade
fadeColor = readColor("fadeColor");
fadeAmount = Json::ensureDouble(colorsRoot, "fadeAmount", 0.5, "fade amount");
} catch (const Exception& e) {
themeWarningLog() << "Couldn't load theme json: " << e.cause();
return false;
}
} else {
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,
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) { colorsObj.insert(colorName, palette.color(role).name()); };
// palette
insertColor(QPalette::Window, "Window");
insertColor(QPalette::WindowText, "WindowText");
insertColor(QPalette::Base, "Base");
insertColor(QPalette::AlternateBase, "AlternateBase");
insertColor(QPalette::ToolTipBase, "ToolTipBase");
insertColor(QPalette::ToolTipText, "ToolTipText");
insertColor(QPalette::Text, "Text");
insertColor(QPalette::Button, "Button");
insertColor(QPalette::ButtonText, "ButtonText");
insertColor(QPalette::BrightText, "BrightText");
insertColor(QPalette::Link, "Link");
insertColor(QPalette::Highlight, "Highlight");
insertColor(QPalette::HighlightedText, "HighlightedText");
// fade
colorsObj.insert("fadeColor", fadeColor.name());
colorsObj.insert("fadeAmount", fadeAmount);
rootObj.insert("colors", colorsObj);
try {
Json::write(rootObj, path);
return true;
} catch ([[maybe_unused]] const Exception& e) {
themeWarningLog() << "Failed to write theme json to" << path;
return false;
}
}
/// @param baseTheme Base Theme
/// @param fileInfo FileInfo object for file to load
/// @param isManifest whether to load a theme manifest or a qss file
@ -176,23 +62,22 @@ CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest
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_qssFilePath, jsonDataIncomplete)) {
bool hasCustomLogColors = false;
if (read(themeFilePath, hasCustomLogColors)) {
// If theme data was found, fade "Disabled" color of each role according to FadeAmount
m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
if (!hasCustomLogColors)
m_logColors = defaultLogColors(m_palette);
} else {
themeDebugLog() << "Did not read theme json file correctly, not changing theme, keeping previous.";
m_logColors = defaultLogColors(m_palette);
return;
}
// FIXME: This is kinda jank, it only actually checks if the qss file path is not present. It should actually check for any relevant
// missing data (e.g. name, colors)
if (jsonDataIncomplete) {
writeThemeJson(fileInfo.absoluteFilePath(), m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath);
}
auto qssFilePath = FS::PathCombine(path, m_qssFilePath);
QFileInfo info(qssFilePath);
if (info.isFile()) {
@ -251,11 +136,6 @@ QString CustomTheme::name()
return m_name;
}
bool CustomTheme::hasColorScheme()
{
return true;
}
QPalette CustomTheme::colorScheme()
{
return m_palette;
@ -289,3 +169,99 @@ QString CustomTheme::tooltip()
{
return m_tooltip;
}
bool CustomTheme::read(const QString& path, bool& hasCustomLogColors)
{
QFileInfo pathInfo(path);
if (pathInfo.exists() && pathInfo.isFile()) {
try {
auto doc = Json::requireDocument(path, "Theme JSON file");
const QJsonObject root = doc.object();
m_name = Json::requireString(root, "name", "Theme name");
m_widgets = Json::requireString(root, "widgets", "Qt widget theme");
m_qssFilePath = Json::ensureString(root, "qssFilePath", "themeStyle.css");
auto readColor = [&](const QJsonObject& colors, const QString& colorName) -> QColor {
auto colorValue = Json::ensureString(colors, colorName, QString());
if (!colorValue.isEmpty()) {
QColor color(colorValue);
if (!color.isValid()) {
themeWarningLog() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
return {};
}
return color;
}
return {};
};
if (root.contains("colors")) {
auto colorsRoot = Json::requireObject(root, "colors");
auto readAndSetPaletteColor = [&](QPalette::ColorRole role, const QString& colorName) {
auto color = readColor(colorsRoot, colorName);
if (color.isValid()) {
m_palette.setColor(role, color);
} else {
themeDebugLog() << "Color value for" << colorName << "was not present.";
}
};
// palette
readAndSetPaletteColor(QPalette::Window, "Window");
readAndSetPaletteColor(QPalette::WindowText, "WindowText");
readAndSetPaletteColor(QPalette::Base, "Base");
readAndSetPaletteColor(QPalette::AlternateBase, "AlternateBase");
readAndSetPaletteColor(QPalette::ToolTipBase, "ToolTipBase");
readAndSetPaletteColor(QPalette::ToolTipText, "ToolTipText");
readAndSetPaletteColor(QPalette::Text, "Text");
readAndSetPaletteColor(QPalette::Button, "Button");
readAndSetPaletteColor(QPalette::ButtonText, "ButtonText");
readAndSetPaletteColor(QPalette::BrightText, "BrightText");
readAndSetPaletteColor(QPalette::Link, "Link");
readAndSetPaletteColor(QPalette::Highlight, "Highlight");
readAndSetPaletteColor(QPalette::HighlightedText, "HighlightedText");
// fade
m_fadeColor = readColor(colorsRoot, "fadeColor");
m_fadeAmount = Json::ensureDouble(colorsRoot, "fadeAmount", 0.5, "fade amount");
}
if (root.contains("logColors")) {
hasCustomLogColors = true;
auto logColorsRoot = Json::requireObject(root, "logColors");
auto readAndSetLogColor = [&](MessageLevel::Enum level, bool fg, const QString& colorName) {
auto color = readColor(logColorsRoot, colorName);
if (color.isValid()) {
if (fg)
m_logColors.foreground[level] = color;
else
m_logColors.background[level] = color;
} else {
themeDebugLog() << "Color value for" << colorName << "was not present.";
}
};
readAndSetLogColor(MessageLevel::Message, false, "MessageHighlight");
readAndSetLogColor(MessageLevel::Launcher, false, "LauncherHighlight");
readAndSetLogColor(MessageLevel::Debug, false, "DebugHighlight");
readAndSetLogColor(MessageLevel::Warning, false, "WarningHighlight");
readAndSetLogColor(MessageLevel::Error, false, "ErrorHighlight");
readAndSetLogColor(MessageLevel::Fatal, false, "FatalHighlight");
readAndSetLogColor(MessageLevel::Message, true, "Message");
readAndSetLogColor(MessageLevel::Launcher, true, "Launcher");
readAndSetLogColor(MessageLevel::Debug, true, "Debug");
readAndSetLogColor(MessageLevel::Warning, true, "Warning");
readAndSetLogColor(MessageLevel::Error, true, "Error");
readAndSetLogColor(MessageLevel::Fatal, true, "Fatal");
}
} catch (const Exception& e) {
themeWarningLog() << "Couldn't load theme json: " << e.cause();
return false;
}
} else {
themeDebugLog() << "No theme json present.";
return false;
}
return true;
}

View File

@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2024 Tayou <git@tayou.org>
* Copyright (C) 2024 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
@ -47,14 +48,16 @@ class CustomTheme : public ITheme {
QString tooltip() override;
bool hasStyleSheet() override;
QString appStyleSheet() override;
bool hasColorScheme() override;
QPalette colorScheme() override;
double fadeAmount() override;
QColor fadeColor() override;
QString qtTheme() override;
LogColors logColorScheme() override { return m_logColors; }
QStringList searchPaths() override;
private: /* data */
private:
bool read(const QString& path, bool& hasCustomLogColors);
QPalette m_palette;
QColor m_fadeColor;
double m_fadeAmount;
@ -63,6 +66,7 @@ class CustomTheme : public ITheme {
QString m_id;
QString m_widgets;
QString m_qssFilePath;
LogColors m_logColors;
/**
* The tooltip could be defined in the theme json,
* or composed of other fields that could be in there.

View File

@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2024 Tayou <git@tayou.org>
* Copyright (C) 2024 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
@ -46,11 +47,6 @@ QString DarkTheme::name()
return QObject::tr("Dark");
}
bool DarkTheme::hasColorScheme()
{
return true;
}
QPalette DarkTheme::colorScheme()
{
QPalette darkPalette;
@ -90,6 +86,7 @@ QString DarkTheme::appStyleSheet()
{
return "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }";
}
QString DarkTheme::tooltip()
{
return "";

View File

@ -45,7 +45,6 @@ class DarkTheme : public FusionTheme {
QString tooltip() override;
bool hasStyleSheet() override;
QString appStyleSheet() override;
bool hasColorScheme() override;
QPalette colorScheme() override;
double fadeAmount() override;
QColor fadeColor() override;

View File

@ -44,9 +44,7 @@ void ITheme::apply(bool)
{
APPLICATION->setStyleSheet(QString());
QApplication::setStyle(new HintOverrideProxyStyle(QStyleFactory::create(qtTheme())));
if (hasColorScheme()) {
QApplication::setPalette(colorScheme());
}
QApplication::setPalette(colorScheme());
APPLICATION->setStyleSheet(appStyleSheet());
QDir::setSearchPaths("theme", searchPaths());
}
@ -73,3 +71,30 @@ QPalette ITheme::fadeInactive(QPalette in, qreal bias, QColor color)
blend(QPalette::HighlightedText);
return in;
}
LogColors ITheme::defaultLogColors(const QPalette& palette)
{
LogColors result;
const QColor& bg = palette.color(QPalette::Base);
const QColor& fg = palette.color(QPalette::Text);
auto blend = [bg, fg](QColor color) {
if (Rainbow::luma(fg) > Rainbow::luma(bg)) {
// for dark color schemes, produce a fitting color first
color = Rainbow::tint(fg, color, 0.5);
}
// adapt contrast
return Rainbow::mix(fg, color, 1);
};
result.background[MessageLevel::Fatal] = Qt::black;
result.foreground[MessageLevel::Launcher] = blend(QColor("purple"));
result.foreground[MessageLevel::Debug] = blend(QColor("green"));
result.foreground[MessageLevel::Warning] = blend(QColor("orange"));
result.foreground[MessageLevel::Error] = blend(QColor("red"));
result.foreground[MessageLevel::Fatal] = blend(QColor("red"));
return result;
}

View File

@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Tayou <git@tayou.org>
* Copyright (C) 2024 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
@ -33,11 +34,19 @@
* limitations under the License.
*/
#pragma once
#include <MessageLevel.h>
#include <QMap>
#include <QPalette>
#include <QString>
class QStyle;
struct LogColors {
QMap<MessageLevel::Enum, QColor> background;
QMap<MessageLevel::Enum, QColor> foreground;
};
// TODO: rename to Theme; this is not an interface as it contains method implementations
class ITheme {
public:
virtual ~ITheme() {}
@ -48,11 +57,12 @@ class ITheme {
virtual bool hasStyleSheet() = 0;
virtual QString appStyleSheet() = 0;
virtual QString qtTheme() = 0;
virtual bool hasColorScheme() = 0;
virtual QPalette colorScheme() = 0;
virtual QColor fadeColor() = 0;
virtual double fadeAmount() = 0;
virtual LogColors logColorScheme() { return defaultLogColors(colorScheme()); }
virtual QStringList searchPaths() { return {}; }
static QPalette fadeInactive(QPalette in, qreal bias, QColor color);
static LogColors defaultLogColors(const QPalette& palette);
};

View File

@ -125,8 +125,3 @@ bool SystemTheme::hasStyleSheet()
{
return false;
}
bool SystemTheme::hasColorScheme()
{
return true;
}

View File

@ -48,7 +48,6 @@ class SystemTheme : public ITheme {
QString qtTheme() override;
bool hasStyleSheet() override;
QString appStyleSheet() override;
bool hasColorScheme() override;
QPalette colorScheme() override;
double fadeAmount() override;
QColor fadeColor() override;

View File

@ -123,11 +123,11 @@ void ThemeManager::initializeWidgets()
{
themeDebugLog() << "Determining System Widget Theme...";
const auto& style = QApplication::style();
currentlySelectedSystemTheme = style->objectName();
themeDebugLog() << "System theme seems to be:" << currentlySelectedSystemTheme;
m_currentlySelectedSystemTheme = style->objectName();
themeDebugLog() << "System theme seems to be:" << m_currentlySelectedSystemTheme;
themeDebugLog() << "<> Initializing Widget Themes";
themeDebugLog() << "Loading Built-in Theme:" << addTheme(std::make_unique<SystemTheme>(currentlySelectedSystemTheme, true));
themeDebugLog() << "Loading Built-in Theme:" << addTheme(std::make_unique<SystemTheme>(m_currentlySelectedSystemTheme, true));
auto darkThemeId = addTheme(std::make_unique<DarkTheme>());
themeDebugLog() << "Loading Built-in Theme:" << darkThemeId;
themeDebugLog() << "Loading Built-in Theme:" << addTheme(std::make_unique<BrightTheme>());
@ -196,8 +196,8 @@ QList<ITheme*> ThemeManager::getValidApplicationThemes()
QList<CatPack*> ThemeManager::getValidCatPacks()
{
QList<CatPack*> ret;
ret.reserve(m_cat_packs.size());
for (auto&& [id, theme] : m_cat_packs) {
ret.reserve(m_catPacks.size());
for (auto&& [id, theme] : m_catPacks) {
ret.append(theme.get());
}
return ret;
@ -246,6 +246,8 @@ void ThemeManager::setApplicationTheme(const QString& name, bool initial)
auto& theme = themeIter->second;
themeDebugLog() << "applying theme" << theme->name();
theme->apply(initial);
m_logColors = theme->logColorScheme();
} else {
themeWarningLog() << "Tried to set invalid theme:" << name;
}
@ -258,7 +260,7 @@ void ThemeManager::applyCurrentlySelectedTheme(bool initial)
themeDebugLog() << "<> Icon theme set.";
auto applicationTheme = settings->get("ApplicationTheme").toString();
if (applicationTheme == "") {
applicationTheme = currentlySelectedSystemTheme;
applicationTheme = m_currentlySelectedSystemTheme;
}
setApplicationTheme(applicationTheme, initial);
themeDebugLog() << "<> Application theme set.";
@ -266,8 +268,8 @@ void ThemeManager::applyCurrentlySelectedTheme(bool initial)
QString ThemeManager::getCatPack(QString catName)
{
auto catIter = m_cat_packs.find(!catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString());
if (catIter != m_cat_packs.end()) {
auto catIter = m_catPacks.find(!catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString());
if (catIter != m_catPacks.end()) {
auto& catPack = catIter->second;
themeDebugLog() << "applying catpack" << catPack->id();
return catPack->path();
@ -275,14 +277,14 @@ QString ThemeManager::getCatPack(QString catName)
themeWarningLog() << "Tried to get invalid catPack:" << catName;
}
return m_cat_packs.begin()->second->path();
return m_catPacks.begin()->second->path();
}
QString ThemeManager::addCatPack(std::unique_ptr<CatPack> catPack)
{
QString id = catPack->id();
if (m_cat_packs.find(id) == m_cat_packs.end())
m_cat_packs.emplace(id, std::move(catPack));
if (m_catPacks.find(id) == m_catPacks.end())
m_catPacks.emplace(id, std::move(catPack));
else
themeWarningLog() << "CatPack(" << id << ") not added to prevent id duplication";
return id;
@ -340,8 +342,8 @@ void ThemeManager::refresh()
{
m_themes.clear();
m_icons.clear();
m_cat_packs.clear();
m_catPacks.clear();
initializeThemes();
initializeCatPacks();
};
}

View File

@ -2,7 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2024 Tayou <git@tayou.org>
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
* Copyright (C) 2024 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
@ -55,6 +55,8 @@ class ThemeManager {
QString getCatPack(QString catName = "");
QList<CatPack*> getValidCatPacks();
const LogColors& getLogColors() { return m_logColors; }
void refresh();
private:
@ -63,8 +65,9 @@ class ThemeManager {
QDir m_iconThemeFolder{ "iconthemes" };
QDir m_applicationThemeFolder{ "themes" };
QDir m_catPacksFolder{ "catpacks" };
std::map<QString, std::unique_ptr<CatPack>> m_cat_packs;
QString currentlySelectedSystemTheme;
std::map<QString, std::unique_ptr<CatPack>> m_catPacks;
QString m_currentlySelectedSystemTheme;
LogColors m_logColors;
void initializeThemes();
void initializeCatPacks();

View File

@ -105,14 +105,14 @@ bool VersionSelectWidget::eventFilter(QObject* watched, QEvent* event)
return QObject::eventFilter(watched, event);
}
void VersionSelectWidget::initialize(BaseVersionList* vlist)
void VersionSelectWidget::initialize(BaseVersionList* vlist, bool forceLoad)
{
m_vlist = vlist;
m_proxyModel->setSourceModel(vlist);
listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
if (!m_vlist->isLoaded()) {
if (!m_vlist->isLoaded() || forceLoad) {
loadList();
} else {
if (m_proxyModel->rowCount() == 0) {

View File

@ -54,7 +54,7 @@ class VersionSelectWidget : public QWidget {
~VersionSelectWidget();
//! loads the list if needed.
void initialize(BaseVersionList* vlist);
void initialize(BaseVersionList* vlist, bool forceLoad = false);
//! Starts a task that loads the list.
void loadList();