Merge remote-tracking branch 'upstream/develop' into data-packs

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad
2025-06-02 09:52:05 +01:00
81 changed files with 5996 additions and 2605 deletions

View File

@ -338,6 +338,9 @@ if(NOT Launcher_FORCE_BUNDLED_LIBS)
# Find cmark
find_package(cmark QUIET)
# Find qrcodegencpp-cmake
find_package(qrcodegencpp QUIET)
endif()
include(ECMQtDeclareLoggingCategory)
@ -528,19 +531,22 @@ if(NOT cmark_FOUND)
else()
message(STATUS "Using system cmark")
endif()
if(NOT qrcodegencpp_FOUND)
set(QRCODE_SOURCES
libraries/qrcodegenerator/cpp/qrcodegen.cpp
libraries/qrcodegenerator/cpp/qrcodegen.hpp
)
add_library(qrcodegenerator STATIC ${QRCODE_SOURCES})
target_include_directories(qrcodegenerator PUBLIC "libraries/qrcodegenerator/cpp/" )
generate_export_header(qrcodegenerator)
else()
add_library(qrcodegenerator ALIAS qrcodegencpp::qrcodegencpp)
message(STATUS "Using system qrcodegencpp-cmake")
endif()
add_subdirectory(libraries/gamemode)
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
add_subdirectory(libraries/qdcss) # css parser
# qr code generator
set(QRCODE_SOURCES
libraries/qrcodegenerator/cpp/qrcodegen.cpp
libraries/qrcodegenerator/cpp/qrcodegen.hpp
)
add_library(qrcodegenerator STATIC ${QRCODE_SOURCES})
target_include_directories(qrcodegenerator PUBLIC "libraries/qrcodegenerator/cpp/" )
generate_export_header(qrcodegenerator)
############################### Built Artifacts ###############################
add_subdirectory(buildconfig)

View File

@ -59,6 +59,7 @@
#include "ui/pages/BasePageProvider.h"
#include "ui/pages/global/APIPage.h"
#include "ui/pages/global/AccountListPage.h"
#include "ui/pages/global/AppearancePage.h"
#include "ui/pages/global/ExternalToolsPage.h"
#include "ui/pages/global/JavaPage.h"
#include "ui/pages/global/LanguagePage.h"
@ -886,13 +887,14 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
{
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
m_globalSettingsProvider->addPage<LauncherPage>();
m_globalSettingsProvider->addPage<LanguagePage>();
m_globalSettingsProvider->addPage<AppearancePage>();
m_globalSettingsProvider->addPage<MinecraftPage>();
m_globalSettingsProvider->addPage<JavaPage>();
m_globalSettingsProvider->addPage<LanguagePage>();
m_globalSettingsProvider->addPage<ProxyPage>();
m_globalSettingsProvider->addPage<ExternalToolsPage>();
m_globalSettingsProvider->addPage<AccountListPage>();
m_globalSettingsProvider->addPage<APIPage>();
m_globalSettingsProvider->addPage<ExternalToolsPage>();
m_globalSettingsProvider->addPage<ProxyPage>();
}
PixmapCache::setInstance(new PixmapCache(this));
@ -1650,9 +1652,9 @@ void Application::ShowGlobalSettings(class QWidget* parent, QString open_page)
{
SettingsObject::Lock lock(APPLICATION->settings());
PageDialog dlg(m_globalSettingsProvider.get(), open_page, parent);
connect(&dlg, &PageDialog::applied, this, &Application::globalSettingsApplied);
dlg.exec();
}
emit globalSettingsClosed();
}
MainWindow* Application::showMainWindow(bool minimized)

View File

@ -196,7 +196,7 @@ class Application : public QApplication {
signals:
void updateAllowedChanged(bool status);
void globalSettingsAboutToOpen();
void globalSettingsClosed();
void globalSettingsApplied();
int currentCatChanged(int index);
void oauthReplyRecieved(QVariantMap);

View File

@ -69,6 +69,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("linkedInstances", "[]");
m_settings->registerSetting("shortcuts", QString());
// Game time override
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
@ -398,6 +399,57 @@ bool BaseInstance::syncInstanceDirName(const QString& newRoot) const
return oldRoot == newRoot || QFile::rename(oldRoot, newRoot);
}
void BaseInstance::registerShortcut(const ShortcutData& data)
{
auto currentShortcuts = shortcuts();
currentShortcuts.append(data);
qDebug() << "Registering shortcut for instance" << id() << "with name" << data.name << "and path" << data.filePath;
setShortcuts(currentShortcuts);
}
void BaseInstance::setShortcuts(const QList<ShortcutData>& shortcuts)
{
// FIXME: if no change, do not set. setting involves saving a file.
QJsonArray array;
for (const auto& elem : shortcuts) {
array.append(QJsonObject{ { "name", elem.name }, { "filePath", elem.filePath }, { "target", static_cast<int>(elem.target) } });
}
QJsonDocument document;
document.setArray(array);
m_settings->set("shortcuts", QString::fromUtf8(document.toJson(QJsonDocument::Compact)));
}
QList<ShortcutData> BaseInstance::shortcuts() const
{
auto data = m_settings->get("shortcuts").toString().toUtf8();
QJsonParseError parseError;
auto document = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError || !document.isArray())
return {};
QList<ShortcutData> results;
for (const auto& elem : document.array()) {
if (!elem.isObject())
continue;
auto dict = elem.toObject();
if (!dict.contains("name") || !dict.contains("filePath") || !dict.contains("target"))
continue;
int value = dict["target"].toInt(-1);
if (!dict["name"].isString() || !dict["filePath"].isString() || value < 0 || value >= 3)
continue;
QString shortcutName = dict["name"].toString();
QString filePath = dict["filePath"].toString();
if (!QDir(filePath).exists()) {
qWarning() << "Shortcut" << shortcutName << "for instance" << name() << "have non-existent path" << filePath;
continue;
}
results.append({ shortcutName, filePath, static_cast<ShortcutTarget>(value) });
}
return results;
}
QString BaseInstance::name() const
{
return m_settings->get("name").toString();

View File

@ -38,7 +38,9 @@
#pragma once
#include <cassert>
#include <QDataStream>
#include <QDateTime>
#include <QList>
#include <QMenu>
#include <QObject>
#include <QProcess>
@ -66,6 +68,16 @@ class BaseInstance;
// pointer for lazy people
using InstancePtr = std::shared_ptr<BaseInstance>;
/// Shortcut saving target representations
enum class ShortcutTarget { Desktop, Applications, Other };
/// Shortcut data representation
struct ShortcutData {
QString name;
QString filePath;
ShortcutTarget target = ShortcutTarget::Other;
};
/*!
* \brief Base class for instances.
* This class implements many functions that are common between instances and
@ -129,6 +141,11 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
/// Sync name and rename instance dir accordingly; returns true if successful
bool syncInstanceDirName(const QString& newRoot) const;
/// Register a created shortcut
void registerShortcut(const ShortcutData& data);
QList<ShortcutData> shortcuts() const;
void setShortcuts(const QList<ShortcutData>& shortcuts);
/// Value used for instance window titles
QString windowTitle() const;

View File

@ -864,7 +864,6 @@ SET(LAUNCHER_SOURCES
ui/setupwizard/LanguageWizardPage.h
ui/setupwizard/PasteWizardPage.cpp
ui/setupwizard/PasteWizardPage.h
ui/setupwizard/ThemeWizardPage.cpp
ui/setupwizard/ThemeWizardPage.h
ui/setupwizard/AutoJavaWizardPage.cpp
ui/setupwizard/AutoJavaWizardPage.h
@ -960,6 +959,7 @@ SET(LAUNCHER_SOURCES
ui/pages/global/MinecraftPage.h
ui/pages/global/LauncherPage.cpp
ui/pages/global/LauncherPage.h
ui/pages/global/AppearancePage.h
ui/pages/global/ProxyPage.cpp
ui/pages/global/ProxyPage.h
ui/pages/global/APIPage.cpp
@ -1157,8 +1157,8 @@ SET(LAUNCHER_SOURCES
ui/widgets/ProgressWidget.cpp
ui/widgets/WideBar.h
ui/widgets/WideBar.cpp
ui/widgets/ThemeCustomizationWidget.h
ui/widgets/ThemeCustomizationWidget.cpp
ui/widgets/AppearanceWidget.h
ui/widgets/AppearanceWidget.cpp
ui/widgets/MinecraftSettingsWidget.h
ui/widgets/MinecraftSettingsWidget.cpp
ui/widgets/JavaSettingsWidget.h
@ -1200,7 +1200,6 @@ qt_wrap_ui(LAUNCHER_UI
ui/setupwizard/PasteWizardPage.ui
ui/setupwizard/AutoJavaWizardPage.ui
ui/setupwizard/LoginWizardPage.ui
ui/setupwizard/ThemeWizardPage.ui
ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui
ui/pages/global/LauncherPage.ui
@ -1234,7 +1233,7 @@ qt_wrap_ui(LAUNCHER_UI
ui/widgets/InfoFrame.ui
ui/widgets/ModFilterWidget.ui
ui/widgets/SubTaskProgressBar.ui
ui/widgets/ThemeCustomizationWidget.ui
ui/widgets/AppearanceWidget.ui
ui/widgets/MinecraftSettingsWidget.ui
ui/widgets/JavaSettingsWidget.ui
ui/dialogs/CopyInstanceDialog.ui

View File

@ -898,26 +898,26 @@ QString getApplicationsDir()
}
// Cross-platform Shortcut creation
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
{
if (destination.isEmpty()) {
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
}
if (!ensureFilePathExists(destination)) {
qWarning() << "Destination path can't be created!";
return false;
return QString();
}
#if defined(Q_OS_MACOS)
QDir application = destination + ".app/";
if (application.exists()) {
qWarning() << "Application already exists!";
return false;
return QString();
}
if (!application.mkpath(".")) {
qWarning() << "Couldn't create application";
return false;
return QString();
}
QDir content = application.path() + "/Contents/";
@ -927,7 +927,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
qWarning() << "Couldn't create directories within application";
return false;
return QString();
}
info.open(QIODevice::WriteOnly | QIODevice::Text);
@ -976,7 +976,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
"</dict>\n"
"</plist>";
return true;
return application.path();
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
destination += ".desktop";
@ -1002,32 +1002,32 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
return true;
return destination;
#elif defined(Q_OS_WIN)
QFileInfo targetInfo(target);
if (!targetInfo.exists()) {
qWarning() << "Target file does not exist!";
return false;
return QString();
}
target = targetInfo.absoluteFilePath();
if (target.length() >= MAX_PATH) {
qWarning() << "Target file path is too long!";
return false;
return QString();
}
if (!icon.isEmpty() && icon.length() >= MAX_PATH) {
qWarning() << "Icon path is too long!";
return false;
return QString();
}
destination += ".lnk";
if (destination.length() >= MAX_PATH) {
qWarning() << "Destination path is too long!";
return false;
return QString();
}
QString argStr;
@ -1046,7 +1046,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (argStr.length() >= MAX_PATH) {
qWarning() << "Arguments string is too long!";
return false;
return QString();
}
HRESULT hres;
@ -1055,7 +1055,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
hres = CoInitialize(nullptr);
if (FAILED(hres)) {
qWarning() << "Failed to initialize COM!";
return false;
return QString();
}
WCHAR wsz[MAX_PATH];
@ -1109,10 +1109,12 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
// go away COM, nobody likes you
CoUninitialize();
return SUCCEEDED(hres);
if (SUCCEEDED(hres))
return destination;
return QString();
#else
qWarning("Desktop Shortcuts not supported on your platform!");
return false;
return QString();
#endif
}

View File

@ -362,8 +362,9 @@ bool overrideFolder(QString overwritten_path, QString override_path);
/**
* Creates a shortcut to the specified target file at the specified destination path.
* Returns null QString if creation failed; otherwise returns the path to the created shortcut.
*/
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
enum class FilesystemType {
FAT,

View File

@ -60,6 +60,7 @@
#include "NullInstance.h"
#include "WatchLock.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/ShortcutUtils.h"
#include "settings/INISettingsObject.h"
#ifdef Q_OS_WIN32
@ -333,7 +334,7 @@ bool InstanceList::trashInstance(const InstanceId& id)
{
auto inst = getInstanceById(id);
if (!inst) {
qDebug() << "Cannot trash instance" << id << ". No such instance is present (deleted externally?).";
qWarning() << "Cannot trash instance" << id << ". No such instance is present (deleted externally?).";
return false;
}
@ -348,26 +349,43 @@ bool InstanceList::trashInstance(const InstanceId& id)
}
if (!FS::trash(inst->instanceRoot(), &trashedLoc)) {
qDebug() << "Trash of instance" << id << "has not been completely successfully...";
qWarning() << "Trash of instance" << id << "has not been completely successful...";
return false;
}
qDebug() << "Instance" << id << "has been trashed by the launcher.";
m_trashHistory.push({ id, inst->instanceRoot(), trashedLoc, cachedGroupId });
// Also trash all of its shortcuts; we remove the shortcuts if trash fails since it is invalid anyway
for (const auto& [name, filePath, target] : inst->shortcuts()) {
if (!FS::trash(filePath, &trashedLoc)) {
qWarning() << "Trash of shortcut" << name << "at path" << filePath << "for instance" << id
<< "has not been successful, trying to delete it instead...";
if (!FS::deletePath(filePath)) {
qWarning() << "Deletion of shortcut" << name << "at path" << filePath << "for instance" << id
<< "has not been successful, given up...";
} else {
qDebug() << "Shortcut" << name << "at path" << filePath << "for instance" << id << "has been deleted by the launcher.";
}
continue;
}
qDebug() << "Shortcut" << name << "at path" << filePath << "for instance" << id << "has been trashed by the launcher.";
m_trashHistory.top().shortcuts.append({ { name, filePath, target }, trashedLoc });
}
return true;
}
bool InstanceList::trashedSomething()
bool InstanceList::trashedSomething() const
{
return !m_trashHistory.empty();
}
void InstanceList::undoTrashInstance()
bool InstanceList::undoTrashInstance()
{
if (m_trashHistory.empty()) {
qWarning() << "Nothing to recover from trash.";
return;
return true;
}
auto top = m_trashHistory.pop();
@ -377,21 +395,41 @@ void InstanceList::undoTrashInstance()
top.path += "1";
}
if (!QFile(top.trashPath).rename(top.path)) {
qWarning() << "Moving" << top.trashPath << "back to" << top.path << "failed!";
return false;
}
qDebug() << "Moving" << top.trashPath << "back to" << top.path;
QFile(top.trashPath).rename(top.path);
bool ok = true;
for (const auto& [data, trashPath] : top.shortcuts) {
if (QDir(data.filePath).exists()) {
// Don't try to append 1 here as the shortcut may have suffixes like .app, just warn and skip it
qWarning() << "Shortcut" << trashPath << "original directory" << data.filePath << "already exists!";
ok = false;
continue;
}
if (!QFile(trashPath).rename(data.filePath)) {
qWarning() << "Moving shortcut from" << trashPath << "back to" << data.filePath << "failed!";
ok = false;
continue;
}
qDebug() << "Moving shortcut from" << trashPath << "back to" << data.filePath;
}
m_instanceGroupIndex[top.id] = top.groupName;
increaseGroupCount(top.groupName);
saveGroupList();
emit instancesChanged();
return ok;
}
void InstanceList::deleteInstance(const InstanceId& id)
{
auto inst = getInstanceById(id);
if (!inst) {
qDebug() << "Cannot delete instance" << id << ". No such instance is present (deleted externally?).";
qWarning() << "Cannot delete instance" << id << ". No such instance is present (deleted externally?).";
return;
}
@ -404,11 +442,19 @@ void InstanceList::deleteInstance(const InstanceId& id)
qDebug() << "Will delete instance" << id;
if (!FS::deletePath(inst->instanceRoot())) {
qWarning() << "Deletion of instance" << id << "has not been completely successful ...";
qWarning() << "Deletion of instance" << id << "has not been completely successful...";
return;
}
qDebug() << "Instance" << id << "has been deleted by the launcher.";
for (const auto& [name, filePath, target] : inst->shortcuts()) {
if (!FS::deletePath(filePath)) {
qWarning() << "Deletion of shortcut" << name << "at path" << filePath << "for instance" << id << "has not been successful...";
continue;
}
qDebug() << "Shortcut" << name << "at path" << filePath << "for instance" << id << "has been deleted by the launcher.";
}
}
static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>& list)
@ -638,7 +684,12 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
} else {
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
}
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
qDebug() << "Loaded instance" << inst->name() << "from" << inst->instanceRoot();
auto shortcut = inst->shortcuts();
if (!shortcut.isEmpty())
qDebug() << "Loaded" << shortcut.size() << "shortcut(s) for instance" << inst->name();
return inst;
}

