Merge pull request #249 from TayouVR/theme-selector-first-time-wizard

This commit is contained in:
flow 2023-01-10 13:28:57 -03:00 committed by GitHub
commit 96d5438633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1233 additions and 545 deletions

View File

@ -66,6 +66,7 @@
#include "ui/setupwizard/LanguageWizardPage.h" #include "ui/setupwizard/LanguageWizardPage.h"
#include "ui/setupwizard/JavaWizardPage.h" #include "ui/setupwizard/JavaWizardPage.h"
#include "ui/setupwizard/PasteWizardPage.h" #include "ui/setupwizard/PasteWizardPage.h"
#include "ui/setupwizard/ThemeWizardPage.h"
#include "ui/dialogs/CustomMessageBox.h" #include "ui/dialogs/CustomMessageBox.h"
@ -497,7 +498,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// Theming // Theming
m_settings->registerSetting("IconTheme", QString("pe_colored")); m_settings->registerSetting("IconTheme", QString("pe_colored"));
m_settings->registerSetting("ApplicationTheme", QString("system")); m_settings->registerSetting("ApplicationTheme", QString());
m_settings->registerSetting("BackgroundCat", QString("kitteh")); m_settings->registerSetting("BackgroundCat", QString("kitteh"));
// Remembered state // Remembered state
@ -846,10 +847,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
}); });
{ {
setIconTheme(settings()->get("IconTheme").toString()); applyCurrentlySelectedTheme();
qDebug() << "<> Icon theme set.";
setApplicationTheme(settings()->get("ApplicationTheme").toString(), true);
qDebug() << "<> Application theme set.";
} }
updateCapabilities(); updateCapabilities();
@ -892,7 +890,8 @@ bool Application::createSetupWizard()
return false; return false;
}(); }();
bool pasteInterventionRequired = settings()->get("PastebinURL") != ""; bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired; bool themeInterventionRequired = settings()->get("ApplicationTheme") == "";
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired;
if(wizardRequired) if(wizardRequired)
{ {
@ -911,6 +910,12 @@ bool Application::createSetupWizard()
{ {
m_setupWizard->addPage(new PasteWizardPage(m_setupWizard)); m_setupWizard->addPage(new PasteWizardPage(m_setupWizard));
} }
if (themeInterventionRequired)
{
settings()->set("ApplicationTheme", QString("system")); // set default theme after going into theme wizard
m_setupWizard->addPage(new ThemeWizardPage(m_setupWizard));
}
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished); connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
m_setupWizard->show(); m_setupWizard->show();
return true; return true;
@ -1118,9 +1123,14 @@ QList<ITheme*> Application::getValidApplicationThemes()
return m_themeManager->getValidApplicationThemes(); return m_themeManager->getValidApplicationThemes();
} }
void Application::setApplicationTheme(const QString& name, bool initial) void Application::applyCurrentlySelectedTheme()
{ {
m_themeManager->setApplicationTheme(name, initial); m_themeManager->applyCurrentlySelectedTheme();
}
void Application::setApplicationTheme(const QString& name)
{
m_themeManager->setApplicationTheme(name);
} }
void Application::setIconTheme(const QString& name) void Application::setIconTheme(const QString& name)

View File