View File

@ -56,11 +56,17 @@ enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateErro
enum class GroupsState { NotLoaded, Steady, Dirty };
struct TrashShortcutItem {
ShortcutData data;
QString trashPath;
};
struct TrashHistoryItem {
QString id;
QString path;
QString trashPath;
QString groupName;
QList<TrashShortcutItem> shortcuts;
};
class InstanceList : public QAbstractListModel {
@ -111,8 +117,8 @@ class InstanceList : public QAbstractListModel {
void deleteGroup(const GroupId& name);
void renameGroup(const GroupId& src, const GroupId& dst);
bool trashInstance(const InstanceId& id);
bool trashedSomething();
void undoTrashInstance();
bool trashedSomething() const;
bool undoTrashInstance();
void deleteInstance(const InstanceId& id);
// Wrap an instance creation task in some more task machinery and make it ready to be used

View File

@ -95,7 +95,7 @@ void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& re
{
QString text;
text += QObject::tr(
"The specified Java binary didn't work.<br />You should use the auto-detect feature, "
"The specified Java binary didn't work.<br />You should press 'Detect', "
"or set the path to the Java executable.<br />");
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}

View File

@ -279,4 +279,29 @@ QJsonValue requireIsType<QJsonValue>(const QJsonValue& value, const QString& wha
return value;
}
QStringList toStringList(const QString& jsonString)
{
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8(), &parseError);
if (parseError.error != QJsonParseError::NoError || !doc.isArray())
return {};
try {
return ensureIsArrayOf<QString>(doc.array(), "");
} catch (Json::JsonException& e) {
return {};
}
}
QString fromStringList(const QStringList& list)
{
QJsonArray array;
for (const QString& str : list) {
array.append(str);
}
QJsonDocument doc(toJsonArray(list));
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
} // namespace Json

View File

@ -99,7 +99,7 @@ template <typename T>
QJsonArray toJsonArray(const QList<T>& container)
{
QJsonArray array;
for (const T item : container) {
for (const T& item : container) {
array.append(toJson<T>(item));
}
return array;
@ -278,5 +278,9 @@ JSON_HELPERFUNCTIONS(Variant, QVariant)
#undef JSON_HELPERFUNCTIONS
// helper functions for settings
QStringList toStringList(const QString& jsonString);
QString fromStringList(const QStringList& list);
} // namespace Json
using JSONValidationError = Json::JsonException;

View File

@ -256,6 +256,10 @@ void MinecraftInstance::loadSpecificSettings()
connect(dataPacksEnabled.get(), &Setting::SettingChanged, this, [this] { m_data_pack_list.reset(); });
connect(dataPacksPath.get(), &Setting::SettingChanged, this, [this] { m_data_pack_list.reset(); });
// Join server on launch, this does not have a global override
m_settings->registerSetting("OverrideModDownloadLoaders", false);
m_settings->registerSetting("ModDownloadLoaders", "[]");
qDebug() << "Instance-type specific settings were loaded!";
setSpecificSettingsLoaded(true);

View File

@ -48,10 +48,10 @@
namespace ShortcutUtils {
void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
{
if (!shortcut.instance)
return;
return false;
QString appPath = QApplication::applicationFilePath();
auto icon = APPLICATION->icons()->icon(shortcut.iconKey.isEmpty() ? shortcut.instance->iconKey() : shortcut.iconKey);
@ -64,7 +64,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (appPath.startsWith("/private/var/")) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts."));
return;
return false;
}
iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "Icon.icns");
@ -72,7 +72,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application."));
return;
return false;
}
QIcon iconObj = icon->icon();
@ -82,7 +82,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (!success) {
iconFile.remove();
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application."));
return;
return false;
}
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
if (appPath.startsWith("/tmp/.mount_")) {
@ -102,7 +102,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut."));
return;
return false;
}
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG");
iconFile.close();
@ -110,7 +110,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (!success) {
iconFile.remove();
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut."));
return;
return false;
}
if (DesktopServices::isFlatpak()) {
@ -128,7 +128,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut."));
return;
return false;
}
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO");
iconFile.close();
@ -139,51 +139,58 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (!success) {
iconFile.remove();
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut."));
return;
return false;
}
#else
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Not supported on your platform!"));
return;
return false;
#endif
args.append({ "--launch", shortcut.instance->id() });
args.append(shortcut.extraArgs);
if (!FS::createShortcut(filePath, appPath, args, shortcut.name, iconPath)) {
QString shortcutPath = FS::createShortcut(filePath, appPath, args, shortcut.name, iconPath);
if (shortcutPath.isEmpty()) {
#if not defined(Q_OS_MACOS)
iconFile.remove();
#endif
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Failed to create %1 shortcut!").arg(shortcut.targetString));
return false;
}
shortcut.instance->registerShortcut({ shortcut.name, shortcutPath, shortcut.target });
return true;
}
void createInstanceShortcutOnDesktop(const Shortcut& shortcut)
bool createInstanceShortcutOnDesktop(const Shortcut& shortcut)
{
if (!shortcut.instance)
return;
return false;
QString desktopDir = FS::getDesktopDir();
if (desktopDir.isEmpty()) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find desktop?!"));
return;
return false;
}
QString shortcutFilePath = FS::PathCombine(desktopDir, FS::RemoveInvalidFilenameChars(shortcut.name));
createInstanceShortcut(shortcut, shortcutFilePath);
if (!createInstanceShortcut(shortcut, shortcutFilePath))
return false;
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Created a shortcut to this %1 on your desktop!").arg(shortcut.targetString));
return true;
}
void createInstanceShortcutInApplications(const Shortcut& shortcut)
bool createInstanceShortcutInApplications(const Shortcut& shortcut)
{
if (!shortcut.instance)
return;
return false;
QString applicationsDir = FS::getApplicationsDir();
if (applicationsDir.isEmpty()) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find applications folder?!"));
return;
return false;
}
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
@ -193,20 +200,22 @@ void createInstanceShortcutInApplications(const Shortcut& shortcut)
if (!applicationsDirQ.mkpath(".")) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Failed to create instances folder in applications folder!"));
return;
return false;
}
#endif
QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(shortcut.name));
createInstanceShortcut(shortcut, shortcutFilePath);
if (!createInstanceShortcut(shortcut, shortcutFilePath))
return false;
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Created a shortcut to this %1 in your applications folder!").arg(shortcut.targetString));
return true;
}
void createInstanceShortcutInOther(const Shortcut& shortcut)
bool createInstanceShortcutInOther(const Shortcut& shortcut)
{
if (!shortcut.instance)
return;
return false;
QString defaultedDir = FS::getDesktopDir();
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
@ -225,13 +234,15 @@ void createInstanceShortcutInOther(const Shortcut& shortcut)
shortcutFilePath = fileDialog.getSaveFileName(shortcut.parent, QObject::tr("Create Shortcut"), shortcutFilePath,
QObject::tr("Desktop Entries") + " (*" + extension + ")");
if (shortcutFilePath.isEmpty())
return; // file dialog canceled by user
return false; // file dialog canceled by user
if (shortcutFilePath.endsWith(extension))
shortcutFilePath = shortcutFilePath.mid(0, shortcutFilePath.length() - extension.length());
createInstanceShortcut(shortcut, shortcutFilePath);
if (!createInstanceShortcut(shortcut, shortcutFilePath))
return false;
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Created a shortcut to this %1!").arg(shortcut.targetString));
return true;
}
} // namespace ShortcutUtils

View File

@ -38,6 +38,7 @@
#pragma once
#include "Application.h"
#include <QList>
#include <QMessageBox>
namespace ShortcutUtils {
@ -49,18 +50,19 @@ struct Shortcut {
QWidget* parent = nullptr;
QStringList extraArgs = {};
QString iconKey = "";
ShortcutTarget target;
};
/// Create an instance shortcut on the specified file path
void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath);
bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath);
/// Create an instance shortcut on the desktop
void createInstanceShortcutOnDesktop(const Shortcut& shortcut);
bool createInstanceShortcutOnDesktop(const Shortcut& shortcut);
/// Create an instance shortcut in the Applications directory
void createInstanceShortcutInApplications(const Shortcut& shortcut);
bool createInstanceShortcutInApplications(const Shortcut& shortcut);
/// Create an instance shortcut in other directories
void createInstanceShortcutInOther(const Shortcut& shortcut);
bool createInstanceShortcutInOther(const Shortcut& shortcut);
} // namespace ShortcutUtils

View File

@ -43,5 +43,6 @@
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#EFF0F1;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 13.427734 2.0058594 A 1.500133 6.7506007 44.989453 0 0 8.0507812 5.8300781 A 1.500133 6.7506007 44.989453 0 0 5.3945312 8.9160156 C 6.2015113 9.1731156 6.8308906 9.802075 7.0878906 10.609375 A 1.500133 6.7506007 44.989453 0 0 10.171875 7.9511719 A 1.500133 6.7506007 44.989453 0 0 13.882812 2.1171875 A 1.500133 6.7506007 44.989453 0 0 13.634766 2.0058594 A 1.500133 6.7506007 44.989453 0 0 13.427734 2.0058594 z M 5 9.9960938 L 5 10 C 2.00008 10.8042 4.24994 12.7027 2 14 C 4.99992 14 6.5 12.499247 6.5 11.498047 C 6.5 10.998947 6.55095 10.079094 5 9.9960938 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 900 B

View File

@ -43,5 +43,6 @@
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#232629;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 13.427734 2.0058594 A 1.500133 6.7506007 44.989453 0 0 8.0507812 5.8300781 A 1.500133 6.7506007 44.989453 0 0 5.3945312 8.9160156 C 6.2015113 9.1731156 6.8308906 9.802075 7.0878906 10.609375 A 1.500133 6.7506007 44.989453 0 0 10.171875 7.9511719 A 1.500133 6.7506007 44.989453 0 0 13.882812 2.1171875 A 1.500133 6.7506007 44.989453 0 0 13.634766 2.0058594 A 1.500133 6.7506007 44.989453 0 0 13.427734 2.0058594 z M 5 9.9960938 L 5 10 C 2.00008 10.8042 4.24994 12.7027 2 14 C 4.99992 14 6.5 12.499247 6.5 11.498047 C 6.5 10.998947 6.55095 10.079094 5 9.9960938 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 900 B

View File

@ -49,5 +49,6 @@
<file>scalable/rename.svg</file>
<file>scalable/server.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#757575"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 14c-1.66 0-3 1.34-3 3 0 1.31-1.16 2-2 2 .92 1.22 2.49 2 4 2 2.21 0 4-1.79 4-4 0-1.66-1.34-3-3-3zm13.71-9.37l-1.34-1.34c-.39-.39-1.02-.39-1.41 0L9 12.25 11.75 15l8.96-8.96c.39-.39.39-1.02 0-1.41z"/></svg>

After

Width:  |  Height:  |  Size: 354 B

View File

@ -49,5 +49,6 @@
<file>scalable/tag.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#eeeeee"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 14c-1.66 0-3 1.34-3 3 0 1.31-1.16 2-2 2 .92 1.22 2.49 2 4 2 2.21 0 4-1.79 4-4 0-1.66-1.34-3-3-3zm13.71-9.37l-1.34-1.34c-.39-.39-1.02-.39-1.41 0L9 12.25 11.75 15l8.96-8.96c.39-.39.39-1.02 0-1.41z"/></svg>

After

Width:  |  Height:  |  Size: 354 B

View File

@ -247,7 +247,7 @@
<!-- matrix logo -->
<file>scalable/matrix.svg</file>
<!-- discord logo icon thing. from discord. traced from bitmap -->
<file>scalable/discord.svg</file>
@ -279,7 +279,7 @@
<file>scalable/instances/fox.svg</file>
<file>scalable/instances/bee.svg</file>
<!-- instance icons -->
<file>32x32/instances/chicken_legacy.png</file>
<file>128x128/instances/chicken_legacy.png</file>
@ -347,6 +347,7 @@
<file>scalable/export.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
<file>scalable/instances/quiltmc.svg</file> <!-- CC0 QuiltMC -->
<file>scalable/instances/fabricmc.svg</file> <!-- CC0 unascribed, https://github.com/FabricMC/community/blob/main/media/unascribed/README.md -->

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -41,5 +41,6 @@
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
id="Calque_1"
x="0px"
y="0px"
viewBox="0 0 32 32"
enable-background="new 0 0 32 32"
xml:space="preserve"
sodipodi:docname="appearance.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="11.313708"
inkscape:cx="4.9497475"
inkscape:cy="37.388271"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g7954"
showgrid="false" /><defs
id="defs45" />
<g
id="g7954"><path
id="path2"
d="M 26,32 H 6 C 2.7,32 0,29.3 0,26 V 6 C 0,2.7 2.7,0 6,0 h 20 c 3.3,0 6,2.7 6,6 v 20 c 0,3.3 -2.7,6 -6,6 z"
fill="#3366cc"
clip-rule="evenodd"
fill-rule="evenodd" /><path
fill="#daeeff"
fill-rule="evenodd"
clip-rule="evenodd"
id="path4"
d="M 28,6 C 28,4.9 27.1,4 26,4 H 6 C 4.9,4 4,4.9 4,6 v 20 c 0,1.1 0.9,2 2,2 h 20 c 1.1,0 2,-0.9 2,-2 z" /><path
fill="none"
d="M 8.9659036,28 H 22.965904 c 1.1,0 2,-0.9 2,-2 V 15 14 H 6.9659036 v 1 11 c 0,1.1 0.9,2 2,2 z"
id="path8" /><rect
style="fill:#000000;fill-opacity:0;stroke:none;stroke-width:0.000000879999;stroke-linecap:round;stroke-linejoin:round"
id="rect2311"
width="29.020048"
height="4"
x="1.4899759"
y="7.1611009" /><g
id="g2657"
transform="rotate(31.454004,7.3789217,28.015625)"><path
id="path5-56"
style="fill:#c1272d;fill-opacity:1;stroke-width:14.5284"
d="M 8.413071,2.4595861 A 2.5,8.0000002 0 0 0 6.3465633,10.337319 2.5,8.0000002 0 0 0 7.4458626,16.960111 C 7.7356137,16.430277 8.2119852,16.01524 8.9151067,15.96976 9.5063364,15.93152 9.9629895,16.336614 10.250228,16.958042 A 2.5,8.0000002 0 0 0 11.346521,10.337343 2.5,8.0000002 0 0 0 8.8459304,2.3382251 2.5,8.0000002 0 0 0 8.413071,2.4595861 Z" /><path
id="path5-6"
style="fill:#c1272d;fill-opacity:1;stroke-width:9.6096"
d="m 9.1439767,17.889764 c -1.3309058,0.08609 -1.8604029,1.491611 -1.8189608,2.506407 0.045613,1.116922 1.4392755,2.225341 0.1366377,3.772111 1.6687108,-0.08051 2.5726364,-1.0077 3.1912724,-2.25073 0.506557,-1.849334 -0.145661,-4.115969 -1.5089493,-4.027788 z"
sodipodi:nodetypes="ssccs" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -41,5 +41,6 @@
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
id="Calque_1"
x="0px"
y="0px"
viewBox="0 0 32 32"
enable-background="new 0 0 32 32"
xml:space="preserve"
sodipodi:docname="appearance.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="16"
inkscape:cx="-7.8125"
inkscape:cy="17.6875"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g7954"
showgrid="false"
showguides="false" /><defs
id="defs45" />
<g
id="g7954"><path
fill="none"
d="M 8.9659036,28 H 22.965904 c 1.1,0 2,-0.9 2,-2 V 15 14 H 6.9659036 v 1 11 c 0,1.1 0.9,2 2,2 z"
id="path8" /><rect
style="fill:#000000;fill-opacity:0;stroke:none;stroke-width:0.000000879999;stroke-linecap:round;stroke-linejoin:round"
id="rect2311"
width="29.020048"
height="4"
x="1.4899759"
y="7.1611009" /><path
id="path2-6"
d="M 28,6 C 28,4.9 27.1,4 26,4 H 6 C 4.9,4 4,4.9 4,6 v 20 c 0,1.1 0.9,2 2,2 h 20 c 1.1,0 2,-0.9 2,-2 z"
fill="#f2f2f2"
clip-rule="evenodd"
fill-rule="evenodd" /><g
id="g12"><path
id="path6"
d="m 6,28 h 20 c 1.1,0 2,-0.9 2,-2 V 9 6 C 28,4.9 27.1,4 26,4 H 6 C 4.9,4 4,4.9 4,6 v 3 17 c 0,1.1 0.9,2 2,2 z"
fill="none" /><path
id="path8-7"
d="M 26,0 H 6 C 2.7,0 0,2.7 0,6 V 9 H 4 V 6 C 4,4.9 4.9,4 6,4 h 20 c 1.1,0 2,0.9 2,2 v 3 h 4 V 6 C 32,2.7 29.3,0 26,0 Z"
fill="#39b54a" /><path
id="path10-5"
d="m 28,26 c 0,1.1 -0.9,2 -2,2 H 6 C 4.9,28 4,27.1 4,26 V 9 H 0 v 17 c 0,3.3 2.7,6 6,6 h 20 c 3.3,0 6,-2.7 6,-6 V 9 h -4 z"
fill="#8c6239" /></g><g
id="g2657"
transform="rotate(31.454004,7.3789216,28.015625)"><path
id="path5"
style="fill:#c1272d;fill-opacity:1;stroke-width:14.5284"
d="M 8.413071,2.4595861 A 2.5,8.0000002 0 0 0 6.3465633,10.337319 2.5,8.0000002 0 0 0 7.4458626,16.960111 C 7.7356137,16.430277 8.2119852,16.01524 8.9151067,15.96976 9.5063364,15.93152 9.9629895,16.336614 10.250228,16.958042 A 2.5,8.0000002 0 0 0 11.346521,10.337343 2.5,8.0000002 0 0 0 8.8459304,2.3382251 2.5,8.0000002 0 0 0 8.413071,2.4595861 Z" /><path
id="path5-6"
style="fill:#c1272d;fill-opacity:1;stroke-width:9.6096"
d="m 9.1439767,17.889764 c -1.3309058,0.08609 -1.8604029,1.491611 -1.8189608,2.506407 0.045613,1.116922 1.4392755,2.225341 0.1366377,3.772111 1.6687108,-0.08051 2.5726364,-1.0077 3.1912724,-2.25073 0.506557,-1.849334 -0.145661,-4.115969 -1.5089493,-4.027788 z"
sodipodi:nodetypes="ssccs" /></g></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -41,5 +41,6 @@
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
id="Calque_1"
x="0px"
y="0px"
viewBox="0 0 32 32"
enable-background="new 0 0 32 32"
xml:space="preserve"
sodipodi:docname="appearance.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="8"
inkscape:cx="17.5"
inkscape:cy="18.5"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g7954"
showgrid="false" /><defs
id="defs45" />
<g
id="g7954"><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 26,32 H 6 C 2.7,32 0,29.3 0,26 V 6 C 0,2.7 2.7,0 6,0 h 20 c 3.3,0 6,2.7 6,6 v 20 c 0,3.3 -2.7,6 -6,6 z"
id="path2" /><path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#f2f2f2"
d="M 28,6 C 28,4.9 27.1,4 26,4 H 6 C 4.9,4 4,4.9 4,6 v 20 c 0,1.1 0.9,2 2,2 h 20 c 1.1,0 2,-0.9 2,-2 z"
id="path4" /><path
fill="none"
d="M 8.9659036,28 H 22.965904 c 1.1,0 2,-0.9 2,-2 V 15 14 H 6.9659036 v 1 11 c 0,1.1 0.9,2 2,2 z"
id="path8" /><rect
style="fill:#000000;fill-opacity:0;stroke:none;stroke-width:0.000000879999;stroke-linecap:round;stroke-linejoin:round"
id="rect2311"
width="29.020048"
height="4"
x="1.4899759"
y="7.1611009" /><g
id="g2657"
transform="rotate(31.454004,7.3789216,28.015625)"
style="fill:#666666;fill-opacity:1"><path
id="path5-7"
style="fill:#666666;fill-opacity:1;stroke-width:14.5284"
d="M 8.413071,2.4595861 A 2.5,8.0000002 0 0 0 6.3465633,10.337319 2.5,8.0000002 0 0 0 7.4458626,16.960111 C 7.7356137,16.430277 8.2119852,16.01524 8.9151067,15.96976 9.5063364,15.93152 9.9629895,16.336614 10.250228,16.958042 A 2.5,8.0000002 0 0 0 11.346521,10.337343 2.5,8.0000002 0 0 0 8.8459304,2.3382251 2.5,8.0000002 0 0 0 8.413071,2.4595861 Z" /><path
id="path5-6"
style="fill:#666666;fill-opacity:1;stroke-width:9.6096"
d="m 9.1439767,17.889764 c -1.3309058,0.08609 -1.8604029,1.491611 -1.8189608,2.506407 0.045613,1.116922 1.4392755,2.225341 0.1366377,3.772111 1.6687108,-0.08051 2.5726364,-1.0077 3.1912724,-2.25073 0.506557,-1.849334 -0.145661,-4.115969 -1.5089493,-4.027788 z"
sodipodi:nodetypes="ssccs" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -41,5 +41,6 @@
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
<file>scalable/server.svg</file>
<file>scalable/appearance.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
id="Calque_1"
x="0px"
y="0px"
viewBox="0 0 32 32"
enable-background="new 0 0 32 32"
xml:space="preserve"
sodipodi:docname="appearance.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="16"
inkscape:cx="16.875"
inkscape:cy="15.4375"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g7954"
showgrid="false" /><defs
id="defs45" />
<g
id="g7954"><path
id="path2"
d="M 28,6 C 28,4.9 27.1,4 26,4 H 6 C 4.9,4 4,4.9 4,6 v 20 c 0,1.1 0.9,2 2,2 h 20 c 1.1,0 2,-0.9 2,-2 z"
fill="#4d4d4d"
clip-rule="evenodd"
fill-rule="evenodd" /><path
id="path6"
d="M 26,32 H 6 C 2.7,32 0,29.3 0,26 V 6 C 0,2.7 2.7,0 6,0 h 20 c 3.3,0 6,2.7 6,6 v 20 c 0,3.3 -2.7,6 -6,6 z M 28,6 C 28,4.9 27.1,4 26,4 H 6 C 4.9,4 4,4.9 4,6 v 20 c 0,1.1 0.9,2 2,2 h 20 c 1.1,0 2,-0.9 2,-2 z"
fill="#f2f2f2"
clip-rule="evenodd"
fill-rule="evenodd" /><path
fill="none"
d="M 8.9659036,28 H 22.965904 c 1.1,0 2,-0.9 2,-2 V 15 14 H 6.9659036 v 1 11 c 0,1.1 0.9,2 2,2 z"
id="path8" /><rect
style="fill:#000000;fill-opacity:0;stroke:none;stroke-width:0.000000879999;stroke-linecap:round;stroke-linejoin:round"
id="rect2311"
width="29.020048"
height="4"
x="1.4899759"
y="7.1611009" /><g
id="g2657"
transform="rotate(31.454004,7.3789216,28.015625)"
style="fill:#ffffff"><path
id="path5"
style="fill:#ffffff;fill-opacity:1;stroke-width:14.5284"
d="M 8.413071,2.4595861 A 2.5,8.0000002 0 0 0 6.3465633,10.337319 2.5,8.0000002 0 0 0 7.4458626,16.960111 C 7.7356137,16.430277 8.2119852,16.01524 8.9151067,15.96976 9.5063364,15.93152 9.9629895,16.336614 10.250228,16.958042 A 2.5,8.0000002 0 0 0 11.346521,10.337343 2.5,8.0000002 0 0 0 8.8459304,2.3382251 2.5,8.0000002 0 0 0 8.413071,2.4595861 Z" /><path
id="path5-6"
style="fill:#ffffff;fill-opacity:1;stroke-width:9.6096"
d="m 9.1439767,17.889764 c -1.3309058,0.08609 -1.8604029,1.491611 -1.8189608,2.506407 0.045613,1.116922 1.4392755,2.225341 0.1366377,3.772111 1.6687108,-0.08051 2.5726364,-1.0077 3.1912724,-2.25073 0.506557,-1.849334 -0.145661,-4.115969 -1.5089493,-4.027788 z"
sodipodi:nodetypes="ssccs" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -24,7 +24,7 @@ JVisualVM::JVisualVM(SettingsObjectPtr settings, InstancePtr instance, QObject*
void JVisualVM::profilerStarted()
{
emit readyToLaunch(tr("JVisualVM started"));
emit readyToLaunch(tr("VisualVM started"));
}
void JVisualVM::profilerFinished([[maybe_unused]] int exit, QProcess::ExitStatus status)
@ -82,7 +82,7 @@ bool JVisualVMFactory::check(const QString& path, QString* error)
}
QFileInfo finfo(path);
if (!finfo.isExecutable() || !finfo.fileName().contains("visualvm")) {
*error = QObject::tr("Invalid path to JVisualVM");
*error = QObject::tr("Invalid path to VisualVM");
return false;
}
return true;

View File

@ -4,7 +4,7 @@
class JVisualVMFactory : public BaseProfilerFactory {
public:
QString name() const override { return "JVisualVM"; }
QString name() const override { return "VisualVM"; }
void registerSettings(SettingsObjectPtr settings) override;
BaseExternalTool* createTool(InstancePtr instance, QObject* parent = 0) override;
bool check(QString* error) override;

View File

@ -111,7 +111,7 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget* parent) : QMainWin
m_container->addButtons(horizontalLayout);
connect(m_instance.get(), &BaseInstance::profilerChanged, this, &InstanceWindow::updateButtons);
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceWindow::updateButtons);
connect(APPLICATION, &Application::globalSettingsApplied, this, &InstanceWindow::updateButtons);
}
// restore window state

View File

@ -379,7 +379,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(APPLICATION->instances().get(), &InstanceList::instanceSelectRequest, this, &MainWindow::instanceSelectRequest);
// When the global settings page closes, we want to know about it and update our state
connect(APPLICATION, &Application::globalSettingsClosed, this, &MainWindow::globalSettingsClosed);
connect(APPLICATION, &Application::globalSettingsApplied, this, &MainWindow::globalSettingsClosed);
m_statusLeft = new QLabel(tr("No instance selected"), this);
m_statusCenter = new QLabel(tr("Total playtime: 0s"), this);
@ -1207,7 +1207,10 @@ void MainWindow::renameGroup(QString group)
void MainWindow::undoTrashInstance()
{
APPLICATION->instances()->undoTrashInstance();
if (!APPLICATION->instances()->undoTrashInstance())
QMessageBox::warning(
this, tr("Failed to undo trashing instance"),
tr("Some instances and shortcuts could not be restored.\nPlease check your trashbin to manually restore them."));
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
}
@ -1406,11 +1409,15 @@ void MainWindow::on_actionDeleteInstance_triggered()
}
auto id = m_selectedInstance->id();
QString shortcutStr;
auto shortcuts = m_selectedInstance->shortcuts();
if (!shortcuts.isEmpty())
shortcutStr = tr(" and its %n registered shortcut(s)", "", shortcuts.size());
auto response = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
tr("You are about to delete \"%1\".\n"
tr("You are about to delete \"%1\"%2.\n"
"This may be permanent and will completely delete the instance.\n\n"
"Are you sure?")
.arg(m_selectedInstance->name()),
.arg(m_selectedInstance->name(), shortcutStr),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();

View File

@ -83,12 +83,12 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent
QString applicationDir = FS::getApplicationsDir();
if (!desktopDir.isEmpty())
ui->saveTargetSelectionBox->addItem(tr("Desktop"), QVariant::fromValue(SaveTarget::Desktop));
ui->saveTargetSelectionBox->addItem(tr("Desktop"), QVariant::fromValue(ShortcutTarget::Desktop));
if (!applicationDir.isEmpty())
ui->saveTargetSelectionBox->addItem(tr("Applications"), QVariant::fromValue(SaveTarget::Applications));
ui->saveTargetSelectionBox->addItem(tr("Applications"), QVariant::fromValue(ShortcutTarget::Applications));
}
ui->saveTargetSelectionBox->addItem(tr("Other..."), QVariant::fromValue(SaveTarget::Other));
ui->saveTargetSelectionBox->addItem(tr("Other..."), QVariant::fromValue(ShortcutTarget::Other));
// Populate worlds
if (m_QuickJoinSupported) {
@ -206,17 +206,17 @@ void CreateShortcutDialog::createShortcut()
}
}
auto target = ui->saveTargetSelectionBox->currentData().value<SaveTarget>();
auto target = ui->saveTargetSelectionBox->currentData().value<ShortcutTarget>();
auto name = ui->instNameTextBox->text();
if (name.isEmpty())
name = ui->instNameTextBox->placeholderText();
if (ui->overrideAccountCheckbox->isChecked())
extraArgs.append({ "--profile", ui->accountSelectionBox->currentData().toString() });
ShortcutUtils::Shortcut args{ m_instance.get(), name, targetString, this, extraArgs, InstIconKey };
if (target == SaveTarget::Desktop)
ShortcutUtils::Shortcut args{ m_instance.get(), name, targetString, this, extraArgs, InstIconKey, target };
if (target == ShortcutTarget::Desktop)
ShortcutUtils::createInstanceShortcutOnDesktop(args);
else if (target == SaveTarget::Applications)
else if (target == ShortcutTarget::Applications)
ShortcutUtils::createInstanceShortcutInApplications(args);
else
ShortcutUtils::createInstanceShortcutInOther(args);

View File

@ -54,9 +54,6 @@ class CreateShortcutDialog : public QDialog {
InstancePtr m_instance;
bool m_QuickJoinSupported = false;
// Index representations
enum class SaveTarget { Desktop, Applications, Other };
// Functions
void stateChanged();
};

View File