@ -120,9 +120,11 @@ public:
void setIconTheme(const QString& name); void setIconTheme(const QString& name);
void applyCurrentlySelectedTheme();
QList<ITheme*> getValidApplicationThemes(); QList<ITheme*> getValidApplicationThemes();
void setApplicationTheme(const QString& name, bool initial); void setApplicationTheme(const QString& name);
shared_qobject_ptr<UpdateChecker> updateChecker() { shared_qobject_ptr<UpdateChecker> updateChecker() {
return m_updateChecker; return m_updateChecker;

View File

@ -683,6 +683,8 @@ SET(LAUNCHER_SOURCES
ui/setupwizard/LanguageWizardPage.h ui/setupwizard/LanguageWizardPage.h
ui/setupwizard/PasteWizardPage.cpp ui/setupwizard/PasteWizardPage.cpp
ui/setupwizard/PasteWizardPage.h ui/setupwizard/PasteWizardPage.h
ui/setupwizard/ThemeWizardPage.cpp
ui/setupwizard/ThemeWizardPage.h
# GUI - themes # GUI - themes
ui/themes/FusionTheme.cpp ui/themes/FusionTheme.cpp
@ -922,6 +924,8 @@ SET(LAUNCHER_SOURCES
ui/widgets/ProgressWidget.cpp ui/widgets/ProgressWidget.cpp
ui/widgets/WideBar.h ui/widgets/WideBar.h
ui/widgets/WideBar.cpp ui/widgets/WideBar.cpp
ui/widgets/ThemeCustomizationWidget.h
ui/widgets/ThemeCustomizationWidget.cpp
# GUI - instance group view # GUI - instance group view
ui/instanceview/InstanceProxyModel.cpp ui/instanceview/InstanceProxyModel.cpp
@ -939,6 +943,7 @@ SET(LAUNCHER_SOURCES
qt_wrap_ui(LAUNCHER_UI qt_wrap_ui(LAUNCHER_UI
ui/setupwizard/PasteWizardPage.ui ui/setupwizard/PasteWizardPage.ui
ui/setupwizard/ThemeWizardPage.ui
ui/pages/global/AccountListPage.ui ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui ui/pages/global/JavaPage.ui
ui/pages/global/LauncherPage.ui ui/pages/global/LauncherPage.ui
@ -971,6 +976,7 @@ qt_wrap_ui(LAUNCHER_UI
ui/widgets/CustomCommands.ui ui/widgets/CustomCommands.ui
ui/widgets/InfoFrame.ui ui/widgets/InfoFrame.ui
ui/widgets/ModFilterWidget.ui ui/widgets/ModFilterWidget.ui
ui/widgets/ThemeCustomizationWidget.ui
ui/dialogs/CopyInstanceDialog.ui ui/dialogs/CopyInstanceDialog.ui
ui/dialogs/ProfileSetupDialog.ui ui/dialogs/ProfileSetupDialog.ui
ui/dialogs/ProgressDialog.ui ui/dialogs/ProgressDialog.ui

View File

@ -111,6 +111,7 @@
#include "ui/dialogs/ExportInstanceDialog.h" #include "ui/dialogs/ExportInstanceDialog.h"
#include "ui/dialogs/ImportResourcePackDialog.h" #include "ui/dialogs/ImportResourcePackDialog.h"
#include "ui/themes/ITheme.h" #include "ui/themes/ITheme.h"
#include "ui/themes/ThemeManager.h"
#include <minecraft/mod/ResourcePackFolderModel.h> #include <minecraft/mod/ResourcePackFolderModel.h>
#include <minecraft/mod/tasks/LocalResourcePackParseTask.h> #include <minecraft/mod/tasks/LocalResourcePackParseTask.h>
@ -1346,7 +1347,7 @@ void MainWindow::updateThemeMenu()
themeAction->setActionGroup(themesGroup); themeAction->setActionGroup(themesGroup);
connect(themeAction, &QAction::triggered, [theme]() { connect(themeAction, &QAction::triggered, [theme]() {
APPLICATION->setApplicationTheme(theme->id(),false); APPLICATION->setApplicationTheme(theme->id());
APPLICATION->settings()->set("ApplicationTheme", theme->id()); APPLICATION->settings()->set("ApplicationTheme", theme->id());
}); });
} }
@ -1652,32 +1653,9 @@ void MainWindow::onCatToggled(bool state)
APPLICATION->settings()->set("TheCat", state); APPLICATION->settings()->set("TheCat", state);
} }
namespace {
template <typename T>
T non_stupid_abs(T in)
{
if (in < 0)
return -in;
return in;
}
}
void MainWindow::setCatBackground(bool enabled) void MainWindow::setCatBackground(bool enabled)
{ {
if (enabled) if (enabled) {
{
QDateTime now = QDateTime::currentDateTime();
QDateTime birthday(QDate(now.date().year(), 11, 30), QTime(0, 0));
QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0));
QDateTime halloween(QDate(now.date().year(), 10, 31), QTime(0, 0));
QString cat = APPLICATION->settings()->get("BackgroundCat").toString();
if (non_stupid_abs(now.daysTo(xmas)) <= 4) {
cat += "-xmas";
} else if (non_stupid_abs(now.daysTo(halloween)) <= 4) {
cat += "-spooky";
} else if (non_stupid_abs(now.daysTo(birthday)) <= 12) {
cat += "-bday";
}
view->setStyleSheet(QString(R"( view->setStyleSheet(QString(R"(
InstanceView InstanceView
{ {
@ -1688,10 +1666,8 @@ InstanceView
background-repeat: none; background-repeat: none;
background-color:palette(base); background-color:palette(base);
})") })")
.arg(cat)); .arg(ThemeManager::getCatImage()));
} } else {
else
{
view->setStyleSheet(QString()); view->setStyleSheet(QString());
} }
} }

View File

@ -286,75 +286,6 @@ void LauncherPage::applySettings()
} }
s->set("UpdateChannel", m_currentUpdateChannel); s->set("UpdateChannel", m_currentUpdateChannel);
auto original = s->get("IconTheme").toString();
//FIXME: make generic
switch (ui->themeComboBox->currentIndex())
{
case 0:
s->set("IconTheme", "pe_colored");
break;
case 1:
s->set("IconTheme", "pe_light");
break;
case 2:
s->set("IconTheme", "pe_dark");
break;
case 3:
s->set("IconTheme", "pe_blue");
break;
case 4:
s->set("IconTheme", "breeze_light");
break;
case 5:
s->set("IconTheme", "breeze_dark");
break;
case 6:
s->set("IconTheme", "OSX");
break;
case 7:
s->set("IconTheme", "iOS");
break;
case 8:
s->set("IconTheme", "flat");
break;
case 9:
s->set("IconTheme", "flat_white");
break;
case 10:
s->set("IconTheme", "multimc");
break;
case 11:
s->set("IconTheme", "custom");
break;
}
if(original != s->get("IconTheme"))
{
APPLICATION->setIconTheme(s->get("IconTheme").toString());
}
auto originalAppTheme = s->get("ApplicationTheme").toString();
auto newAppTheme = ui->themeComboBoxColors->currentData().toString();
if(originalAppTheme != newAppTheme)
{
s->set("ApplicationTheme", newAppTheme);
APPLICATION->setApplicationTheme(newAppTheme, false);
}
switch (ui->themeBackgroundCat->currentIndex()) {
case 0: // original cat
s->set("BackgroundCat", "kitteh");
break;
case 1: // rory the cat
s->set("BackgroundCat", "rory");
break;
case 2: // rory the cat flat edition
s->set("BackgroundCat", "rory-flat");
break;
case 3: // teawie
s->set("BackgroundCat", "teawie");
break;
}
s->set("MenuBarInsteadOfToolBar", ui->preferMenuBarCheckBox->isChecked()); s->set("MenuBarInsteadOfToolBar", ui->preferMenuBarCheckBox->isChecked());
@ -404,47 +335,6 @@ void LauncherPage::loadSettings()
} }
m_currentUpdateChannel = s->get("UpdateChannel").toString(); m_currentUpdateChannel = s->get("UpdateChannel").toString();
//FIXME: make generic
auto theme = s->get("IconTheme").toString();
QStringList iconThemeOptions{"pe_colored",
"pe_light",
"pe_dark",
"pe_blue",
"breeze_light",
"breeze_dark",
"OSX",
"iOS",
"flat",
"flat_white",
"multimc",
"custom"};
ui->themeComboBox->setCurrentIndex(iconThemeOptions.indexOf(theme));
auto cat = s->get("BackgroundCat").toString();
if (cat == "kitteh") {
ui->themeBackgroundCat->setCurrentIndex(0);
} else if (cat == "rory") {
ui->themeBackgroundCat->setCurrentIndex(1);
} else if (cat == "rory-flat") {
ui->themeBackgroundCat->setCurrentIndex(2);
} else if (cat == "teawie") {
ui->themeBackgroundCat->setCurrentIndex(3);
}
{
auto currentTheme = s->get("ApplicationTheme").toString();
auto themes = APPLICATION->getValidApplicationThemes();
int idx = 0;
for(auto &theme: themes)
{
ui->themeComboBoxColors->addItem(theme->name(), theme->id());
if(currentTheme == theme->id())
{
ui->themeComboBoxColors->setCurrentIndex(idx);
}
idx++;
}
}
// Toolbar/menu bar settings (not applicable if native menu bar is present) // Toolbar/menu bar settings (not applicable if native menu bar is present)
ui->toolsBox->setEnabled(!QMenuBar().isNativeMenuBar()); ui->toolsBox->setEnabled(!QMenuBar().isNativeMenuBar());

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>514</width> <width>511</width>
<height>629</height> <height>629</height>
</rect> </rect>
</property> </property>
@ -38,7 +38,7 @@
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="featuresTab"> <widget class="QWidget" name="featuresTab">
<attribute name="title"> <attribute name="title">
@ -243,155 +243,9 @@
<property name="title"> <property name="title">
<string>Theme</string> <string>Theme</string>
</property> </property>
<layout class="QFormLayout" name="formLayout"> <layout class="QVBoxLayout" name="verticalLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&amp;Icons</string>
</property>
<property name="buddy">
<cstring>themeComboBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="themeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<item> <item>
<property name="text"> <widget class="ThemeCustomizationWidget" name="themeCustomizationWidget" native="true"/>
<string>Simple (Colored Icons)</string>
</property>
</item>
<item>
<property name="text">
<string>Simple (Light Icons)</string>
</property>
</item>
<item>
<property name="text">
<string>Simple (Dark Icons)</string>
</property>
</item>
<item>
<property name="text">
<string>Simple (Blue Icons)</string>
</property>
</item>
<item>
<property name="text">
<string>Breeze Light</string>
</property>
</item>
<item>
<property name="text">
<string>Breeze Dark</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">OSX</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">iOS</string>
</property>
</item>
<item>
<property name="text">
<string>Flat</string>
</property>
</item>
<item>
<property name="text">
<string>Flat (White)</string>
</property>
</item>
<item>
<property name="text">
<string>Legacy</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Colors</string>
</property>
<property name="buddy">
<cstring>themeComboBoxColors</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="themeComboBoxColors">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>C&amp;at</string>
</property>
<property name="buddy">
<cstring>themeBackgroundCat</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="themeBackgroundCat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<item>
<property name="text">
<string>Background Cat (from MultiMC)</string>
</property>
</item>
<item>
<property name="text">
<string>Rory ID 11 (drawn by Ashtaka)</string>
</property>
</item>
<item>
<property name="text">
<string>Rory ID 11 (flat edition, drawn by Ashtaka)</string>
</property>
</item>
<item>
<property name="text">
<string>Teawie (drawn by SympathyTea)</string>
</property>
</item>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -575,6 +429,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>ThemeCustomizationWidget</class>
<extends>QWidget</extends>
<header>ui/widgets/ThemeCustomizationWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>tabWidget</tabstop> <tabstop>tabWidget</tabstop>
<tabstop>autoUpdateCheckBox</tabstop> <tabstop>autoUpdateCheckBox</tabstop>
@ -587,8 +449,6 @@
<tabstop>iconsDirBrowseBtn</tabstop> <tabstop>iconsDirBrowseBtn</tabstop>
<tabstop>sortLastLaunchedBtn</tabstop> <tabstop>sortLastLaunchedBtn</tabstop>
<tabstop>sortByNameBtn</tabstop> <tabstop>sortByNameBtn</tabstop>
<tabstop>themeComboBox</tabstop>
<tabstop>themeComboBoxColors</tabstop>
<tabstop>showConsoleCheck</tabstop> <tabstop>showConsoleCheck</tabstop>
<tabstop>autoCloseConsoleCheck</tabstop> <tabstop>autoCloseConsoleCheck</tabstop>
<tabstop>showConsoleErrorCheck</tabstop> <tabstop>showConsoleErrorCheck</tabstop>