@ -194,6 +194,20 @@
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="noteLabel">
<property name="text">
<string>Note: If a shortcut is moved after creation, it won't be deleted when deleting the instance.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="noteLabel2">
<property name="text">
<string>You'll need to delete them manually if that is the case.</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@ -21,42 +21,63 @@
#include <QVBoxLayout>
#include "Application.h"
#include "settings/SettingsObject.h"
#include "ui/widgets/IconLabel.h"
#include "ui/widgets/PageContainer.h"
PageDialog::PageDialog(BasePageProvider* pageProvider, QString defaultId, QWidget* parent) : QDialog(parent)
{
setWindowTitle(pageProvider->dialogTitle());
m_container = new PageContainer(pageProvider, defaultId, this);
m_container = new PageContainer(pageProvider, std::move(defaultId), this);
auto* mainLayout = new QVBoxLayout(this);
auto* focusStealer = new QPushButton(this);
mainLayout->addWidget(focusStealer);
focusStealer->setDefault(true);
focusStealer->hide();
QVBoxLayout* mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_container);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
setLayout(mainLayout);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
buttons->button(QDialogButtonBox::Close)->setDefault(true);
buttons->button(QDialogButtonBox::Close)->setText(tr("Close"));
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->button(QDialogButtonBox::Ok)->setText(tr("&OK"));
buttons->button(QDialogButtonBox::Cancel)->setText(tr("&Cancel"));
buttons->button(QDialogButtonBox::Help)->setText(tr("Help"));
buttons->setContentsMargins(6, 0, 6, 0);
m_container->addButtons(buttons);
connect(buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), m_container, SLOT(help()));
connect(buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &PageDialog::accept);
connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &PageDialog::reject);
connect(buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, m_container, &PageContainer::help);
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("PagedGeometry").toByteArray()));
}
void PageDialog::accept()
{
if (handleClose())
QDialog::accept();
}
void PageDialog::closeEvent(QCloseEvent* event)
{
qDebug() << "Paged dialog close requested";
if (m_container->prepareToClose()) {
qDebug() << "Paged dialog close approved";
APPLICATION->settings()->set("PagedGeometry", saveGeometry().toBase64());
qDebug() << "Paged dialog geometry saved";
if (handleClose())
QDialog::closeEvent(event);
}
}
bool PageDialog::handleClose()
{
qDebug() << "Paged dialog close requested";
if (!m_container->prepareToClose())
return false;
qDebug() << "Paged dialog close approved";
APPLICATION->settings()->set("PagedGeometry", saveGeometry().toBase64());
qDebug() << "Paged dialog geometry saved";
emit applied();
return true;
}

View File

@ -25,8 +25,13 @@ class PageDialog : public QDialog {
explicit PageDialog(BasePageProvider* pageProvider, QString defaultId = QString(), QWidget* parent = 0);
virtual ~PageDialog() {}
private slots:
virtual void closeEvent(QCloseEvent* event);
signals:
void applied();
private:
void accept() override;
void closeEvent(QCloseEvent* event) override;
bool handleClose();
private:
PageContainer* m_container;

View File

@ -53,7 +53,7 @@ class APIPage : public QWidget, public BasePage {
explicit APIPage(QWidget* parent = 0);
~APIPage();
QString displayName() const override { return tr("APIs"); }
QString displayName() const override { return tr("Services"); }
QIcon icon() const override { return APPLICATION->getThemedIcon("worlds"); }
QString id() const override { return "apis"; }
QString helpPage() const override { return "APIs"; }

View File

@ -10,7 +10,7 @@
<height>620</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
@ -24,15 +24,20 @@
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Services</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>-216</y>
<width>816</width>
<height>832</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_paste">
<property name="title">
@ -50,7 +55,14 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="pasteTypeComboBox"/>
<widget class="QComboBox" name="pasteTypeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="baseURLLabel">
@ -65,7 +77,7 @@
<item>
<widget class="QLineEdit" name="baseURLEntry">
<property name="placeholderText">
<string/>
<string>Use Default</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
@ -91,30 +103,10 @@
<string>Meta&amp;data Server</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>You can set this to a third-party metadata server to use patched libraries or other hacks.</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="metaURL">
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Enter a custom URL for meta here.</string>
<string>You can set this to a third-party metadata server to use patched libraries or other hacks.</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
@ -127,35 +119,80 @@
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="metaURL">
<property name="placeholderText">
<string>Use Default</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<widget class="QGroupBox" name="groupBox_ua">
<property name="minimumSize">
<size>
<width>20</width>
<height>40</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
<property name="title">
<string>User Agent</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QLineEdit" name="userAgentLineEdit">
<property name="placeholderText">
<string>Use Default</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="userAgentLabel">
<property name="text">
<string>Enter a custom User Agent here. The special string $LAUNCHER_VER will be replaced with the version of the launcher.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>API Keys</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QGroupBox" name="groupBox_msa">
<property name="title">
<string>&amp;Microsoft Authentication</string>
<string>&amp;API Keys</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="msaClientIDLabel">
<property name="text">
<string>&amp;Microsoft Authentation</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>msaClientID</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="msaClientID">
<property name="placeholderText">
<string>Use Default</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
@ -170,99 +207,83 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="msaClientID">
<property name="placeholderText">
<string>(Default)</string>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="modrinthTokenLabel">
<property name="text">
<string>Mod&amp;rinth</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>modrinthToken</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Enter a custom client ID for Microsoft Authentication here.</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_modrinth">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;Modrinth API</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Note: you only need to set this to access private data. Read the &lt;a href=&quot;https://docs.modrinth.com/api/#authentication&quot;&gt;documentation&lt;/a&gt; for more information.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Enter a custom API token for Modrinth here.</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="modrinthToken">
<property name="enabled">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>(None)</string>
<string>Use None</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_flame">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;CurseForge Core API</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Note: you probably don't need to set this if CurseForge already works.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Note: you only need to set this to access private data. Read the &lt;a href=&quot;https://docs.modrinth.com/api/#authentication&quot;&gt;documentation&lt;/a&gt; for more information.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_9">
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="flameKeyLabel">
<property name="text">
<string>Enter a custom API Key for CurseForge here.</string>
<string>&amp;CurseForge</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
@ -273,45 +294,71 @@
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>flameKey</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<item>
<widget class="QLineEdit" name="flameKey">
<property name="enabled">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>(Default)</string>
<string>Use Default</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Technic Client ID</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="label_11">
<widget class="QLabel" name="label_10">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Note: you only need to set this to access private data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>Note: you probably don't need to set this if CurseForge already works.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>&amp;Technic</string>
</property>
<property name="buddy">
<cstring>technicClientID</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="technicClientID">
<property name="placeholderText">
<string>(None)</string>
<string>Use Default</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Enter a custom GUID client ID for Technic here.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Note: you only need to set this to access private data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
@ -319,61 +366,16 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Miscellaneous</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QGroupBox" name="groupBox_ua">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>User Agent</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QLineEdit" name="userAgentLineEdit"/>
</item>
<item>
<widget class="QLabel" name="userAgentLabel">
<property name="text">
<string>Enter a custom User Agent here. The special string $LAUNCHER_VER will be replaced with the version of the launcher.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>

View File

@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
* 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
#include <QDialog>
#include <QLayout>
#include "Application.h"
#include "java/JavaChecker.h"
#include "translations/TranslationsModel.h"
#include "ui/pages/BasePage.h"
#include "ui/widgets/AppearanceWidget.h"
class QTextCharFormat;
class SettingsObject;
class AppearancePage : public AppearanceWidget, public BasePage {
Q_OBJECT
public:
explicit AppearancePage(QWidget* parent = nullptr) : AppearanceWidget(false, parent) { layout()->setContentsMargins(0, 0, 6, 0); }
QString displayName() const override { return tr("Appearance"); }
QIcon icon() const override { return APPLICATION->getThemedIcon("appearance"); }
QString id() const override { return "appearance-settings"; }
QString helpPage() const override { return "Launcher-settings"; }
bool apply() override
{
applySettings();
return true;
}
void retranslate() override { retranslateUi(); }
};

View File

@ -50,7 +50,6 @@
ExternalToolsPage::ExternalToolsPage(QWidget* parent) : QWidget(parent), ui(new Ui::ExternalToolsPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
ui->jsonEditorTextBox->setClearButtonEnabled(true);
@ -128,13 +127,13 @@ void ExternalToolsPage::on_jvisualvmPathBtn_clicked()
QString raw_dir = ui->jvisualvmPathEdit->text();
QString error;
do {
raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), raw_dir);
raw_dir = QFileDialog::getOpenFileName(this, tr("VisualVM Executable"), raw_dir);
if (raw_dir.isEmpty()) {
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!APPLICATION->profilers()["jvisualvm"]->check(cooked_dir, &error)) {
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
QMessageBox::critical(this, tr("Error"), tr("Error while checking VisualVM install:\n%1").arg(error));
continue;
} else {
ui->jvisualvmPathEdit->setText(cooked_dir);
@ -146,9 +145,9 @@ void ExternalToolsPage::on_jvisualvmCheckBtn_clicked()
{
QString error;
if (!APPLICATION->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error)) {
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
QMessageBox::critical(this, tr("Error"), tr("Error while checking VisualVM install:\n%1").arg(error));
} else {
QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK"));
QMessageBox::information(this, tr("OK"), tr("VisualVM setup seems to be OK"));
}
}
@ -187,7 +186,7 @@ void ExternalToolsPage::on_mceditCheckBtn_clicked()
void ExternalToolsPage::on_jsonEditorBrowseBtn_clicked()
{
QString raw_file = QFileDialog::getOpenFileName(this, tr("JSON Editor"),
QString raw_file = QFileDialog::getOpenFileName(this, tr("Text Editor"),
ui->jsonEditorTextBox->text().isEmpty()
#if defined(Q_OS_LINUX)
? QString("/usr/bin")

View File

@ -51,7 +51,7 @@ class ExternalToolsPage : public QWidget, public BasePage {
explicit ExternalToolsPage(QWidget* parent = 0);
~ExternalToolsPage();
QString displayName() const override { return tr("External Tools"); }
QString displayName() const override { return tr("Tools"); }
QIcon icon() const override
{
auto icon = APPLICATION->getThemedIcon("externaltools");

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>673</width>
<height>751</height>
<height>823</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -24,28 +24,43 @@
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string notr="true">Tab 1</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>669</width>
<height>819</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox_2">
<widget class="QGroupBox" name="editorsBox">
<property name="title">
<string notr="true">J&amp;Profiler</string>
<string>&amp;Editors</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&amp;Text Editor</string>
</property>
<property name="buddy">
<cstring>jsonEditorTextBox</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="jprofilerPathEdit"/>
<widget class="QLineEdit" name="jsonEditorTextBox"/>
</item>
<item>
<widget class="QPushButton" name="jprofilerPathBtn">
<widget class="QPushButton" name="jsonEditorBrowseBtn">
<property name="text">
<string>Browse</string>
</property>
@ -54,65 +69,38 @@
</layout>
</item>
<item>
<widget class="QPushButton" name="jprofilerCheckBtn">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Check</string>
<string>Used to edit component JSON files.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="jprofilerLink">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="mceditLabel">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.ej-technologies.com/products/jprofiler/overview.html&quot;&gt;https://www.ej-technologies.com/products/jprofiler/overview.html&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&amp;MCEdit</string>
</property>
<property name="buddy">
<cstring>mceditPathEdit</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string notr="true">J&amp;VisualVM</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="jvisualvmPathEdit"/>
</item>
<item>
<widget class="QPushButton" name="jvisualvmPathBtn">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="jvisualvmCheckBtn">
<property name="text">
<string>Check</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="jvisualvmLink">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://visualvm.github.io/&quot;&gt;https://visualvm.github.io/&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string notr="true">&amp;MCEdit</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
@ -129,6 +117,12 @@
</item>
<item>
<widget class="QPushButton" name="mceditCheckBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Check</string>
</property>
@ -137,7 +131,7 @@
<item>
<widget class="QLabel" name="mceditLink">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.mcedit.net/&quot;&gt;https://www.mcedit.net/&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.mcedit.net/&quot;&gt;MCEdit Website&lt;/a&gt; - Used as world editor in the instance Worlds menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@ -145,28 +139,138 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="editorsBox">
<widget class="QGroupBox" name="profilersBox">
<property name="title">
<string>External Editors (leave empty for system default)</string>
<string>&amp;Profilers</string>
</property>
<layout class="QGridLayout" name="foldersBoxLayout_2">
<item row="0" column="1">
<widget class="QLineEdit" name="jsonEditorTextBox"/>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="labelJsonEditor">
<property name="text">
<string>&amp;Text Editor:</string>
<string>Profilers are accessible through the Launch dropdown menu.</string>
</property>
<property name="buddy">
<cstring>jsonEditorTextBox</cstring>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="jsonEditorBrowseBtn">
<item>
<spacer name="verticalSpacer_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Browse</string>
<string>J&amp;Profiler</string>
</property>
<property name="buddy">
<cstring>jprofilerPathEdit</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLineEdit" name="jprofilerPathEdit"/>
</item>
<item>
<widget class="QPushButton" name="jprofilerPathBtn">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="jprofilerCheckBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Check</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="jprofilerLink">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.ej-technologies.com/products/jprofiler/overview.html&quot;&gt;JProfiler Website&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;VisualVM</string>
</property>
<property name="buddy">
<cstring>jvisualvmPathEdit</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="jvisualvmPathEdit"/>
</item>
<item>
<widget class="QPushButton" name="jvisualvmPathBtn">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="jvisualvmCheckBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Check</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="jvisualvmLink">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://visualvm.github.io/&quot;&gt;VisualVM Website&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@ -180,8 +284,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>216</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>

View File

@ -50,10 +50,22 @@
<x>0</x>
<y>0</y>
<width>535</width>
<height>610</height>
<height>606</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<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>
<widget class="JavaSettingsWidget" name="javaSettings" native="true"/>
</item>
@ -65,78 +77,56 @@
</widget>
<widget class="QWidget" name="management">
<attribute name="title">
<string>Management</string>
<string>Installations</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Downloaded Java Versions</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="VersionSelectWidget" name="managedJavaList" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="managedJavaBtnLayout">
<item>
<widget class="QPushButton" name="downloadJavaButton">
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeJavaButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="refreshJavaButton">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="downloadJavaButton">
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeJavaButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="refreshJavaButton">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="managementSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="VersionSelectWidget" name="managedJavaList" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</widget>
</item>
</layout>
</widget>

View File

@ -81,24 +81,14 @@ LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::Launch
ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name);
ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch);
defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat());
m_languageModel = APPLICATION->translations();
loadSettings();
ui->updateSettingsBox->setHidden(!APPLICATION->updater());
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);
}
LauncherPage::~LauncherPage()
{
delete ui;
delete defaultFormat;
}
bool LauncherPage::apply()
@ -203,9 +193,9 @@ void LauncherPage::on_skinsDirBrowseBtn_clicked()
}
}
void LauncherPage::on_metadataDisableBtn_clicked()
void LauncherPage::on_metadataEnableBtn_clicked()
{
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
ui->metadataWarningLabel->setHidden(ui->metadataEnableBtn->isChecked());
}
void LauncherPage::applySettings()
@ -226,9 +216,6 @@ void LauncherPage::applySettings()
s->set("RequestTimeout", ui->timeoutSecondsSpinBox->value());
// Console settings
QString consoleFontFamily = ui->consoleFont->currentFont().family();
s->set("ConsoleFont", consoleFontFamily);
s->set("ConsoleFontSize", ui->fontSizeBox->value());
s->set("ConsoleMaxLines", ui->lineLimitSpinBox->value());
s->set("ConsoleOverflowStop", ui->checkStopLogging->checkState() != Qt::Unchecked);
@ -269,13 +256,10 @@ void LauncherPage::applySettings()
break;
}
// Cat
s->set("CatOpacity", ui->catOpacitySpinBox->value());
// Mods
s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked());
s->set("ModDependenciesDisabled", ui->dependenciesDisableBtn->isChecked());
s->set("SkipModpackUpdatePrompt", ui->skipModpackUpdatePromptBtn->isChecked());
s->set("ModMetadataDisabled", !ui->metadataEnableBtn->isChecked());
s->set("ModDependenciesDisabled", !ui->dependenciesEnableBtn->isChecked());
s->set("SkipModpackUpdatePrompt", !ui->modpackUpdatePromptBtn->isChecked());
}
void LauncherPage::loadSettings()
{
@ -286,11 +270,6 @@ void LauncherPage::loadSettings()
ui->updateIntervalSpinBox->setValue(APPLICATION->updater()->getUpdateCheckInterval() / 3600);
}
// Toolbar/menu bar settings (not applicable if native menu bar is present)
ui->toolsBox->setEnabled(!QMenuBar().isNativeMenuBar());
#ifdef Q_OS_MACOS
ui->toolsBox->setVisible(!QMenuBar().isNativeMenuBar());
#endif
ui->preferMenuBarCheckBox->setChecked(s->get("MenuBarInsteadOfToolBar").toBool());
ui->numberOfConcurrentTasksSpinBox->setValue(s->get("NumberOfConcurrentTasks").toInt());
@ -299,17 +278,6 @@ void LauncherPage::loadSettings()
ui->timeoutSecondsSpinBox->setValue(s->get("RequestTimeout").toInt());
// Console settings
QString fontFamily = APPLICATION->settings()->get("ConsoleFont").toString();
QFont consoleFont(fontFamily);
ui->consoleFont->setCurrentFont(consoleFont);
bool conversionOk = true;
int fontSize = APPLICATION->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if (!conversionOk) {
fontSize = 11;
}
ui->fontSizeBox->setValue(fontSize);
refreshFontPreview();
ui->lineLimitSpinBox->setValue(s->get("ConsoleMaxLines").toInt());
ui->checkStopLogging->setChecked(s->get("ConsoleOverflowStop").toBool());
@ -342,59 +310,11 @@ void LauncherPage::loadSettings()
}
ui->renamingBehaviorComboBox->setCurrentIndex(renamingModeEnum);
// Cat
ui->catOpacitySpinBox->setValue(s->get("CatOpacity").toInt());
// Mods
ui->metadataDisableBtn->setChecked(s->get("ModMetadataDisabled").toBool());
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
ui->dependenciesDisableBtn->setChecked(s->get("ModDependenciesDisabled").toBool());
ui->skipModpackUpdatePromptBtn->setChecked(s->get("SkipModpackUpdatePrompt").toBool());
}
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);
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(message, 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);
ui->metadataEnableBtn->setChecked(!s->get("ModMetadataDisabled").toBool());
ui->metadataWarningLabel->setHidden(ui->metadataEnableBtn->isChecked());
ui->dependenciesEnableBtn->setChecked(!s->get("ModDependenciesDisabled").toBool());
ui->modpackUpdatePromptBtn->setChecked(!s->get("SkipModpackUpdatePrompt").toBool());
}
void LauncherPage::retranslate()

View File

@ -57,8 +57,8 @@ class LauncherPage : public QWidget, public BasePage {
explicit LauncherPage(QWidget* parent = 0);
~LauncherPage();
QString displayName() const override { return tr("Launcher"); }
QIcon icon() const override { return APPLICATION->getThemedIcon("launcher"); }
QString displayName() const override { return tr("General"); }
QIcon icon() const override { return APPLICATION->getThemedIcon("settings"); }
QString id() const override { return "launcher-settings"; }
QString helpPage() const override { return "Launcher-settings"; }
bool apply() override;
@ -75,23 +75,8 @@ class LauncherPage : public QWidget, public BasePage {
void on_downloadsDirBrowseBtn_clicked();
void on_javaDirBrowseBtn_clicked();
void on_skinsDirBrowseBtn_clicked();
void on_metadataDisableBtn_clicked();
/*!
* Updates the font preview
*/
void refreshFontPreview();
void on_metadataEnableBtn_clicked();
private:
Ui::LauncherPage* ui;
/*!
* Stores the currently selected update channel.
*/
QString m_currentUpdateChannel;
// default format for the font preview...
QTextCharFormat* defaultFormat;
std::shared_ptr<TranslationsModel> m_languageModel;
};

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,6 @@
ProxyPage::ProxyPage(QWidget* parent) : QWidget(parent), ui(new Ui::ProxyPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
loadSettings();
updateCheckboxStuff();

View File

@ -23,184 +23,205 @@
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<widget class="QWidget" name="tabWidgetPage1">
<attribute name="title">
<string notr="true"/>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="proxyPlainTextWarningLabel_2">
<property name="text">
<string>This only applies to the launcher. Minecraft does not accept proxy settings.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="proxyTypeBox">
<property name="title">
<string>Type</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QRadioButton" name="proxyDefaultBtn">
<property name="toolTip">
<string>Uses your system's default proxy settings.</string>
</property>
<property name="text">
<string>&amp;Default</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="proxyNoneBtn">
<property name="text">
<string>&amp;None</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="proxySOCKS5Btn">
<property name="text">
<string>&amp;SOCKS5</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="proxyHTTPBtn">
<property name="text">
<string>&amp;HTTP</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="proxyAddrBox">
<property name="title">
<string>&amp;Address and Port</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="proxyAddrEdit">
<property name="placeholderText">
<string notr="true">127.0.0.1</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="proxyPortEdit">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::PlusMinus</enum>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8080</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="proxyAuthBox">
<property name="title">
<string>Authentication</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="1">
<widget class="QLineEdit" name="proxyUserEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="proxyUsernameLabel">
<property name="text">
<string>&amp;Username:</string>
</property>
<property name="buddy">
<cstring>proxyUserEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="proxyPasswordLabel">
<property name="text">
<string>&amp;Password:</string>
</property>
<property name="buddy">
<cstring>proxyPassEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="proxyPassEdit">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="proxyPlainTextWarningLabel">
<property name="text">
<string>Note: Proxy username and password are stored in plain text inside the launcher's configuration file!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QLabel" name="proxyPlainTextWarningLabel_2">
<property name="text">
<string>This only applies to the launcher. Minecraft does not accept proxy settings.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="proxyTypeBox">
<property name="title">
<string>Type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QRadioButton" name="proxyDefaultBtn">
<property name="toolTip">
<string>Uses your system's default proxy settings.</string>
</property>
<property name="text">
<string>Use S&amp;ystem Settings</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="proxyNoneBtn">
<property name="text">
<string>&amp;None</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="proxySOCKS5Btn">
<property name="text">
<string>&amp;SOCKS5</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="proxyHTTPBtn">
<property name="text">
<string>&amp;HTTP</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyGroup</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="proxyAddrBox">
<property name="title">
<string>&amp;Address and Port</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="proxyAddrEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="placeholderText">
<string notr="true">127.0.0.1</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="proxyPortEdit">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::PlusMinus</enum>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8080</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="proxyAuthBox">
<property name="title">
<string>Authentication</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="proxyUsernameLabel">
<property name="text">
<string>&amp;Username:</string>
</property>
<property name="buddy">
<cstring>proxyUserEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="proxyUserEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="proxyPasswordLabel">
<property name="text">
<string>&amp;Password:</string>
</property>
<property name="buddy">
<cstring>proxyPassEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="proxyPassEdit">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="proxyPlainTextWarningLabel">
<property name="text">
<string>Note: Proxy username and password are stored in plain text inside the launcher's configuration file!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>proxyDefaultBtn</tabstop>
<tabstop>proxyNoneBtn</tabstop>
<tabstop>proxySOCKS5Btn</tabstop>
<tabstop>proxyHTTPBtn</tabstop>
<tabstop>proxyAddrEdit</tabstop>
<tabstop>proxyPortEdit</tabstop>
<tabstop>proxyUserEdit</tabstop>
<tabstop>proxyPassEdit</tabstop>
</tabstops>
<resources/>
<connections/>
<buttongroups>

View File

@ -49,7 +49,7 @@ class InstanceSettingsPage : public MinecraftSettingsWidget, public BasePage {
: MinecraftSettingsWidget(std::move(instance), parent)
{
connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::saveSettings);
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
connect(APPLICATION, &Application::globalSettingsApplied, this, &InstanceSettingsPage::loadSettings);
}
~InstanceSettingsPage() override {}
QString displayName() const override { return tr("Settings"); }

View File

@ -34,37 +34,6 @@ ThemeWizardPage::ThemeWizardPage(QWidget* parent) : BaseWizardPage(parent), ui(n
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"(%1)").arg(APPLICATION->themeManager()->getCatPack())));
}
void ThemeWizardPage::retranslate()
{
ui->retranslateUi(this);
}

View File

@ -17,27 +17,30 @@
*/
#pragma once
#include <ui/widgets/AppearanceWidget.h>
#include <QHBoxLayout>
#include <QWidget>
#include "BaseWizardPage.h"
namespace Ui {
class ThemeWizardPage;
}
class ThemeWizardPage : public BaseWizardPage {
Q_OBJECT
public:
explicit ThemeWizardPage(QWidget* parent = nullptr);
~ThemeWizardPage();
ThemeWizardPage(QWidget* parent = nullptr) : BaseWizardPage(parent)
{
auto layout = new QVBoxLayout(this);
layout->addWidget(&widget);
layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
setTitle(tr("Appearance"));
setSubTitle(tr("Select theme and icons to use"));
}
bool validatePage() override { return true; };
void retranslate() override;
private slots:
void updateIcons();
void updateCat();
void retranslate() override { widget.retranslateUi(); }
private:
Ui::ThemeWizardPage* ui;
AppearanceWidget widget{true};
};

View File

@ -1,371 +0,0 @@
<?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