View File

@ -13,7 +13,8 @@
SetupWizard::SetupWizard(QWidget *parent) : QWizard(parent) SetupWizard::SetupWizard(QWidget *parent) : QWizard(parent)
{ {
setObjectName(QStringLiteral("SetupWizard")); setObjectName(QStringLiteral("SetupWizard"));
resize(615, 659); resize(620, 660);
setMinimumSize(300, 400);
// make it ugly everywhere to avoid variability in theming // make it ugly everywhere to avoid variability in theming
setWizardStyle(QWizard::ClassicStyle); setWizardStyle(QWizard::ClassicStyle);
setOptions(QWizard::NoCancelButton | QWizard::IndependentPages | QWizard::HaveCustomButton1); setOptions(QWizard::NoCancelButton | QWizard::IndependentPages | QWizard::HaveCustomButton1);

View File

@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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 "ThemeWizardPage.h"
#include "ui_ThemeWizardPage.h"
#include "Application.h"
#include "ui/themes/ITheme.h"
#include "ui/themes/ThemeManager.h"
#include "ui/widgets/ThemeCustomizationWidget.h"
#include "ui_ThemeCustomizationWidget.h"
ThemeWizardPage::ThemeWizardPage(QWidget* parent) : BaseWizardPage(parent), ui(new Ui::ThemeWizardPage)
{
ui->setupUi(this);
connect(ui->themeCustomizationWidget, &ThemeCustomizationWidget::currentIconThemeChanged, this, &ThemeWizardPage::updateIcons);
connect(ui->themeCustomizationWidget, &ThemeCustomizationWidget::currentCatChanged, this, &ThemeWizardPage::updateCat);
updateIcons();
updateCat();
}
ThemeWizardPage::~ThemeWizardPage()
{
delete ui;
}
void ThemeWizardPage::updateIcons()
{
qDebug() << "Setting Icons";
ui->previewIconButton0->setIcon(APPLICATION->getThemedIcon("new"));
ui->previewIconButton1->setIcon(APPLICATION->getThemedIcon("centralmods"));
ui->previewIconButton2->setIcon(APPLICATION->getThemedIcon("viewfolder"));
ui->previewIconButton3->setIcon(APPLICATION->getThemedIcon("launch"));
ui->previewIconButton4->setIcon(APPLICATION->getThemedIcon("copy"));
ui->previewIconButton5->setIcon(APPLICATION->getThemedIcon("export"));
ui->previewIconButton6->setIcon(APPLICATION->getThemedIcon("delete"));
ui->previewIconButton7->setIcon(APPLICATION->getThemedIcon("about"));
ui->previewIconButton8->setIcon(APPLICATION->getThemedIcon("settings"));
ui->previewIconButton9->setIcon(APPLICATION->getThemedIcon("cat"));
update();
repaint();
parentWidget()->update();
}
void ThemeWizardPage::updateCat()
{
qDebug() << "Setting Cat";
ui->catImagePreviewButton->setIcon(QIcon(QString(R"(:/backgrounds/%1)").arg(ThemeManager::getCatImage())));
}
void ThemeWizardPage::retranslate()
{
ui->retranslateUi(this);
}

View File

@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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/>.
*/
#pragma once
#include <QWidget>
#include "BaseWizardPage.h"
namespace Ui {
class ThemeWizardPage;
}
class ThemeWizardPage : public BaseWizardPage {
Q_OBJECT
public:
explicit ThemeWizardPage(QWidget* parent = nullptr);
~ThemeWizardPage();
bool validatePage() override { return true; };
void retranslate() override;
private slots:
void updateIcons();
void updateCat();
private:
Ui::ThemeWizardPage* ui;
};

View File

@ -0,0 +1,371 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ThemeWizardPage</class>
<widget class="QWizardPage" name="ThemeWizardPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>510</width>
<height>552</height>
</rect>
</property>
<property name="windowTitle">
<string>WizardPage</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Select the Theme you wish to use</string>
</property>
</widget>
</item>
<item>
<widget class="ThemeCustomizationWidget" name="themeCustomizationWidget" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Hint: The cat appears in the background and is not shown by default. It is only made visible when pressing the Cat button in the Toolbar.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string> Preview:</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="iconPreview">
<item row="0" column="2">
<widget class="QPushButton" name="previewIconButton2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QPushButton" name="previewIconButton5">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QPushButton" name="previewIconButton7">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="previewIconButton4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="previewIconButton1">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="centralmods">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="previewIconButton0">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="9">
<widget class="QPushButton" name="previewIconButton9">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="viewfolder">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QPushButton" name="previewIconButton6">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="new">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="previewIconButton3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="8">
<widget class="QPushButton" name="previewIconButton8">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="icon">
<iconset theme="applications-engineering">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="catImagePreviewButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>256</height>
</size>
</property>
<property name="toolTip">
<string>The cat appears in the background and does not serve a purpose, it is purely visual.</string>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>256</width>
<height>256</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>193</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ThemeCustomizationWidget</class>
<extends>QWidget</extends>
<header>ui/widgets/ThemeCustomizationWidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -167,8 +167,6 @@ CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest
if (!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources)) { if (!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources)) {
themeWarningLog() << "couldn't create folder for theme!"; themeWarningLog() << "couldn't create folder for theme!";
m_palette = baseTheme->colorScheme();
m_styleSheet = baseTheme->appStyleSheet();
return; return;
} }
@ -177,18 +175,15 @@ CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest
bool jsonDataIncomplete = false; bool jsonDataIncomplete = false;
m_palette = baseTheme->colorScheme(); m_palette = baseTheme->colorScheme();
if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath, jsonDataIncomplete)) { 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; // If theme data was found, fade "Disabled" color of each role according to FadeAmount
m_name = "Custom";
m_palette = baseTheme->colorScheme();
m_fadeColor = baseTheme->fadeColor();
m_fadeAmount = baseTheme->fadeAmount();
m_widgets = baseTheme->qtTheme();
m_qssFilePath = "themeStyle.css";
} else {
m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor); m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
} else {
themeDebugLog() << "Did not read theme json file correctly, not changing theme, keeping previous.";
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) { if (jsonDataIncomplete) {
writeThemeJson(fileInfo.absoluteFilePath(), m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath); writeThemeJson(fileInfo.absoluteFilePath(), m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath);
} }
@ -197,20 +192,14 @@ CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest
QFileInfo info(qssFilePath); QFileInfo info(qssFilePath);
if (info.isFile()) { if (info.isFile()) {
try { try {
// TODO: validate css? // TODO: validate qss?
m_styleSheet = QString::fromUtf8(FS::read(qssFilePath)); m_styleSheet = QString::fromUtf8(FS::read(qssFilePath));
} catch (const Exception& e) { } catch (const Exception& e) {
themeWarningLog() << "Couldn't load css:" << e.cause() << "from" << qssFilePath; themeWarningLog() << "Couldn't load qss:" << e.cause() << "from" << qssFilePath;
m_styleSheet = baseTheme->appStyleSheet(); return;
} }
} else { } else {
themeDebugLog() << "No theme css present."; themeDebugLog() << "No theme qss present.";
m_styleSheet = baseTheme->appStyleSheet();
try {
FS::write(qssFilePath, m_styleSheet.toUtf8());
} catch (const Exception& e) {
themeWarningLog() << "Couldn't write css:" << e.cause() << "to" << qssFilePath;
}
} }
} else { } else {
m_id = fileInfo.fileName(); m_id = fileInfo.fileName();

View File

@ -1,19 +1,51 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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
*
* 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 "ITheme.h" #include "ITheme.h"
#include "rainbow.h" #include "rainbow.h"
#include <QStyleFactory> #include <QStyleFactory>
#include <QDir> #include <QDir>
#include "Application.h" #include "Application.h"
void ITheme::apply(bool) void ITheme::apply()
{ {
APPLICATION->setStyleSheet(QString()); APPLICATION->setStyleSheet(QString());
QApplication::setStyle(QStyleFactory::create(qtTheme())); QApplication::setStyle(QStyleFactory::create(qtTheme()));
if (hasColorScheme()) { if (hasColorScheme()) {
QApplication::setPalette(colorScheme()); QApplication::setPalette(colorScheme());
} }
if (hasStyleSheet())
APPLICATION->setStyleSheet(appStyleSheet()); APPLICATION->setStyleSheet(appStyleSheet());
QDir::setSearchPaths("theme", searchPaths()); QDir::setSearchPaths("theme", searchPaths());
} }

View File

@ -1,14 +1,47 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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
*
* 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 #pragma once
#include <QString>
#include <QPalette> #include <QPalette>
#include <QString>
class QStyle; class QStyle;
class ITheme class ITheme {
{
public: public:
virtual ~ITheme() {} virtual ~ITheme() {}
virtual void apply(bool initial); virtual void apply();
virtual QString id() = 0; virtual QString id() = 0;
virtual QString name() = 0; virtual QString name() = 0;
virtual bool hasStyleSheet() = 0; virtual bool hasStyleSheet() = 0;
@ -18,10 +51,7 @@ public:
virtual QPalette colorScheme() = 0; virtual QPalette colorScheme() = 0;
virtual QColor fadeColor() = 0; virtual QColor fadeColor() = 0;
virtual double fadeAmount() = 0; virtual double fadeAmount() = 0;
virtual QStringList searchPaths() virtual QStringList searchPaths() { return {}; }
{
return {};
}
static QPalette fadeInactive(QPalette in, qreal bias, QColor color); static QPalette fadeInactive(QPalette in, qreal bias, QColor color);
}; };

View File

@ -34,9 +34,9 @@
*/ */
#include "SystemTheme.h" #include "SystemTheme.h"
#include <QApplication> #include <QApplication>
#include <QDebug>
#include <QStyle> #include <QStyle>
#include <QStyleFactory> #include <QStyleFactory>
#include <QDebug>
#include "ThemeManager.h" #include "ThemeManager.h"
SystemTheme::SystemTheme() SystemTheme::SystemTheme()
@ -47,11 +47,9 @@ SystemTheme::SystemTheme()
QString lowerThemeName = style->objectName(); QString lowerThemeName = style->objectName();
themeDebugLog() << "System theme seems to be:" << lowerThemeName; themeDebugLog() << "System theme seems to be:" << lowerThemeName;
QStringList styles = QStyleFactory::keys(); QStringList styles = QStyleFactory::keys();
for(auto &st: styles) for (auto& st : styles) {
{
themeDebugLog() << "Considering theme from theme factory:" << st.toLower(); themeDebugLog() << "Considering theme from theme factory:" << st.toLower();
if(st.toLower() == lowerThemeName) if (st.toLower() == lowerThemeName) {
{
systemTheme = st; systemTheme = st;
themeDebugLog() << "System theme has been determined to be:" << systemTheme; themeDebugLog() << "System theme has been determined to be:" << systemTheme;
return; return;
@ -62,14 +60,9 @@ SystemTheme::SystemTheme()
themeDebugLog() << "System theme not found, defaulted to Fusion"; themeDebugLog() << "System theme not found, defaulted to Fusion";
} }
void SystemTheme::apply(bool initial) void SystemTheme::apply()
{ {
// if we are applying the system theme as the first theme, just don't touch anything. it's for the better... ITheme::apply();
if(initial)
{
return;
}
ITheme::apply(initial);
} }
QString SystemTheme::id() QString SystemTheme::id()

View File

@ -1,13 +1,46 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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
*
* 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 #pragma once
#include "ITheme.h" #include "ITheme.h"
class SystemTheme: public ITheme class SystemTheme : public ITheme {
{
public: public:
SystemTheme(); SystemTheme();
virtual ~SystemTheme() {} virtual ~SystemTheme() {}
void apply(bool initial) override; void apply() override;
QString id() override; QString id() override;
QString name() override; QString name() override;
@ -18,6 +51,7 @@ public:
QPalette colorScheme() override; QPalette colorScheme() override;
double fadeAmount() override; double fadeAmount() override;
QColor fadeColor() override; QColor fadeColor() override;
private: private:
QPalette systemPalette; QPalette systemPalette;
QString systemTheme; QString systemTheme;

View File

@ -31,13 +31,13 @@
ThemeManager::ThemeManager(MainWindow* mainWindow) ThemeManager::ThemeManager(MainWindow* mainWindow)
{ {
m_mainWindow = mainWindow; m_mainWindow = mainWindow;
InitializeThemes(); initializeThemes();
} }
/// @brief Adds the Theme to the list of themes /// @brief Adds the Theme to the list of themes
/// @param theme The Theme to add /// @param theme The Theme to add
/// @return Theme ID /// @return Theme ID
QString ThemeManager::AddTheme(std::unique_ptr<ITheme> theme) QString ThemeManager::addTheme(std::unique_ptr<ITheme> theme)
{ {
QString id = theme->id(); QString id = theme->id();
m_themes.emplace(id, std::move(theme)); m_themes.emplace(id, std::move(theme));
@ -47,12 +47,12 @@ QString ThemeManager::AddTheme(std::unique_ptr<ITheme> theme)
/// @brief Gets the Theme from the List via ID /// @brief Gets the Theme from the List via ID
/// @param themeId Theme ID of theme to fetch /// @param themeId Theme ID of theme to fetch
/// @return Theme at themeId /// @return Theme at themeId
ITheme* ThemeManager::GetTheme(QString themeId) ITheme* ThemeManager::getTheme(QString themeId)
{ {
return m_themes[themeId].get(); return m_themes[themeId].get();
} }
void ThemeManager::InitializeThemes() void ThemeManager::initializeThemes()
{ {
// Icon themes // Icon themes
{ {
@ -67,10 +67,10 @@ void ThemeManager::InitializeThemes()
// Initialize widget themes // Initialize widget themes
{ {
themeDebugLog() << "<> Initializing Widget Themes"; themeDebugLog() << "<> Initializing Widget Themes";
themeDebugLog() << "Loading Built-in Theme:" << AddTheme(std::make_unique<SystemTheme>()); themeDebugLog() << "Loading Built-in Theme:" << addTheme(std::make_unique<SystemTheme>());
auto darkThemeId = AddTheme(std::make_unique<DarkTheme>()); auto darkThemeId = addTheme(std::make_unique<DarkTheme>());
themeDebugLog() << "Loading Built-in Theme:" << darkThemeId; themeDebugLog() << "Loading Built-in Theme:" << darkThemeId;
themeDebugLog() << "Loading Built-in Theme:" << AddTheme(std::make_unique<BrightTheme>()); 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 // TODO: need some way to differentiate same name themes in different subdirectories (maybe smaller grey text next to theme name in
// dropdown?) // dropdown?)
@ -84,7 +84,7 @@ void ThemeManager::InitializeThemes()
if (themeJson.exists()) { if (themeJson.exists()) {
// Load "theme.json" based themes // Load "theme.json" based themes
themeDebugLog() << "Loading JSON Theme from:" << themeJson.absoluteFilePath(); themeDebugLog() << "Loading JSON Theme from:" << themeJson.absoluteFilePath();
AddTheme(std::make_unique<CustomTheme>(GetTheme(darkThemeId), themeJson, true)); addTheme(std::make_unique<CustomTheme>(getTheme(darkThemeId), themeJson, true));
} else { } else {
// Load pure QSS Themes // Load pure QSS Themes
QDirIterator stylesheetFileIterator(dir.absoluteFilePath(""), { "*.qss", "*.css" }, QDir::Files); QDirIterator stylesheetFileIterator(dir.absoluteFilePath(""), { "*.qss", "*.css" }, QDir::Files);
@ -92,7 +92,7 @@ void ThemeManager::InitializeThemes()
QFile customThemeFile(stylesheetFileIterator.next()); QFile customThemeFile(stylesheetFileIterator.next());
QFileInfo customThemeFileInfo(customThemeFile); QFileInfo customThemeFileInfo(customThemeFile);
themeDebugLog() << "Loading QSS Theme from:" << customThemeFileInfo.absoluteFilePath(); themeDebugLog() << "Loading QSS Theme from:" << customThemeFileInfo.absoluteFilePath();
AddTheme(std::make_unique<CustomTheme>(GetTheme(darkThemeId), customThemeFileInfo, false)); addTheme(std::make_unique<CustomTheme>(getTheme(darkThemeId), customThemeFileInfo, false));
} }
} }
} }
@ -120,19 +120,36 @@ void ThemeManager::applyCurrentlySelectedTheme()
{ {
setIconTheme(APPLICATION->settings()->get("IconTheme").toString()); setIconTheme(APPLICATION->settings()->get("IconTheme").toString());
themeDebugLog() << "<> Icon theme set."; themeDebugLog() << "<> Icon theme set.";
setApplicationTheme(APPLICATION->settings()->get("ApplicationTheme").toString(), true); setApplicationTheme(APPLICATION->settings()->get("ApplicationTheme").toString());
themeDebugLog() << "<> Application theme set."; themeDebugLog() << "<> Application theme set.";
} }
void ThemeManager::setApplicationTheme(const QString& name, bool initial) void ThemeManager::setApplicationTheme(const QString& name)
{ {
auto systemPalette = qApp->palette(); auto systemPalette = qApp->palette();
auto themeIter = m_themes.find(name); auto themeIter = m_themes.find(name);
if (themeIter != m_themes.end()) { if (themeIter != m_themes.end()) {
auto& theme = themeIter->second; auto& theme = themeIter->second;
themeDebugLog() << "applying theme" << theme->name(); themeDebugLog() << "applying theme" << theme->name();
theme->apply(initial); theme->apply();
} else { } else {
themeWarningLog() << "Tried to set invalid theme:" << name; themeWarningLog() << "Tried to set invalid theme:" << name;
} }
} }
QString ThemeManager::getCatImage(QString catName)
{
QDateTime now = QDateTime::currentDateTime();
QDateTime birthday(QDate(now.date().year(), 11, 30), QTime(0, 0));
QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0));
QDateTime halloween(QDate(now.date().year(), 10, 31), QTime(0, 0));
QString cat = !catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString();
if (std::abs(now.daysTo(xmas)) <= 4) {
cat += "-xmas";
} else if (std::abs(now.daysTo(halloween)) <= 4) {
cat += "-spooky";
} else if (std::abs(now.daysTo(birthday)) <= 12) {
cat += "-bday";
}
return cat;
}

View File

@ -35,18 +35,23 @@ class ThemeManager {
public: public:
ThemeManager(MainWindow* mainWindow); ThemeManager(MainWindow* mainWindow);
// maybe make private? Or put in ctor?
void InitializeThemes();
QList<ITheme*> getValidApplicationThemes(); QList<ITheme*> getValidApplicationThemes();
void setIconTheme(const QString& name); void setIconTheme(const QString& name);
void applyCurrentlySelectedTheme(); void applyCurrentlySelectedTheme();
void setApplicationTheme(const QString& name, bool initial); void setApplicationTheme(const QString& name);
/// <summary>
/// Returns the cat based on selected cat and with events (Birthday, XMas, etc.)
/// </summary>
/// <param name="catName">Optional, if you need a specific cat.</param>
/// <returns></returns>
static QString getCatImage(QString catName = "");
private: private:
std::map<QString, std::unique_ptr<ITheme>> m_themes; std::map<QString, std::unique_ptr<ITheme>> m_themes;
MainWindow* m_mainWindow; MainWindow* m_mainWindow;
QString AddTheme(std::unique_ptr<ITheme> theme); void initializeThemes();
ITheme* GetTheme(QString themeId); QString addTheme(std::unique_ptr<ITheme> theme);
ITheme* getTheme(QString themeId);
}; };

View File

@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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 "ThemeCustomizationWidget.h"
#include "ui_ThemeCustomizationWidget.h"
#include "Application.h"
#include "ui/themes/ITheme.h"
#include "ui/themes/ThemeManager.h"
ThemeCustomizationWidget::ThemeCustomizationWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ThemeCustomizationWidget)
{
ui->setupUi(this);
loadSettings();
connect(ui->iconsComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyIconTheme);
connect(ui->widgetStyleComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyWidgetTheme);
connect(ui->backgroundCatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyCatTheme);
}
ThemeCustomizationWidget::~ThemeCustomizationWidget()
{
delete ui;
}
/// <summary>
/// The layout was not quite right, so currently this just disables the UI elements, which should be hidden instead
/// TODO FIXME
///
/// Original Method One:
/// ui->iconsComboBox->setVisible(features& ThemeFields::ICONS);
/// ui->iconsLabel->setVisible(features& ThemeFields::ICONS);
/// ui->widgetStyleComboBox->setVisible(features& ThemeFields::WIDGETS);
/// ui->widgetThemeLabel->setVisible(features& ThemeFields::WIDGETS);
/// ui->backgroundCatComboBox->setVisible(features& ThemeFields::CAT);
/// ui->backgroundCatLabel->setVisible(features& ThemeFields::CAT);
///
/// original Method Two:
/// if (!(features & ThemeFields::ICONS)) {
/// ui->formLayout->setRowVisible(0, false);
/// }
/// if (!(features & ThemeFields::WIDGETS)) {
/// ui->formLayout->setRowVisible(1, false);
/// }
/// if (!(features & ThemeFields::CAT)) {
/// ui->formLayout->setRowVisible(2, false);
/// }
/// </summary>
/// <param name="features"></param>
void ThemeCustomizationWidget::showFeatures(ThemeFields features) {
ui->iconsComboBox->setEnabled(features & ThemeFields::ICONS);
ui->iconsLabel->setEnabled(features & ThemeFields::ICONS);
ui->widgetStyleComboBox->setEnabled(features & ThemeFields::WIDGETS);
ui->widgetThemeLabel->setEnabled(features & ThemeFields::WIDGETS);
ui->backgroundCatComboBox->setEnabled(features & ThemeFields::CAT);
ui->backgroundCatLabel->setEnabled(features & ThemeFields::CAT);
}
void ThemeCustomizationWidget::applyIconTheme(int index) {
auto settings = APPLICATION->settings();
auto originalIconTheme = settings->get("IconTheme").toString();
auto& newIconTheme = m_iconThemeOptions[index].first;
settings->set("IconTheme", newIconTheme);
if (originalIconTheme != newIconTheme) {
APPLICATION->applyCurrentlySelectedTheme();
}
emit currentIconThemeChanged(index);
}
void ThemeCustomizationWidget::applyWidgetTheme(int index) {
auto settings = APPLICATION->settings();
auto originalAppTheme = settings->get("ApplicationTheme").toString();
auto newAppTheme = ui->widgetStyleComboBox->currentData().toString();
if (originalAppTheme != newAppTheme) {
settings->set("ApplicationTheme", newAppTheme);
APPLICATION->applyCurrentlySelectedTheme();
}
emit currentWidgetThemeChanged(index);
}
void ThemeCustomizationWidget::applyCatTheme(int index) {
auto settings = APPLICATION->settings();
settings->set("BackgroundCat", m_catOptions[index].first);
emit currentCatChanged(index);
}
void ThemeCustomizationWidget::applySettings()
{
applyIconTheme(ui->iconsComboBox->currentIndex());
applyWidgetTheme(ui->widgetStyleComboBox->currentIndex());
applyCatTheme(ui->backgroundCatComboBox->currentIndex());
}
void ThemeCustomizationWidget::loadSettings()
{
auto settings = APPLICATION->settings();
auto iconTheme = settings->get("IconTheme").toString();
for (auto& iconThemeFromList : m_iconThemeOptions) {
QIcon iconForComboBox = QIcon(QString(":/icons/%1/scalable/settings").arg(iconThemeFromList.first));
ui->iconsComboBox->addItem(iconForComboBox, iconThemeFromList.second);
if (iconTheme == iconThemeFromList.first) {
ui->iconsComboBox->setCurrentIndex(ui->iconsComboBox->count() - 1);
}
}
{
auto currentTheme = settings->get("ApplicationTheme").toString();
auto themes = APPLICATION->getValidApplicationThemes();
int idx = 0;
for (auto& theme : themes) {
ui->widgetStyleComboBox->addItem(theme->name(), theme->id());
if (currentTheme == theme->id()) {
ui->widgetStyleComboBox->setCurrentIndex(idx);
}
idx++;
}
}
auto cat = settings->get("BackgroundCat").toString();
for (auto& catFromList : m_catOptions) {
QIcon catIcon = QIcon(QString(":/backgrounds/%1").arg(ThemeManager::getCatImage(catFromList.first)));
ui->backgroundCatComboBox->addItem(catIcon, catFromList.second);
if (cat == catFromList.first) {
ui->backgroundCatComboBox->setCurrentIndex(ui->backgroundCatComboBox->count() - 1);
}
}
}
void ThemeCustomizationWidget::retranslate()
{
ui->retranslateUi(this);
}

View File

@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft 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/>.
*/
#pragma once
#include <QWidget>
#include "translations/TranslationsModel.h"
enum ThemeFields { NONE = 0b0000, ICONS = 0b0001, WIDGETS = 0b0010, CAT = 0b0100 };
namespace Ui {
class ThemeCustomizationWidget;
}
class ThemeCustomizationWidget : public QWidget {
Q_OBJECT
public:
explicit ThemeCustomizationWidget(QWidget* parent = nullptr);
~ThemeCustomizationWidget();
void showFeatures(ThemeFields features);
void applySettings();
void loadSettings();
void retranslate();
private slots:
void applyIconTheme(int index);
void applyWidgetTheme(int index);
void applyCatTheme(int index);
signals:
int currentIconThemeChanged(int index);
int currentWidgetThemeChanged(int index);
int currentCatChanged(int index);
private:
Ui::ThemeCustomizationWidget* ui;
//TODO finish implementing
QList<std::pair<QString, QString>> m_iconThemeOptions{
{ "pe_colored", QObject::tr("Simple (Colored Icons)") },
{ "pe_light", QObject::tr("Simple (Light Icons)") },
{ "pe_dark", QObject::tr("Simple (Dark Icons)") },
{ "pe_blue", QObject::tr("Simple (Blue Icons)") },
{ "breeze_light", QObject::tr("Breeze Light") },
{ "breeze_dark", QObject::tr("Breeze Dark") },
{ "OSX", QObject::tr("OSX") },
{ "iOS", QObject::tr("iOS") },
{ "flat", QObject::tr("Flat") },
{ "flat_white", QObject::tr("Flat (White)") },
{ "multimc", QObject::tr("Legacy") },
{ "custom", QObject::tr("Custom") }
};
QList<std::pair<QString, QString>> m_catOptions{
{ "kitteh", QObject::tr("Background Cat (from MultiMC)") },
{ "rory", QObject::tr("Rory ID 11 (drawn by Ashtaka)") },
{ "rory-flat", QObject::tr("Rory ID 11 (flat edition, drawn by Ashtaka)") },
{ "teawie", QObject::tr("Teawie (drawn by SympathyTea)") }
};
};

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ThemeCustomizationWidget</class>
<widget class="QWidget" name="ThemeCustomizationWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>191</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="iconsLabel">
<property name="text">
<string>&amp;Icons</string>
</property>
<property name="buddy">
<cstring>iconsComboBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="iconsComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="widgetThemeLabel">
<property name="text">
<string>&amp;Colors</string>
</property>
<property name="buddy">
<cstring>widgetStyleComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="widgetStyleComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="backgroundCatLabel">
<property name="toolTip">
<string>The cat appears in the background and is not shown by default. It is only made visible when pressing the Cat button in the Toolbar.</string>
</property>
<property name="text">
<string>C&amp;at</string>
</property>
<property name="buddy">
<cstring>backgroundCatComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="backgroundCatComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>The cat appears in the background and is not shown by default. It is only made visible when pressing the Cat button in the Toolbar.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="catInfoLabel">
<property name="toolTip">
<string>The cat appears in the background and is not shown by default. It is only made visible when pressing the Cat button in the Toolbar.</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="about">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>