@ -43,7 +43,7 @@
#include "FileSystem.h"
#include "Json.h"
QString BasicCatPack::path()
QString BasicCatPack::path() const
{
const auto now = QDate::currentDate();
const auto birthday = QDate(now.year(), 11, 1);
@ -100,12 +100,12 @@ QDate ensureDay(int year, int month, int day)
return QDate(year, month, day);
}
QString JsonCatPack::path()
QString JsonCatPack::path() const
{
return path(QDate::currentDate());
}
QString JsonCatPack::path(QDate now)
QString JsonCatPack::path(QDate now) const
{
for (auto var : m_variants) {
QDate startDate = ensureDay(now.year(), var.startTime.month, var.startTime.day);

View File

@ -43,18 +43,18 @@
class CatPack {
public:
virtual ~CatPack() {}
virtual QString id() = 0;
virtual QString name() = 0;
virtual QString path() = 0;
virtual QString id() const = 0;
virtual QString name() const = 0;
virtual QString path() const = 0;
};
class BasicCatPack : public CatPack {
public:
BasicCatPack(QString id, QString name) : m_id(id), m_name(name) {}
BasicCatPack(QString id) : BasicCatPack(id, id) {}
virtual QString id() override { return m_id; }
virtual QString name() override { return m_name; }
virtual QString path() override;
virtual QString id() const override { return m_id; }
virtual QString name() const override { return m_name; }
virtual QString path() const override;
protected:
QString m_id;
@ -65,7 +65,7 @@ class FileCatPack : public BasicCatPack {
public:
FileCatPack(QString id, QFileInfo& fileInfo) : BasicCatPack(id), m_path(fileInfo.absoluteFilePath()) {}
FileCatPack(QFileInfo& fileInfo) : FileCatPack(fileInfo.baseName(), fileInfo) {}
virtual QString path() { return m_path; }
virtual QString path() const { return m_path; }
private:
QString m_path;
@ -83,8 +83,8 @@ class JsonCatPack : public BasicCatPack {
PartialDate endTime;
};
JsonCatPack(QFileInfo& manifestInfo);
virtual QString path() override;
QString path(QDate now);
virtual QString path() const override;
QString path(QDate now) const;
private:
QString m_default_path;

View File

@ -20,7 +20,7 @@
HintOverrideProxyStyle::HintOverrideProxyStyle(QStyle* style) : QProxyStyle(style)
{
setObjectName(style->objectName());
setObjectName(baseStyle()->objectName());
}
int HintOverrideProxyStyle::styleHint(QStyle::StyleHint hint,
@ -31,5 +31,11 @@ int HintOverrideProxyStyle::styleHint(QStyle::StyleHint hint,
if (hint == QStyle::SH_ItemView_ActivateItemOnSingleClick)
return 0;
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
return Qt::LeftButton | Qt::MiddleButton;
if (hint == QStyle::SH_Slider_PageSetButtons)
return Qt::RightButton;
return QProxyStyle::styleHint(hint, option, widget, returnData);
}

View File

@ -47,6 +47,7 @@ struct LogColors {
};
// TODO: rename to Theme; this is not an interface as it contains method implementations
// TODO: make methods const
class ITheme {
public:
virtual ~ITheme() {}

View File

@ -21,8 +21,6 @@
#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";
@ -36,18 +34,3 @@ bool IconTheme::load()
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

@ -22,13 +22,13 @@
class IconTheme {
public:
IconTheme(const QString& id, const QString& path);
IconTheme(const QString& id, const QString& path) : m_id(id), m_path(path) {}
IconTheme() = default;
bool load();
QString id();
QString path();
QString name();
QString id() const { return m_id; }
QString path() const { return m_path; }
QString name() const { return m_name; }
private:
QString m_id;

View File

@ -0,0 +1,273 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2025 TheKodeToad <TheKodeToad@proton.me>
* Copyright (C) 2022 Tayou <git@tayou.org>
*
* 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 "AppearanceWidget.h"
#include "ui_AppearanceWidget.h"
#include <DesktopServices.h>
#include <QGraphicsOpacityEffect>
#include "BuildConfig.h"
#include "ui/themes/ITheme.h"
#include "ui/themes/ThemeManager.h"
AppearanceWidget::AppearanceWidget(bool themesOnly, QWidget* parent)
: QWidget(parent), m_ui(new Ui::AppearanceWidget), m_themesOnly(themesOnly)
{
m_ui->setupUi(this);
m_ui->catPreview->setGraphicsEffect(new QGraphicsOpacityEffect(this));
m_defaultFormat = QTextCharFormat(m_ui->consolePreview->currentCharFormat());
if (themesOnly) {
m_ui->catPackLabel->hide();
m_ui->catPackComboBox->hide();
m_ui->catPackFolder->hide();
m_ui->settingsBox->hide();
m_ui->consolePreview->hide();
m_ui->catPreview->hide();
loadThemeSettings();
} else {
loadSettings();
loadThemeSettings();
updateConsolePreview();
updateCatPreview();
}
connect(m_ui->fontSizeBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AppearanceWidget::updateConsolePreview);
connect(m_ui->consoleFont, &QFontComboBox::currentFontChanged, this, &AppearanceWidget::updateConsolePreview);
connect(m_ui->iconsComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AppearanceWidget::applyIconTheme);
connect(m_ui->widgetStyleComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AppearanceWidget::applyWidgetTheme);
connect(m_ui->catPackComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AppearanceWidget::applyCatTheme);
connect(m_ui->catOpacitySlider, &QAbstractSlider::valueChanged, this, &AppearanceWidget::updateCatPreview);
connect(m_ui->iconsFolder, &QPushButton::clicked, this,
[] { DesktopServices::openPath(APPLICATION->themeManager()->getIconThemesFolder().path()); });
connect(m_ui->widgetStyleFolder, &QPushButton::clicked, this,
[] { DesktopServices::openPath(APPLICATION->themeManager()->getApplicationThemesFolder().path()); });
connect(m_ui->catPackFolder, &QPushButton::clicked, this,
[] { DesktopServices::openPath(APPLICATION->themeManager()->getCatPacksFolder().path()); });
connect(m_ui->reloadThemesButton, &QPushButton::pressed, this, &AppearanceWidget::loadThemeSettings);
}
AppearanceWidget::~AppearanceWidget()
{
delete m_ui;
}
void AppearanceWidget::applySettings()
{
SettingsObjectPtr settings = APPLICATION->settings();
QString consoleFontFamily = m_ui->consoleFont->currentFont().family();
settings->set("ConsoleFont", consoleFontFamily);
settings->set("ConsoleFontSize", m_ui->fontSizeBox->value());
settings->set("CatOpacity", m_ui->catOpacitySlider->value());
}
void AppearanceWidget::loadSettings()
{
QString fontFamily = APPLICATION->settings()->get("ConsoleFont").toString();
QFont consoleFont(fontFamily);
m_ui->consoleFont->setCurrentFont(consoleFont);
bool conversionOk = true;
int fontSize = APPLICATION->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if (!conversionOk) {
fontSize = 11;
}
m_ui->fontSizeBox->setValue(fontSize);
m_ui->catOpacitySlider->setValue(APPLICATION->settings()->get("CatOpacity").toInt());
}
void AppearanceWidget::retranslateUi()
{
m_ui->retranslateUi(this);
}
void AppearanceWidget::applyIconTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalIconTheme = settings->get("IconTheme").toString();
auto newIconTheme = m_ui->iconsComboBox->itemData(index).toString();
if (originalIconTheme != newIconTheme) {
settings->set("IconTheme", newIconTheme);
APPLICATION->themeManager()->applyCurrentlySelectedTheme();
}
}
void AppearanceWidget::applyWidgetTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalAppTheme = settings->get("ApplicationTheme").toString();
auto newAppTheme = m_ui->widgetStyleComboBox->itemData(index).toString();
if (originalAppTheme != newAppTheme) {
settings->set("ApplicationTheme", newAppTheme);
APPLICATION->themeManager()->applyCurrentlySelectedTheme();
}
updateConsolePreview();
}
void AppearanceWidget::applyCatTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalCat = settings->get("BackgroundCat").toString();
auto newCat = m_ui->catPackComboBox->itemData(index).toString();
if (originalCat != newCat) {
settings->set("BackgroundCat", newCat);
}
APPLICATION->currentCatChanged(index);
updateCatPreview();
}
void AppearanceWidget::loadThemeSettings()
{
APPLICATION->themeManager()->refresh();
m_ui->iconsComboBox->blockSignals(true);
m_ui->widgetStyleComboBox->blockSignals(true);
m_ui->catPackComboBox->blockSignals(true);
m_ui->iconsComboBox->clear();
m_ui->widgetStyleComboBox->clear();
m_ui->catPackComboBox->clear();
const SettingsObjectPtr settings = APPLICATION->settings();
const QString currentIconTheme = settings->get("IconTheme").toString();
const auto iconThemes = APPLICATION->themeManager()->getValidIconThemes();
for (int i = 0; i < iconThemes.count(); ++i) {
const IconTheme* theme = iconThemes[i];
QIcon iconForComboBox = QIcon(theme->path() + "/scalable/settings");
m_ui->iconsComboBox->addItem(iconForComboBox, theme->name(), theme->id());
if (currentIconTheme == theme->id())
m_ui->iconsComboBox->setCurrentIndex(i);
}
const QString currentTheme = settings->get("ApplicationTheme").toString();
auto themes = APPLICATION->themeManager()->getValidApplicationThemes();
for (int i = 0; i < themes.count(); ++i) {
ITheme* theme = themes[i];
m_ui->widgetStyleComboBox->addItem(theme->name(), theme->id());
if (!theme->tooltip().isEmpty())
m_ui->widgetStyleComboBox->setItemData(i, theme->tooltip(), Qt::ToolTipRole);
if (currentTheme == theme->id())
m_ui->widgetStyleComboBox->setCurrentIndex(i);
}
if (!m_themesOnly) {
const QString currentCat = settings->get("BackgroundCat").toString();
const auto cats = APPLICATION->themeManager()->getValidCatPacks();
for (int i = 0; i < cats.count(); ++i) {
const CatPack* cat = cats[i];
QIcon catIcon = QIcon(QString("%1").arg(cat->path()));
m_ui->catPackComboBox->addItem(catIcon, cat->name(), cat->id());
if (currentCat == cat->id())
m_ui->catPackComboBox->setCurrentIndex(i);
}
}
m_ui->iconsComboBox->blockSignals(false);
m_ui->widgetStyleComboBox->blockSignals(false);
m_ui->catPackComboBox->blockSignals(false);
}
void AppearanceWidget::updateConsolePreview()
{
const LogColors& colors = APPLICATION->themeManager()->getLogColors();
int fontSize = m_ui->fontSizeBox->value();
QString fontFamily = m_ui->consoleFont->currentFont().family();
m_ui->consolePreview->clear();
m_defaultFormat.setFont(QFont(fontFamily, fontSize));
auto print = [this, colors](const QString& message, MessageLevel::Enum level) {
QTextCharFormat format(m_defaultFormat);
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 = m_ui->consolePreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(message, format);
workCursor.insertBlock();
};
print(QString("%1 version: %2\n")
.arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()),
MessageLevel::Launcher);
QDate today = QDate::currentDate();
if (today.month() == 10 && today.day() == 31)
print(tr("[ERROR] OOoooOOOoooo! A spooky error!"), MessageLevel::Error);
else
print(tr("[ERROR] A spooky error!"), MessageLevel::Error);
print(tr("[INFO] A harmless message..."), MessageLevel::Info);
print(tr("[WARN] A not so spooky warning."), MessageLevel::Warning);
print(tr("[DEBUG] A secret debugging message..."), MessageLevel::Debug);
print(tr("[FATAL] A terrifying fatal error!"), MessageLevel::Fatal);
}
void AppearanceWidget::updateCatPreview()
{
QIcon catPackIcon(APPLICATION->themeManager()->getCatPack());
m_ui->catPreview->setIcon(catPackIcon);
auto effect = dynamic_cast<QGraphicsOpacityEffect*>(m_ui->catPreview->graphicsEffect());
if (effect)
effect->setOpacity(m_ui->catOpacitySlider->value() / 100.0);
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2025 TheKodeToad <TheKodeToad@proton.me>
* Copyright (C) 2022 Tayou <git@tayou.org>
*
* This program is free software: you can redistribute it and/or modify
@ -15,42 +16,47 @@
* 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"
#include <QDialog>
#include <memory>
enum ThemeFields { NONE = 0b0000, ICONS = 0b0001, WIDGETS = 0b0010, CAT = 0b0100 };
#include <Application.h>
#include <translations/TranslationsModel.h>
#include <QTextCursor>
#include "java/JavaChecker.h"
#include "ui/pages/BasePage.h"
class QTextCharFormat;
class SettingsObject;
namespace Ui {
class ThemeCustomizationWidget;
class AppearanceWidget;
}
class ThemeCustomizationWidget : public QWidget {
class AppearanceWidget : public QWidget {
Q_OBJECT
public:
explicit ThemeCustomizationWidget(QWidget* parent = nullptr);
~ThemeCustomizationWidget() override;
void showFeatures(ThemeFields features);
explicit AppearanceWidget(bool simple, QWidget* parent = 0);
virtual ~AppearanceWidget();
public:
void applySettings();
void loadSettings();
void retranslate();
void retranslateUi();
private slots:
private:
void applyIconTheme(int index);
void applyWidgetTheme(int index);
void applyCatTheme(int index);
void refresh();
void loadThemeSettings();
signals:
int currentIconThemeChanged(int index);
int currentWidgetThemeChanged(int index);
int currentCatChanged(int index);
void updateConsolePreview();
void updateCatPreview();
private:
Ui::ThemeCustomizationWidget* ui;
Ui::AppearanceWidget* m_ui;
QTextCharFormat m_defaultFormat;
bool m_themesOnly;
};

View File

@ -0,0 +1,594 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AppearanceWidget</class>
<widget class="QWidget" name="AppearanceWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>700</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
<item>
<widget class="QGroupBox" name="themingBox">
<property name="title">
<string/>
</property>
<property name="flat">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="3">
<widget class="QPushButton" name="catPackFolder">
<property name="toolTip">
<string>View cat packs folder.</string>
</property>
<property name="text">
<string>Open Folder</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="widgetStyleFolder">
<property name="toolTip">
<string>View widget themes folder.</string>
</property>
<property name="text">
<string>Open Folder</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="iconsFolder">
<property name="toolTip">
<string>View icon themes folder.</string>
</property>
<property name="text">
<string>Open Folder</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="catPackLabel">
<property name="text">
<string>&amp;Cat Pack:</string>
</property>
<property name="buddy">
<cstring>catPackComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="catPackComboBox"/>
</item>
<item row="1" column="2">
<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="0" column="2">
<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="3" column="2">
<widget class="QPushButton" name="reloadThemesButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reload All</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="widgetStyleLabel">
<property name="text">
<string>Theme:</string>
</property>
<property name="buddy">
<cstring>widgetStyleComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="iconsLabel">
<property name="text">
<string>&amp;Icons:</string>
</property>
<property name="buddy">
<cstring>iconsComboBox</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="settingsBox">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Console Font:</string>
</property>
</widget>
</item>
<item>
<widget class="QFontComboBox" name="consoleFont"/>
</item>
<item>
<widget class="QSpinBox" name="fontSizeBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>16</number>
</property>
<property name="value">
<number>11</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="catOpacityLabel">
<property name="text">
<string>Cat Opacity</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_2" native="true">
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<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>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<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="3" column="3">
<widget class="QLabel" name="label_5">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Opaque</string>
</property>
</widget>
</item>
<item row="3" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_4">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Transparent</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QSlider" name="catOpacitySlider">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="previewBox">
<property name="title">
<string>Preview</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="catPreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>128</width>
<height>256</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="icon1">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="new">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon2">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="centralmods">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon3">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="viewfolder">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon4">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="launch">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon5">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="copy">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon6">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="export">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon7">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="delete">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon8">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</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>
<item>
<widget class="QPushButton" name="icon9">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="settings">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="icon10">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="cat">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTextEdit" name="consolePreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>widgetStyleComboBox</tabstop>
<tabstop>widgetStyleFolder</tabstop>
<tabstop>iconsComboBox</tabstop>
<tabstop>iconsFolder</tabstop>
<tabstop>catPackComboBox</tabstop>
<tabstop>catPackFolder</tabstop>
<tabstop>reloadThemesButton</tabstop>
<tabstop>consoleFont</tabstop>
<tabstop>fontSizeBox</tabstop>
<tabstop>catOpacitySlider</tabstop>
<tabstop>consolePreview</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -44,13 +44,14 @@ CustomCommands::~CustomCommands()
CustomCommands::CustomCommands(QWidget* parent) : QWidget(parent), ui(new Ui::CustomCommands)
{
ui->setupUi(this);
connect(ui->overrideCheckBox, &QCheckBox::toggled, ui->customCommandsWidget, &QWidget::setEnabled);
}
void CustomCommands::initialize(bool checkable, bool checked, const QString& prelaunch, const QString& wrapper, const QString& postexit)
{
ui->customCommandsGroupBox->setCheckable(checkable);
ui->overrideCheckBox->setVisible(checkable);
if (checkable) {
ui->customCommandsGroupBox->setChecked(checked);
ui->overrideCheckBox->setChecked(checked);
}
ui->preLaunchCmdTextBox->setText(prelaunch);
ui->wrapperCmdTextBox->setText(wrapper);
@ -64,9 +65,9 @@ void CustomCommands::retranslate()
bool CustomCommands::checked() const
{
if (!ui->customCommandsGroupBox->isCheckable())
if (!ui->overrideCheckBox->isVisible())
return true;
return ui->customCommandsGroupBox->isChecked();
return ui->overrideCheckBox->isChecked();
}
QString CustomCommands::prelaunchCommand() const

View File

@ -24,58 +24,100 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="customCommandsGroupBox">
<widget class="QCheckBox" name="overrideCheckBox">
<property name="text">
<string>Override &amp;Global Settings</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="customCommandsWidget" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;Custom Commands</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelPreLaunchCmd">
<property name="text">
<string>&amp;Pre-launch command:</string>
<string>&amp;Pre-launch Command</string>
</property>
<property name="buddy">
<cstring>preLaunchCmdTextBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
<item row="5" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
</item>
<item row="4" column="0">
<widget class="QLineEdit" name="wrapperCmdTextBox"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="labelPostExitCmd">
<property name="text">
<string>P&amp;ost-exit Command</string>
</property>
<property name="buddy">
<cstring>labelPostExitCmd</cstring>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLineEdit" name="postExitCmdTextBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelWrapperCmd">
<property name="text">
<string>&amp;Wrapper command:</string>
<string>&amp;Wrapper Command</string>
</property>
<property name="buddy">
<cstring>wrapperCmdTextBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="wrapperCmdTextBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPostExitCmd">
<property name="text">
<string>P&amp;ost-exit command:</string>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="buddy">
<cstring>postExitCmdTextBox</cstring>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="postExitCmdTextBox"/>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>

View File

@ -50,6 +50,8 @@ EnvironmentVariables::EnvironmentVariables(QWidget* parent) : QWidget(parent), u
});
connect(ui->clear, &QPushButton::clicked, this, [this] { ui->list->clear(); });
connect(ui->overrideCheckBox, &QCheckBox::toggled, ui->settingsWidget, &QWidget::setEnabled);
}
EnvironmentVariables::~EnvironmentVariables()
@ -60,8 +62,8 @@ EnvironmentVariables::~EnvironmentVariables()
void EnvironmentVariables::initialize(bool instance, bool override, const QMap<QString, QVariant>& value)
{
// update widgets to settings
ui->groupBox->setCheckable(instance);
ui->groupBox->setChecked(override);
ui->overrideCheckBox->setVisible(instance);
ui->overrideCheckBox->setChecked(override);
// populate
ui->list->clear();
@ -94,9 +96,9 @@ void EnvironmentVariables::retranslate()
bool EnvironmentVariables::override() const
{
if (!ui->groupBox->isCheckable())
if (!ui->overrideCheckBox->isVisible())
return false;
return ui->groupBox->isChecked();
return ui->overrideCheckBox->isChecked();
}
QMap<QString, QVariant> EnvironmentVariables::value() const

View File

@ -14,27 +14,72 @@
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>&amp;Environment Variables</string>
<widget class="QCheckBox" name="overrideCheckBox">
<property name="text">
<string>Override &amp;Global Settings</string>
</property>
<property name="checkable">
<property name="checked">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
</widget>
</item>
<item>
<widget class="QWidget" name="settingsWidget" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<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>
<layout class="QHBoxLayout" name="buttons">
<item>
<widget class="QPushButton" name="add">
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="clear">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeWidget" name="list">
<property name="alternatingRowColors">
@ -67,44 +112,6 @@
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="buttons">
<item>
<widget class="QPushButton" name="add">
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="remove">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -289,26 +289,18 @@ void JavaSettingsWidget::updateThresholds()
unsigned int maxMem = m_ui->maxMemSpinBox->value();
unsigned int minMem = m_ui->minMemSpinBox->value();
QString iconName;
const QString warningColour(QStringLiteral("<span style='color:#f5c211'>%1</span>"));
if (maxMem >= sysMiB) {
iconName = "status-bad";
m_ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
m_ui->labelMaxMemNotice->setText(QString("<span style='color:red'>%1</span>").arg(tr("Your maximum memory allocation exceeds your system memory capacity.")));
m_ui->labelMaxMemNotice->show();
} else if (maxMem > (sysMiB * 0.9)) {
iconName = "status-yellow";
m_ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
m_ui->labelMaxMemNotice->setText(warningColour.arg(tr("Your maximum memory allocation is close to your system memory capacity.")));
m_ui->labelMaxMemNotice->show();
} else if (maxMem < minMem) {
iconName = "status-yellow";
m_ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
m_ui->labelMaxMemNotice->setText(warningColour.arg(tr("Your maximum memory allocation is below the minimum memory allocation.")));
m_ui->labelMaxMemNotice->show();
} else {
iconName = "status-good";
m_ui->labelMaxMemIcon->setToolTip("");
}
{
auto height = m_ui->labelMaxMemIcon->fontInfo().pixelSize();
QIcon icon = APPLICATION->getThemedIcon(iconName);
QPixmap pix = icon.pixmap(height, height);
m_ui->labelMaxMemIcon->setPixmap(pix);
m_ui->labelMaxMemNotice->hide();
}
}

View File

@ -65,4 +65,4 @@ class JavaSettingsWidget : public QWidget {
InstancePtr m_instance;
Ui::JavaSettingsWidget* m_ui;
unique_qobject_ptr<JavaCommon::TestCheck> m_checker;
};
};

View File

@ -7,13 +7,13 @@
<x>0</x>
<y>0</y>
<width>500</width>
<height>600</height>
<height>1000</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
<item>
<widget class="QGroupBox" name="javaInstallationGroupBox">
<property name="enabled">
@ -29,53 +29,92 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="6" column="0">
<item row="7" column="0">
<widget class="QCheckBox" name="autodetectJavaCheckBox">
<property name="text">
<string>Auto-&amp;detect Java version</string>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="javaPathTextBox"/>
<widget class="QPushButton" name="javaDetectBtn">
<property name="text">
<string>&amp;Detect</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="javaBrowseBtn">
<property name="text">
<string>Browse</string>
<string>&amp;Browse</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<item row="10" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="javaDownloadBtn">
<property name="text">
<string>Download Java</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="javaDetectBtn">
<property name="text">
<string>Auto-detect...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="javaTestBtn">
<property name="text">
<string>Test</string>
<string>Test S&amp;ettings</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="javaDownloadBtn">
<property name="text">
<string>Open Java &amp;Downloader</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="7" column="0">
<item row="9" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="autodownloadJavaCheckBox">
<property name="toolTip">
<string>Automatically downloads and selects the Java build recommended by Mojang.</string>
@ -86,6 +125,29 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="skipCompatibilityCheckBox">
<property name="toolTip">
<string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
</property>
<property name="text">
<string>Skip Java compatibility checks</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="javaPathTextBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Java &amp;Executable</string>
</property>
<property name="buddy">
<cstring>javaPathTextBox</cstring>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="skipWizardCheckBox">
<property name="toolTip">
<string>If enabled, the launcher won't prompt you to choose a Java version if one is not found on startup.</string>
@ -96,14 +158,20 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="skipCompatibilityCheckBox">
<property name="toolTip">
<string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="text">
<string>Skip Java compatibility checks</string>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
@ -122,23 +190,29 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="1,0,0">
<item row="2" column="0">
<widget class="QLabel" name="labelPermGen">
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="labelMaxMemNotice">
<property name="text">
<string>PermGen (Java 7 and earlier):</string>
<string>Memory Notice</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelMinMem">
<item row="2" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Minimum memory allocation:</string>
<string>(-XX:PermSize)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="permGenSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>The amount of memory available to store loaded Java classes.</string>
</property>
@ -149,7 +223,7 @@
<number>4</number>
</property>
<property name="maximum">
<number>999999999</number>
<number>1048576</number>
</property>
<property name="singleStep">
<number>8</number>
@ -159,28 +233,14 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelMaxMem">
<property name="text">
<string>Maximum memory allocation:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="labelMaxMemIcon">
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="buddy">
<cstring>maxMemSpinBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="maxMemSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>The maximum amount of memory Minecraft is allowed to use.</string>
</property>
@ -201,8 +261,21 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>(-Xmx)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="minMemSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>The amount of memory Minecraft is started with.</string>
</property>
@ -223,6 +296,56 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>&amp;PermGen Size:</string>
</property>
<property name="buddy">
<cstring>permGenSpinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>(-Xms)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelMaxMem">
<property name="text">
<string>Ma&amp;ximum Memory Usage:</string>
</property>
<property name="buddy">
<cstring>maxMemSpinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelMinMem">
<property name="text">
<string>M&amp;inimum Memory Usage:</string>
</property>
<property name="buddy">
<cstring>minMemSpinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -251,14 +374,14 @@
</widget>
<tabstops>
<tabstop>javaPathTextBox</tabstop>
<tabstop>javaBrowseBtn</tabstop>
<tabstop>javaDownloadBtn</tabstop>
<tabstop>javaDetectBtn</tabstop>
<tabstop>javaTestBtn</tabstop>
<tabstop>javaBrowseBtn</tabstop>
<tabstop>skipCompatibilityCheckBox</tabstop>
<tabstop>skipWizardCheckBox</tabstop>
<tabstop>autodetectJavaCheckBox</tabstop>
<tabstop>autodownloadJavaCheckBox</tabstop>
<tabstop>javaTestBtn</tabstop>
<tabstop>javaDownloadBtn</tabstop>
<tabstop>minMemSpinBox</tabstop>
<tabstop>maxMemSpinBox</tabstop>
<tabstop>permGenSpinBox</tabstop>

View File

@ -41,6 +41,8 @@
#include <QFileDialog>
#include "Application.h"
#include "BuildConfig.h"
#include "Json.h"
#include "minecraft/PackProfile.h"
#include "minecraft/WorldList.h"
#include "minecraft/auth/AccountList.h"
#include "settings/Setting.h"
@ -51,16 +53,13 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstancePtr instance,
m_ui->setupUi(this);
if (m_instance == nullptr) {
for (int i = m_ui->settingsTabs->count() - 1; i >= 0; --i) {
const QString name = m_ui->settingsTabs->widget(i)->objectName();
if (name == "javaPage" || name == "launchPage")
m_ui->settingsTabs->removeTab(i);
}
m_ui->settingsTabs->removeTab(1);
m_ui->openGlobalSettingsButton->setVisible(false);
m_ui->instanceAccountGroupBox->hide();
m_ui->serverJoinGroupBox->hide();
m_ui->globalDataPacksGroupBox->hide();
m_ui->loaderGroup->hide();
} else {
m_javaSettings = new JavaSettingsWidget(m_instance, this);
m_ui->javaScrollArea->setWidget(m_javaSettings);
@ -74,7 +73,6 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstancePtr instance,
tr("<span style=\" font-weight:600; color:#f5c211;\">Warning</span><span style=\" color:#f5c211;\">: The maximized option is "
"not fully supported on this Minecraft version.</span>"));
m_ui->miscellaneousSettingsBox->setCheckable(true);
m_ui->consoleSettingsBox->setCheckable(true);
m_ui->windowSizeGroupBox->setCheckable(true);
m_ui->nativeWorkaroundsGroupBox->setCheckable(true);
@ -108,6 +106,17 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstancePtr instance,
});
connect(m_ui->dataPacksPathEdit, &QLineEdit::editingFinished, this, &MinecraftSettingsWidget::editedDataPacksPath);
connect(m_ui->dataPacksPathBrowse, &QPushButton::clicked, this, &MinecraftSettingsWidget::selectDataPacksFolder);
connect(m_ui->loaderGroup, &QGroupBox::toggled, this, [this](bool value) {
m_instance->settings()->set("OverrideModDownloadLoaders", value);
if (!value)
m_instance->settings()->reset("ModDownloadLoaders");
});
connect(m_ui->neoForge, &QCheckBox::stateChanged, this, &MinecraftSettingsWidget::selectedLoadersChanged);
connect(m_ui->forge, &QCheckBox::stateChanged, this, &MinecraftSettingsWidget::selectedLoadersChanged);
connect(m_ui->fabric, &QCheckBox::stateChanged, this, &MinecraftSettingsWidget::selectedLoadersChanged);
connect(m_ui->quilt, &QCheckBox::stateChanged, this, &MinecraftSettingsWidget::selectedLoadersChanged);
connect(m_ui->liteLoader, &QCheckBox::stateChanged, this, &MinecraftSettingsWidget::selectedLoadersChanged);
}
m_ui->maximizedWarning->hide();
@ -150,11 +159,13 @@ void MinecraftSettingsWidget::loadSettings()
settings = APPLICATION->settings();
// Game Window
m_ui->windowSizeGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideWindow").toBool());
m_ui->windowSizeGroupBox->setChecked(settings->get("OverrideWindow").toBool());
m_ui->windowSizeGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideWindow").toBool() ||
settings->get("OverrideMiscellaneous").toBool());
m_ui->maximizedCheckBox->setChecked(settings->get("LaunchMaximized").toBool());
m_ui->windowWidthSpinBox->setValue(settings->get("MinecraftWinWidth").toInt());
m_ui->windowHeightSpinBox->setValue(settings->get("MinecraftWinHeight").toInt());
m_ui->closeAfterLaunchCheck->setChecked(settings->get("CloseAfterLaunch").toBool());
m_ui->quitAfterGameStopCheck->setChecked(settings->get("QuitAfterGameStop").toBool());
// Game Time
m_ui->gameTimeGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideGameTime").toBool());
@ -169,11 +180,6 @@ void MinecraftSettingsWidget::loadSettings()
m_ui->autoCloseConsoleCheck->setChecked(settings->get("AutoCloseConsole").toBool());
m_ui->showConsoleErrorCheck->setChecked(settings->get("ShowConsoleOnError").toBool());
// Miscellaneous
m_ui->miscellaneousSettingsBox->setChecked(settings->get("OverrideMiscellaneous").toBool());
m_ui->closeAfterLaunchCheck->setChecked(settings->get("CloseAfterLaunch").toBool());
m_ui->quitAfterGameStopCheck->setChecked(settings->get("QuitAfterGameStop").toBool());
if (m_javaSettings != nullptr)
m_javaSettings->loadSettings();
@ -238,6 +244,35 @@ void MinecraftSettingsWidget::loadSettings()
m_ui->instanceAccountGroupBox->setChecked(settings->get("UseAccountForInstance").toBool());
updateAccountsMenu(*settings);
m_ui->loaderGroup->blockSignals(true);
m_ui->neoForge->blockSignals(true);
m_ui->forge->blockSignals(true);
m_ui->fabric->blockSignals(true);
m_ui->quilt->blockSignals(true);
m_ui->liteLoader->blockSignals(true);
auto instLoaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
m_ui->loaderGroup->setChecked(settings->get("OverrideModDownloadLoaders").toBool());
auto loaders = Json::toStringList(settings->get("ModDownloadLoaders").toString());
if (loaders.isEmpty()) {
m_ui->neoForge->setChecked(instLoaders & ModPlatform::NeoForge);
m_ui->forge->setChecked(instLoaders & ModPlatform::Forge);
m_ui->fabric->setChecked(instLoaders & ModPlatform::Fabric);
m_ui->quilt->setChecked(instLoaders & ModPlatform::Quilt);
m_ui->liteLoader->setChecked(instLoaders & ModPlatform::LiteLoader);
} else {
m_ui->neoForge->setChecked(loaders.contains(getModLoaderAsString(ModPlatform::NeoForge)));
m_ui->forge->setChecked(loaders.contains(getModLoaderAsString(ModPlatform::Forge)));
m_ui->fabric->setChecked(loaders.contains(getModLoaderAsString(ModPlatform::Fabric)));
m_ui->quilt->setChecked(loaders.contains(getModLoaderAsString(ModPlatform::Quilt)));
m_ui->liteLoader->setChecked(loaders.contains(getModLoaderAsString(ModPlatform::LiteLoader)));
}
m_ui->loaderGroup->blockSignals(false);
m_ui->neoForge->blockSignals(false);
m_ui->forge->blockSignals(false);
m_ui->fabric->blockSignals(false);
m_ui->quilt->blockSignals(false);
m_ui->liteLoader->blockSignals(false);
}
m_ui->legacySettingsGroupBox->setChecked(settings->get("OverrideLegacySettings").toBool());
@ -263,20 +298,6 @@ void MinecraftSettingsWidget::saveSettings()
{
SettingsObject::Lock lock(settings);
// Miscellaneous
bool miscellaneous = m_instance == nullptr || m_ui->miscellaneousSettingsBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideMiscellaneous", miscellaneous);
if (miscellaneous) {
settings->set("CloseAfterLaunch", m_ui->closeAfterLaunchCheck->isChecked());
settings->set("QuitAfterGameStop", m_ui->quitAfterGameStopCheck->isChecked());
} else {
settings->reset("CloseAfterLaunch");
settings->reset("QuitAfterGameStop");
}
// Console
bool console = m_instance == nullptr || m_ui->consoleSettingsBox->isChecked();
@ -293,20 +314,26 @@ void MinecraftSettingsWidget::saveSettings()
settings->reset("ShowConsoleOnError");
}
// Window Size
// Game Window
bool window = m_instance == nullptr || m_ui->windowSizeGroupBox->isChecked();
if (m_instance != nullptr)
if (m_instance != nullptr) {
settings->set("OverrideWindow", window);
settings->set("OverrideMiscellaneous", window);
}
if (window) {
settings->set("LaunchMaximized", m_ui->maximizedCheckBox->isChecked());
settings->set("MinecraftWinWidth", m_ui->windowWidthSpinBox->value());
settings->set("MinecraftWinHeight", m_ui->windowHeightSpinBox->value());
settings->set("CloseAfterLaunch", m_ui->closeAfterLaunchCheck->isChecked());
settings->set("QuitAfterGameStop", m_ui->quitAfterGameStopCheck->isChecked());
} else {
settings->reset("LaunchMaximized");
settings->reset("MinecraftWinWidth");
settings->reset("MinecraftWinHeight");
settings->reset("CloseAfterLaunch");
settings->reset("QuitAfterGameStop");
}
// Custom Commands
@ -504,3 +531,19 @@ void MinecraftSettingsWidget::selectDataPacksFolder()
m_ui->dataPacksPathEdit->setText(path);
m_instance->settings()->set("GlobalDataPacksPath", path);
}
void MinecraftSettingsWidget::selectedLoadersChanged()
{
QStringList loaders;
if (m_ui->neoForge->isChecked())
loaders << getModLoaderAsString(ModPlatform::NeoForge);
if (m_ui->forge->isChecked())
loaders << getModLoaderAsString(ModPlatform::Forge);
if (m_ui->fabric->isChecked())
loaders << getModLoaderAsString(ModPlatform::Fabric);
if (m_ui->quilt->isChecked())
loaders << getModLoaderAsString(ModPlatform::Quilt);
if (m_ui->liteLoader->isChecked())
loaders << getModLoaderAsString(ModPlatform::LiteLoader);
m_instance->settings()->set("ModDownloadLoaders", Json::fromStringList(loaders));
}

View File

@ -56,6 +56,8 @@ class MinecraftSettingsWidget : public QWidget {
void openGlobalSettings();
void updateAccountsMenu(const SettingsObject& settings);
bool isQuickPlaySupported();
private slots:
void selectedLoadersChanged();
void editedDataPacksPath();
void selectDataPacksFolder();

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>648</width>
<height>400</height>
<height>600</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -51,9 +51,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -61,9 +58,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-166</y>
<width>610</width>
<height>768</height>
<y>0</y>
<width>603</width>
<height>1042</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -81,15 +78,8 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="maximizedCheckBox">
<property name="text">
<string>Start Minecraft maximized</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="6">
<widget class="QLabel" name="maximizedWarning">
<property name="toolTip">
<string>The base game only supports resolution. In order to simulate the maximized behaviour the current implementation approximates the maximum display size.</string>
@ -99,52 +89,165 @@
</property>
</widget>
</item>
<item row="5" column="0" colspan="6">
<widget class="QCheckBox" name="quitAfterGameStopCheck">
<property name="text">
<string>When the game window closes, quit the launcher</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="6">
<widget class="QCheckBox" name="maximizedCheckBox">
<property name="text">
<string>Start Minecraft maximized</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="6">
<widget class="QCheckBox" name="closeAfterLaunchCheck">
<property name="text">
<string>When the game window opens, hide the launcher</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QSpinBox" name="windowWidthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>854</number>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="windowHeightSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="value">
<number>480</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelWindowWidth">
<property name="text">
<string>&amp;Window Size:</string>
</property>
<property name="buddy">
<cstring>windowWidthSpinBox</cstring>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>×</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLabel" name="label_2">
<property name="text">
<string>pixels</string>
</property>
</widget>
</item>
<item row="2" column="5">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="consoleSettingsBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;Console Window</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayoutWindowSize">
<item row="1" column="0">
<widget class="QLabel" name="labelWindowHeight">
<property name="text">
<string>Window height:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelWindowWidth">
<property name="text">
<string>Window width:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="windowWidthSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>854</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="windowHeightSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="value">
<number>480</number>
</property>
</widget>
</item>
</layout>
<widget class="QCheckBox" name="showConsoleCheck">
<property name="text">
<string>When the game is launched, show the console window</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showConsoleErrorCheck">
<property name="text">
<string>When the game crashes, show the console window</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoCloseConsoleCheck">
<property name="text">
<string>When the game quits, hide the console window</string>
</property>
</widget>
</item>
</layout>
</widget>
@ -162,7 +265,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_18">
<item>
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Allows installing data packs across all worlds if an applicable mod is installed.
It is most likely you will need to change the path - please refer to the mod's website.</string>
@ -186,14 +289,14 @@ It is most likely you will need to change the path - please refer to the mod's w
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Folder Path</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="dataPacksPathEdit">
<property name="placeholderText">
@ -260,67 +363,156 @@ It is most likely you will need to change the path - please refer to the mod's w
</widget>
</item>
<item>
<widget class="QGroupBox" name="consoleSettingsBox">
<property name="enabled">
<bool>true</bool>
</property>
<widget class="QGroupBox" name="instanceAccountGroupBox">
<property name="title">
<string>&amp;Console</string>
<string>Override &amp;Default Account</string>
</property>
<property name="checkable">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="showConsoleCheck">
<widget class="QLabel" name="instanceAccountNameLabel">
<property name="text">
<string>Show console while the game is running</string>
<string>Account:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoCloseConsoleCheck">
<property name="text">
<string>Automatically close console when the game quits</string>
<widget class="QComboBox" name="instanceAccountSelector">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showConsoleErrorCheck">
<property name="text">
<string>Show console when the game crashes</string>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="miscellaneousSettingsBox">
<widget class="QGroupBox" name="serverJoinGroupBox">
<property name="title">
<string>&amp;Miscellaneous</string>
<string>Enable Auto-&amp;join</string>
</property>
<property name="checkable">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QCheckBox" name="closeAfterLaunchCheck">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QComboBox" name="worldsCb">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="worldJoinButton">
<property name="text">
<string>Close the launcher after game window opens</string>
<string>Singleplayer world:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="serverJoinAddressButton">
<property name="text">
<string>Server address:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="serverJoinAddress">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="loaderGroup">
<property name="title">
<string>Override Mod Download &amp;Loaders</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="neoForge">
<property name="text">
<string>NeoForge</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="quitAfterGameStopCheck">
<widget class="QCheckBox" name="forge">
<property name="text">
<string>Quit the launcher after game window closes</string>
<string>Forge</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fabric">
<property name="text">
<string>Fabric</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="quilt">
<property name="text">
<string>Quilt</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="liteLoader">
<property name="text">
<string>LiteLoader</string>
</property>
</widget>
</item>
@ -362,7 +554,7 @@ It is most likely you will need to change the path - please refer to the mod's w
<x>0</x>
<y>0</y>
<width>624</width>
<height>291</height>
<height>487</height>
</rect>
</property>
</widget>
@ -377,9 +569,6 @@ It is most likely you will need to change the path - please refer to the mod's w
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QScrollArea" name="scrollArea_2">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -388,8 +577,8 @@ It is most likely you will need to change the path - please refer to the mod's w
<rect>
<x>0</x>
<y>0</y>
<width>610</width>
<height>439</height>
<width>624</width>
<height>487</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
@ -432,49 +621,68 @@ It is most likely you will need to change the path - please refer to the mod's w
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QFormLayout" name="formLayout_2">
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<item row="2" column="0">
<widget class="QCheckBox" name="useNativeOpenALCheck">
<property name="text">
<string>Use system installation of OpenAL</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelGLFWPath">
<property name="text">
<string>&amp;GLFW library path</string>
<string>&amp;GLFW library path:</string>
</property>
<property name="buddy">
<cstring>lineEditGLFWPath</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="useNativeGLFWCheck">
<property name="text">
<string>Use system installation of GLFW</string>
<item row="4" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditGLFWPath">
<property name="enabled">
<bool>false</bool>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<item row="6" column="0">
<widget class="QLabel" name="labelOpenALPath">
<property name="text">
<string>&amp;OpenAL library path</string>
<string>&amp;OpenAL library path:</string>
</property>
<property name="buddy">
<cstring>lineEditOpenALPath</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditGLFWPath">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="useNativeGLFWCheck">
<property name="text">
<string>Use system installation of GLFW</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="useNativeOpenALCheck">
<property name="text">
<string>Use system installation of OpenAL</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="lineEditOpenALPath">
<property name="enabled">
<bool>false</bool>
@ -561,115 +769,6 @@ It is most likely you will need to change the path - please refer to the mod's w
</item>
</layout>
</widget>
<widget class="QWidget" name="launchPage">
<attribute name="title">
<string>Launch</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QScrollArea" name="scrollArea_3">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_5">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>624</width>
<height>291</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<widget class="QGroupBox" name="instanceAccountGroupBox">
<property name="title">
<string>Override default &amp;account</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<layout class="QGridLayout" name="instanceAccountLayout">
<item row="0" column="0">
<widget class="QLabel" name="instanceAccountNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Account:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="instanceAccountSelector"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="serverJoinGroupBox">
<property name="title">
<string>Set a &amp;target to join on launch</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QRadioButton" name="serverJoinAddressButton">
<property name="text">
<string>Server address:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="serverJoinAddress"/>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="worldJoinButton">
<property name="text">
<string>Singleplayer world</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="worldsCb"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="customCommandsPage">
<attribute name="title">
<string>Custom Commands</string>
@ -685,6 +784,18 @@ It is most likely you will need to change the path - please refer to the mod's w
<string>Environment Variables</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_16">
<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>
<widget class="EnvironmentVariables" name="environmentVariables" native="true"/>
</item>
@ -711,31 +822,19 @@ It is most likely you will need to change the path - please refer to the mod's w
<tabstops>
<tabstop>openGlobalSettingsButton</tabstop>
<tabstop>settingsTabs</tabstop>
<tabstop>scrollArea</tabstop>
<tabstop>maximizedCheckBox</tabstop>
<tabstop>windowWidthSpinBox</tabstop>
<tabstop>windowHeightSpinBox</tabstop>
<tabstop>windowWidthSpinBox</tabstop>
<tabstop>closeAfterLaunchCheck</tabstop>
<tabstop>quitAfterGameStopCheck</tabstop>
<tabstop>showConsoleCheck</tabstop>
<tabstop>showConsoleErrorCheck</tabstop>
<tabstop>autoCloseConsoleCheck</tabstop>
<tabstop>showGameTime</tabstop>
<tabstop>recordGameTime</tabstop>
<tabstop>showGlobalGameTime</tabstop>
<tabstop>showGameTimeWithoutDays</tabstop>
<tabstop>showConsoleCheck</tabstop>
<tabstop>autoCloseConsoleCheck</tabstop>
<tabstop>showConsoleErrorCheck</tabstop>
<tabstop>closeAfterLaunchCheck</tabstop>
<tabstop>quitAfterGameStopCheck</tabstop>
<tabstop>javaScrollArea</tabstop>
<tabstop>scrollArea_2</tabstop>
<tabstop>onlineFixes</tabstop>
<tabstop>useNativeGLFWCheck</tabstop>
<tabstop>lineEditGLFWPath</tabstop>
<tabstop>useNativeOpenALCheck</tabstop>
<tabstop>lineEditOpenALPath</tabstop>
<tabstop>perfomanceGroupBox</tabstop>
<tabstop>enableFeralGamemodeCheck</tabstop>
<tabstop>enableMangoHud</tabstop>
<tabstop>useDiscreteGpuCheck</tabstop>
<tabstop>useZink</tabstop>
<tabstop>scrollArea_3</tabstop>
<tabstop>instanceAccountGroupBox</tabstop>
<tabstop>instanceAccountSelector</tabstop>
<tabstop>serverJoinGroupBox</tabstop>
@ -743,6 +842,17 @@ It is most likely you will need to change the path - please refer to the mod's w
<tabstop>serverJoinAddress</tabstop>
<tabstop>worldJoinButton</tabstop>
<tabstop>worldsCb</tabstop>
<tabstop>javaScrollArea</tabstop>
<tabstop>scrollArea_2</tabstop>
<tabstop>onlineFixes</tabstop>
<tabstop>useNativeGLFWCheck</tabstop>
<tabstop>lineEditGLFWPath</tabstop>
<tabstop>useNativeOpenALCheck</tabstop>
<tabstop>lineEditOpenALPath</tabstop>
<tabstop>enableFeralGamemodeCheck</tabstop>
<tabstop>enableMangoHud</tabstop>
<tabstop>useDiscreteGpuCheck</tabstop>
<tabstop>useZink</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@ -40,6 +40,7 @@
#include <algorithm>
#include <list>
#include "BaseVersionList.h"
#include "Json.h"
#include "Version.h"
#include "meta/Index.h"
#include "modplatform/ModIndex.h"
@ -218,7 +219,14 @@ void ModFilterWidget::prepareBasicFilter()
if (m_instance) {
m_filter->hideInstalled = false;
m_filter->side = ""; // or "both"
auto loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
ModPlatform::ModLoaderTypes loaders;
if (m_instance->settings()->get("OverrideModDownloadLoaders").toBool()) {
for (auto loader : Json::toStringList(m_instance->settings()->get("ModDownloadLoaders").toString())) {
loaders |= ModPlatform::getModLoaderFromString(loader);
}
} else {
loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
}
ui->neoForge->setChecked(loaders & ModPlatform::NeoForge);
ui->forge->setChecked(loaders & ModPlatform::Forge);
ui->fabric->setChecked(loaders & ModPlatform::Fabric);

View File

@ -1,197 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2024 Tayou <git@tayou.org>
*
* 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 "DesktopServices.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();
ThemeCustomizationWidget::refresh();
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);
connect(ui->iconsFolder, &QPushButton::clicked, this,
[] { DesktopServices::openPath(APPLICATION->themeManager()->getIconThemesFolder().path()); });
connect(ui->widgetStyleFolder, &QPushButton::clicked, this,
[] { DesktopServices::openPath(APPLICATION->themeManager()->getApplicationThemesFolder().path()); });
connect(ui->catPackFolder, &QPushButton::clicked, this,
[] { DesktopServices::openPath(APPLICATION->themeManager()->getCatPacksFolder().path()); });
connect(ui->refreshButton, &QPushButton::clicked, this, &ThemeCustomizationWidget::refresh);
}
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->widgetStyleLabel->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 = ui->iconsComboBox->itemData(index).toString();
if (originalIconTheme != newIconTheme) {
settings->set("IconTheme", newIconTheme);
APPLICATION->themeManager()->applyCurrentlySelectedTheme();
}
emit currentIconThemeChanged(index);
}
void ThemeCustomizationWidget::applyWidgetTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalAppTheme = settings->get("ApplicationTheme").toString();
auto newAppTheme = ui->widgetStyleComboBox->itemData(index).toString();
if (originalAppTheme != newAppTheme) {
settings->set("ApplicationTheme", newAppTheme);
APPLICATION->themeManager()->applyCurrentlySelectedTheme();
}
emit currentWidgetThemeChanged(index);
}
void ThemeCustomizationWidget::applyCatTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalCat = settings->get("BackgroundCat").toString();
auto newCat = ui->backgroundCatComboBox->itemData(index).toString();
if (originalCat != newCat) {
settings->set("BackgroundCat", newCat);
}
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 currentIconTheme = settings->get("IconTheme").toString();
auto iconThemes = APPLICATION->themeManager()->getValidIconThemes();
int idx = 0;
for (auto iconTheme : iconThemes) {
QIcon iconForComboBox = QIcon(iconTheme->path() + "/scalable/settings");
ui->iconsComboBox->addItem(iconForComboBox, iconTheme->name(), iconTheme->id());
if (currentIconTheme == iconTheme->id()) {
ui->iconsComboBox->setCurrentIndex(idx);
}
idx++;
}
}
{
auto currentTheme = settings->get("ApplicationTheme").toString();
auto themes = APPLICATION->themeManager()->getValidApplicationThemes();
int idx = 0;
for (auto& theme : themes) {
ui->widgetStyleComboBox->addItem(theme->name(), theme->id());
if (theme->tooltip() != "") {
int index = ui->widgetStyleComboBox->count() - 1;
ui->widgetStyleComboBox->setItemData(index, theme->tooltip(), Qt::ToolTipRole);
}
if (currentTheme == theme->id()) {
ui->widgetStyleComboBox->setCurrentIndex(idx);
}
idx++;
}
}
auto cat = settings->get("BackgroundCat").toString();
for (auto& catFromList : APPLICATION->themeManager()->getValidCatPacks()) {
QIcon catIcon = QIcon(QString("%1").arg(catFromList->path()));
ui->backgroundCatComboBox->addItem(catIcon, catFromList->name(), catFromList->id());
if (cat == catFromList->id()) {
ui->backgroundCatComboBox->setCurrentIndex(ui->backgroundCatComboBox->count() - 1);
}
}
}
void ThemeCustomizationWidget::retranslate()
{
ui->retranslateUi(this);
}
void ThemeCustomizationWidget::refresh()
{
applySettings();
disconnect(ui->iconsComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyIconTheme);
disconnect(ui->widgetStyleComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ThemeCustomizationWidget::applyWidgetTheme);
disconnect(ui->backgroundCatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ThemeCustomizationWidget::applyCatTheme);
APPLICATION->themeManager()->refresh();
ui->iconsComboBox->clear();
ui->widgetStyleComboBox->clear();
ui->backgroundCatComboBox->clear();
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);
};

View File

@ -1,212 +0,0 @@
<?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="QVBoxLayout" name="verticalLayout">
<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>
<layout class="QFormLayout" name="formLayout">
<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">
<layout class="QHBoxLayout" name="iconsLayout">
<item>
<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>
<widget class="QPushButton" name="iconsFolder">
<property name="toolTip">
<string>View icon themes folder.</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="viewfolder"/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="widgetStyleLabel">
<property name="text">
<string>&amp;Widgets</string>
</property>
<property name="buddy">
<cstring>widgetStyleComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="widgetStyleLayout">
<item>
<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>
<widget class="QPushButton" name="widgetStyleFolder">
<property name="toolTip">
<string>View widget themes folder.</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="viewfolder"/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</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="catLayout">
<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="catPackFolder">
<property name="toolTip">
<string>View cat packs folder.</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="viewfolder"/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="refreshLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="refreshButton">
<property name="text">
<string>Refresh all</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>