From bc05ad30aa7c3da5d76947e82012f50466bb5d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 20 Jul 2014 23:47:46 +0200 Subject: [PATCH] Rework the settings dialog. Rework all of it. Thoroughly. Also introduces the ColumnResizer from: https://github.com/agateau/columnresizer/ --- CMakeLists.txt | 29 +- gui/ColumnResizer.cpp | 202 ++++ gui/ColumnResizer.h | 38 + gui/MainWindow.cpp | 12 +- gui/dialogs/AboutDialog.ui | 39 +- gui/pages/global/AccountListPage.cpp | 3 +- gui/pages/global/AccountListPage.h | 2 +- gui/pages/global/AccountListPage.ui | 144 +-- gui/pages/global/BaseSettingsPage.cpp | 28 - gui/pages/global/BaseSettingsPage.h | 35 - gui/pages/global/ExternalToolsPage.cpp | 77 +- gui/pages/global/ExternalToolsPage.h | 12 +- gui/pages/global/ExternalToolsPage.ui | 296 +++--- gui/pages/global/JavaPage.cpp | 146 +++ gui/pages/global/JavaPage.h | 72 ++ gui/pages/global/JavaPage.ui | 303 ++++++ gui/pages/global/MinecraftPage.cpp | 104 ++ gui/pages/global/MinecraftPage.h | 69 ++ gui/pages/global/MinecraftPage.ui | 184 ++++ .../{SettingsPage.cpp => MultiMCPage.cpp} | 259 +---- .../global/{SettingsPage.h => MultiMCPage.h} | 43 +- gui/pages/global/MultiMCPage.ui | 399 +++++++ gui/pages/global/ProxyPage.cpp | 95 ++ gui/pages/global/ProxyPage.h | 66 ++ gui/pages/global/ProxyPage.ui | 197 ++++ gui/pages/global/SettingsPage.ui | 985 ------------------ gui/widgets/PageContainer.cpp | 3 + resources/multimc/16x16/minecraft.png | Bin 0 -> 782 bytes resources/multimc/24x24/minecraft.png | Bin 0 -> 1500 bytes resources/multimc/256x256/minecraft.png | Bin 0 -> 49869 bytes resources/multimc/32x32/minecraft.png | Bin 0 -> 2495 bytes resources/multimc/48x48/minecraft.png | Bin 0 -> 5077 bytes resources/multimc/index.theme | 3 + resources/multimc/multimc.qrc | 13 + resources/multimc/scalable/java.svg | 773 ++++++++++++++ resources/multimc/scalable/proxy.svg | 260 +++++ 36 files changed, 3357 insertions(+), 1534 deletions(-) create mode 100644 gui/ColumnResizer.cpp create mode 100644 gui/ColumnResizer.h delete mode 100644 gui/pages/global/BaseSettingsPage.cpp delete mode 100644 gui/pages/global/BaseSettingsPage.h create mode 100644 gui/pages/global/JavaPage.cpp create mode 100644 gui/pages/global/JavaPage.h create mode 100644 gui/pages/global/JavaPage.ui create mode 100644 gui/pages/global/MinecraftPage.cpp create mode 100644 gui/pages/global/MinecraftPage.h create mode 100644 gui/pages/global/MinecraftPage.ui rename gui/pages/global/{SettingsPage.cpp => MultiMCPage.cpp} (54%) rename gui/pages/global/{SettingsPage.h => MultiMCPage.h} (65%) create mode 100644 gui/pages/global/MultiMCPage.ui create mode 100644 gui/pages/global/ProxyPage.cpp create mode 100644 gui/pages/global/ProxyPage.h create mode 100644 gui/pages/global/ProxyPage.ui delete mode 100644 gui/pages/global/SettingsPage.ui create mode 100644 resources/multimc/16x16/minecraft.png create mode 100644 resources/multimc/24x24/minecraft.png create mode 100644 resources/multimc/256x256/minecraft.png create mode 100644 resources/multimc/32x32/minecraft.png create mode 100644 resources/multimc/48x48/minecraft.png create mode 100644 resources/multimc/scalable/java.svg create mode 100644 resources/multimc/scalable/proxy.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cae21dd4..7efd42e64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,8 @@ SET(MULTIMC_SOURCES # GUI - general utilities gui/GuiUtil.h gui/GuiUtil.cpp + gui/ColumnResizer.h + gui/ColumnResizer.cpp # GUI - windows gui/MainWindow.h @@ -312,14 +314,20 @@ SET(MULTIMC_SOURCES gui/pages/ScreenshotsPage.h gui/pages/OtherLogsPage.cpp gui/pages/OtherLogsPage.h - gui/pages/global/SettingsPage.cpp - gui/pages/global/SettingsPage.h - gui/pages/global/ExternalToolsPage.cpp - gui/pages/global/ExternalToolsPage.h - gui/pages/global/BaseSettingsPage.cpp - gui/pages/global/BaseSettingsPage.h + + # GUI - global settings pages gui/pages/global/AccountListPage.cpp gui/pages/global/AccountListPage.h + gui/pages/global/ExternalToolsPage.cpp + gui/pages/global/ExternalToolsPage.h + gui/pages/global/JavaPage.cpp + gui/pages/global/JavaPage.h + gui/pages/global/MinecraftPage.cpp + gui/pages/global/MinecraftPage.h + gui/pages/global/MultiMCPage.cpp + gui/pages/global/MultiMCPage.h + gui/pages/global/ProxyPage.cpp + gui/pages/global/ProxyPage.h # GUI - dialogs gui/dialogs/AboutDialog.cpp @@ -648,9 +656,14 @@ SET(MULTIMC_UIS gui/pages/NotesPage.ui gui/pages/ScreenshotsPage.ui gui/pages/OtherLogsPage.ui - gui/pages/global/SettingsPage.ui - gui/pages/global/ExternalToolsPage.ui + + # Global settings pages gui/pages/global/AccountListPage.ui + gui/pages/global/ExternalToolsPage.ui + gui/pages/global/JavaPage.ui + gui/pages/global/MinecraftPage.ui + gui/pages/global/MultiMCPage.ui + gui/pages/global/ProxyPage.ui # Dialogs gui/dialogs/CopyInstanceDialog.ui diff --git a/gui/ColumnResizer.cpp b/gui/ColumnResizer.cpp new file mode 100644 index 000000000..1c5597aaa --- /dev/null +++ b/gui/ColumnResizer.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2011 Aurélien Gâteau + * License: LGPL v2.1 or later (see COPYING) + */ +#include "ColumnResizer.h" + +#include +#include +#include +#include +#include +#include + +class FormLayoutWidgetItem : public QWidgetItem +{ +public: + FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole) + : QWidgetItem(widget) + , m_width(-1) + , m_formLayout(formLayout) + , m_itemRole(itemRole) + {} + + QSize sizeHint() const + { + QSize size = QWidgetItem::sizeHint(); + if (m_width != -1) { + size.setWidth(m_width); + } + return size; + } + + QSize minimumSize() const + { + QSize size = QWidgetItem::minimumSize(); + if (m_width != -1) { + size.setWidth(m_width); + } + return size; + } + + QSize maximumSize() const + { + QSize size = QWidgetItem::maximumSize(); + if (m_width != -1) { + size.setWidth(m_width); + } + return size; + } + + void setWidth(int width) + { + if (width != m_width) { + m_width = width; + invalidate(); + } + } + + void setGeometry(const QRect& _rect) + { + QRect rect = _rect; + int width = widget()->sizeHint().width(); + if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) { + rect.setLeft(rect.right() - width); + } + QWidgetItem::setGeometry(rect); + } + + QFormLayout* formLayout() const + { + return m_formLayout; + } + +private: + int m_width; + QFormLayout* m_formLayout; + QFormLayout::ItemRole m_itemRole; +}; + +typedef QPair GridColumnInfo; + +class ColumnResizerPrivate +{ +public: + ColumnResizerPrivate(ColumnResizer* q_ptr) + : q(q_ptr) + , m_updateTimer(new QTimer(q)) + { + m_updateTimer->setSingleShot(true); + m_updateTimer->setInterval(0); + QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth())); + } + + void scheduleWidthUpdate() + { + m_updateTimer->start(); + } + + ColumnResizer* q; + QTimer* m_updateTimer; + QList m_widgets; + QList m_wrWidgetItemList; + QList m_gridColumnInfoList; +}; + +ColumnResizer::ColumnResizer(QObject* parent) +: QObject(parent) +, d(new ColumnResizerPrivate(this)) +{} + +ColumnResizer::~ColumnResizer() +{ + delete d; +} + +void ColumnResizer::addWidget(QWidget* widget) +{ + d->m_widgets.append(widget); + widget->installEventFilter(this); + d->scheduleWidthUpdate(); +} + +void ColumnResizer::updateWidth() +{ + int width = 0; + Q_FOREACH(QWidget* widget, d->m_widgets) { + width = qMax(widget->sizeHint().width(), width); + } + Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) { + item->setWidth(width); + item->formLayout()->update(); + } + Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) { + info.first->setColumnMinimumWidth(info.second, width); + } +} + +bool ColumnResizer::eventFilter(QObject*, QEvent* event) +{ + if (event->type() == QEvent::Resize) { + d->scheduleWidthUpdate(); + } + return false; +} + +void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column) +{ + Q_ASSERT(column >= 0); + QGridLayout* gridLayout = qobject_cast(layout); + QFormLayout* formLayout = qobject_cast(layout); + if (gridLayout) { + addWidgetsFromGridLayout(gridLayout, column); + } else if (formLayout) { + if (column > QFormLayout::SpanningRole) { + qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout"; + return; + } + QFormLayout::ItemRole role = static_cast(column); + addWidgetsFromFormLayout(formLayout, role); + } else { + qCritical() << "Don't know how to handle layout" << layout; + } +} + +void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column) +{ + for (int row = 0; row < layout->rowCount(); ++row) { + QLayoutItem* item = layout->itemAtPosition(row, column); + if (!item) { + continue; + } + QWidget* widget = item->widget(); + if (!widget) { + continue; + } + addWidget(widget); + } + d->m_gridColumnInfoList << GridColumnInfo(layout, column); +} + +void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role) +{ + for (int row = 0; row < layout->rowCount(); ++row) { + QLayoutItem* item = layout->itemAt(row, role); + if (!item) { + continue; + } + QWidget* widget = item->widget(); + if (!widget) { + continue; + } + layout->removeItem(item); + delete item; + FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role); + layout->setItem(row, role, newItem); + addWidget(widget); + d->m_wrWidgetItemList << newItem; + } +} + +#include +// vi: ts=4 sw=4 et diff --git a/gui/ColumnResizer.h b/gui/ColumnResizer.h new file mode 100644 index 000000000..4bbac3834 --- /dev/null +++ b/gui/ColumnResizer.h @@ -0,0 +1,38 @@ +/* + * Copyright 2011 Aurélien Gâteau + * License: LGPL v2.1 or later (see COPYING) + */ +#pragma once + +#include + +#include +#include + +class QEvent; +class QGridLayout; +class QLayout; +class QWidget; + +class ColumnResizerPrivate; +class ColumnResizer : public QObject +{ + Q_OBJECT +public: + ColumnResizer(QObject* parent = 0); + ~ColumnResizer(); + + void addWidget(QWidget* widget); + void addWidgetsFromLayout(QLayout*, int column); + void addWidgetsFromGridLayout(QGridLayout*, int column); + void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role); + +private Q_SLOTS: + void updateWidth(); + +protected: + bool eventFilter(QObject*, QEvent* event); + +private: + ColumnResizerPrivate* const d; +}; diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 81ee466bd..ce03d7b93 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -62,9 +62,12 @@ #include "gui/dialogs/EditAccountDialog.h" #include "gui/dialogs/NotificationDialog.h" -#include "gui/pages/global/SettingsPage.h" +#include "gui/pages/global/MultiMCPage.h" #include "gui/pages/global/ExternalToolsPage.h" #include "gui/pages/global/AccountListPage.h" +#include "pages/global/ProxyPage.h" +#include "pages/global/JavaPage.h" +#include "pages/global/MinecraftPage.h" #include "gui/ConsoleWindow.h" #include "pagedialog/PageDialog.h" @@ -250,9 +253,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // set up global pages dialog { m_globalSettingsProvider = std::make_shared(tr("Settings")); - m_globalSettingsProvider->addPage(); - m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); } // Update the menu when the active account changes. diff --git a/gui/dialogs/AboutDialog.ui b/gui/dialogs/AboutDialog.ui index 04983299e..93fa8963f 100644 --- a/gui/dialogs/AboutDialog.ui +++ b/gui/dialogs/AboutDialog.ui @@ -96,7 +96,7 @@ - 1 + 0 @@ -104,7 +104,7 @@ 0 0 689 - 331 + 311 @@ -229,7 +229,7 @@ 0 0 689 - 331 + 311 @@ -245,8 +245,8 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> +</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse @@ -271,7 +271,7 @@ p, li { white-space: pre-wrap; } 0 0 689 - 331 + 311 @@ -298,7 +298,7 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:9pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">MultiMC</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright 2012-2014 MultiMC Contributors</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></p> @@ -422,7 +422,7 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">Java IconLoader class</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Copyright (c) 2011, Chris Molini</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">All rights reserved.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> @@ -447,8 +447,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">ColumnResizer</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">/*</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Copyright 2011 Aurélien Gâteau &lt;agateau@kde.org&gt;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * License: LGPL v2.1 or later (see COPYING)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p></body></html> @@ -459,8 +464,8 @@ p, li { white-space: pre-wrap; } 0 0 - 689 - 331 + 98 + 88 @@ -473,12 +478,12 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork </span><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:600;">without</span><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;"> implying that you have our blessing.</span></p></body></html> +</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork <span style=" font-weight:600;">without</span> implying that you have our blessing.</p></body></html> Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse diff --git a/gui/pages/global/AccountListPage.cpp b/gui/pages/global/AccountListPage.cpp index cad7d5bc3..00487d570 100644 --- a/gui/pages/global/AccountListPage.cpp +++ b/gui/pages/global/AccountListPage.cpp @@ -34,9 +34,10 @@ #include AccountListPage::AccountListPage(QWidget *parent) - : QDialog(parent), ui(new Ui::AccountListPage) + : QWidget(parent), ui(new Ui::AccountListPage) { ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); m_accounts = MMC->accounts(); diff --git a/gui/pages/global/AccountListPage.h b/gui/pages/global/AccountListPage.h index fd4724d12..fd2c96e3b 100644 --- a/gui/pages/global/AccountListPage.h +++ b/gui/pages/global/AccountListPage.h @@ -29,7 +29,7 @@ class AccountListPage; class AuthenticateTask; -class AccountListPage : public QDialog, public BasePage +class AccountListPage : public QWidget, public BasePage { Q_OBJECT public: diff --git a/gui/pages/global/AccountListPage.ui b/gui/pages/global/AccountListPage.ui index 1e5b07ebc..8ad78cf46 100644 --- a/gui/pages/global/AccountListPage.ui +++ b/gui/pages/global/AccountListPage.ui @@ -6,81 +6,107 @@ 0 0 - 400 - 300 + 694 + 609 Manage Accounts + + 0 + + + 0 + + + 0 + + + 0 + - - - <html><head/><body><p>Welcome! If you're new here, you can click the &quot;Add&quot; button to add your Mojang or Minecraft account.</p></body></html> + + + 0 - - true - - - - - - - - - - + + + Tab 1 + + - + - &Add + <html><head/><body><p>Welcome! If you're new here, you can click the &quot;Add&quot; button to add your Mojang or Minecraft account.</p></body></html> + + + true - - - &Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - <html><head/><body><p>Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).</p></body></html> - - - &Set Default - - - - - - - Set no default account. This will cause MultiMC to prompt you to select an account every time you launch an instance that doesn't have its own default set. - - - &No Default - - + + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).</p></body></html> + + + &Set Default + + + + + + + Set no default account. This will cause MultiMC to prompt you to select an account every time you launch an instance that doesn't have its own default set. + + + &No Default + + + + + + - - + + diff --git a/gui/pages/global/BaseSettingsPage.cpp b/gui/pages/global/BaseSettingsPage.cpp deleted file mode 100644 index 167b23c0c..000000000 --- a/gui/pages/global/BaseSettingsPage.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright 2014 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 "BaseSettingsPage.h" - -#include "MultiMC.h" - -void BaseSettingsPage::opened() -{ - loadSettings(MMC->settings().get()); -} -bool BaseSettingsPage::apply() -{ - applySettings(MMC->settings().get()); - return true; -} diff --git a/gui/pages/global/BaseSettingsPage.h b/gui/pages/global/BaseSettingsPage.h deleted file mode 100644 index 55e5f2a4e..000000000 --- a/gui/pages/global/BaseSettingsPage.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 2014 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 "gui/pages/BasePage.h" - -class SettingsObject; - -class BaseSettingsPage : public BasePage -{ -public: - virtual ~BaseSettingsPage() - { - } - - void opened() override; - bool apply() override; - -protected: - virtual void loadSettings(SettingsObject *object) = 0; - virtual void applySettings(SettingsObject *object) = 0; -}; diff --git a/gui/pages/global/ExternalToolsPage.cpp b/gui/pages/global/ExternalToolsPage.cpp index e0312ee55..417a13e3c 100644 --- a/gui/pages/global/ExternalToolsPage.cpp +++ b/gui/pages/global/ExternalToolsPage.cpp @@ -18,6 +18,7 @@ #include #include +#include #include @@ -30,10 +31,16 @@ ExternalToolsPage::ExternalToolsPage(QWidget *parent) : ui(new Ui::ExternalToolsPage) { ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + + #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) + ui->jsonEditorTextBox->setClearButtonEnabled(true); + #endif ui->mceditLink->setOpenExternalLinks(true); ui->jvisualvmLink->setOpenExternalLinks(true); ui->jprofilerLink->setOpenExternalLinks(true); + loadSettings(); } ExternalToolsPage::~ExternalToolsPage() @@ -41,17 +48,35 @@ ExternalToolsPage::~ExternalToolsPage() delete ui; } -void ExternalToolsPage::loadSettings(SettingsObject *object) +void ExternalToolsPage::loadSettings() { - ui->jprofilerPathEdit->setText(object->get("JProfilerPath").toString()); - ui->jvisualvmPathEdit->setText(object->get("JVisualVMPath").toString()); - ui->mceditPathEdit->setText(object->get("MCEditPath").toString()); + auto s = MMC->settings(); + ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString()); + ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString()); + ui->mceditPathEdit->setText(s->get("MCEditPath").toString()); + + // Editors + ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString()); } -void ExternalToolsPage::applySettings(SettingsObject *object) +void ExternalToolsPage::applySettings() { - object->set("JProfilerPath", ui->jprofilerPathEdit->text()); - object->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); - object->set("MCEditPath", ui->mceditPathEdit->text()); + auto s = MMC->settings(); + s->set("JProfilerPath", ui->jprofilerPathEdit->text()); + s->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); + s->set("MCEditPath", ui->mceditPathEdit->text()); + + // Editors + QString jsonEditor = ui->jsonEditorTextBox->text(); + if (!jsonEditor.isEmpty() && + (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable())) + { + QString found = QStandardPaths::findExecutable(jsonEditor); + if (!found.isEmpty()) + { + jsonEditor = found; + } + } + s->set("JsonEditor", jsonEditor); } void ExternalToolsPage::on_jprofilerPathBtn_clicked() @@ -175,3 +200,39 @@ void ExternalToolsPage::on_mceditCheckBtn_clicked() QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK")); } } + +void ExternalToolsPage::on_jsonEditorBrowseBtn_clicked() +{ + QString raw_file = QFileDialog::getOpenFileName( + this, tr("JSON Editor"), + ui->jsonEditorTextBox->text().isEmpty() +#if defined(Q_OS_LINUX) + ? QString("/usr/bin") +#else + ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first() +#endif + : ui->jsonEditorTextBox->text()); + QString cooked_file = NormalizePath(raw_file); + + if (cooked_file.isEmpty()) + { + return; + } + + // it has to exist and be an executable + if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable()) + { + ui->jsonEditorTextBox->setText(cooked_file); + } + else + { + QMessageBox::warning(this, tr("Invalid"), + tr("The file chosen does not seem to be an executable")); + } +} + +bool ExternalToolsPage::apply() +{ + applySettings(); + return true; +} diff --git a/gui/pages/global/ExternalToolsPage.h b/gui/pages/global/ExternalToolsPage.h index 1b35a92be..027e164eb 100644 --- a/gui/pages/global/ExternalToolsPage.h +++ b/gui/pages/global/ExternalToolsPage.h @@ -17,13 +17,13 @@ #include -#include "BaseSettingsPage.h" +#include "gui/pages/BasePage.h" namespace Ui { class ExternalToolsPage; } -class ExternalToolsPage : public QWidget, public BaseSettingsPage +class ExternalToolsPage : public QWidget, public BasePage { Q_OBJECT @@ -47,10 +47,11 @@ public: { return "External-tools"; } + virtual bool apply(); -protected: - void loadSettings(SettingsObject *object) override; - void applySettings(SettingsObject *object) override; +private: + void loadSettings(); + void applySettings(); private: Ui::ExternalToolsPage *ui; @@ -63,4 +64,5 @@ slots: void on_jvisualvmCheckBtn_clicked(); void on_mceditPathBtn_clicked(); void on_mceditCheckBtn_clicked(); + void on_jsonEditorBrowseBtn_clicked(); }; diff --git a/gui/pages/global/ExternalToolsPage.ui b/gui/pages/global/ExternalToolsPage.ui index 96650f0f9..ba1b6f01a 100644 --- a/gui/pages/global/ExternalToolsPage.ui +++ b/gui/pages/global/ExternalToolsPage.ui @@ -6,138 +6,190 @@ 0 0 - 494 - 562 + 673 + 751 Form + + 0 + + + 0 + + + 0 + + + 0 + - - - JProfiler + + + 0 - - - - - - - - - - ... - - - - - - - - - Check - - - - - - - <html><head/><body><p><a href="http://www.ej-technologies.com/products/jprofiler/overview.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.ej-technologies.com/products/jprofiler/overview.html</span></a></p></body></html> - - - - + + + Tab 1 + + + + + + JProfiler + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + <html><head/><body><p><a href="http://www.ej-technologies.com/products/jprofiler/overview.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.ej-technologies.com/products/jprofiler/overview.html</span></a></p></body></html> + + + + + + + + + + JVisualVM + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + <html><head/><body><p><a href="http://visualvm.java.net/"><span style=" text-decoration: underline; color:#0000ff;">http://visualvm.java.net/</span></a></p></body></html> + + + + + + + + + + MCEdit + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + <html><head/><body><p><a href="http://www.mcedit.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.mcedit.net/</span></a></p></body></html> + + + + + + + + + + External Editors (leave empty for system default) + + + + + + + + + Text Editor: + + + + + + + ... + + + + + + + + + + Qt::Vertical + + + + 20 + 216 + + + + + + - - - - JVisualVM - - - - - - - - - - - ... - - - - - - - - - Check - - - - - - - <html><head/><body><p><a href="http://visualvm.java.net/"><span style=" text-decoration: underline; color:#0000ff;">http://visualvm.java.net/</span></a></p></body></html> - - - - - - - - - - MCEdit - - - - - - - - - - - ... - - - - - - - - - Check - - - - - - - <html><head/><body><p><a href="http://www.mcedit.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.mcedit.net/</span></a></p></body></html> - - - - - - - - - - Qt::Vertical - - - - 20 - 160 - - - - diff --git a/gui/pages/global/JavaPage.cpp b/gui/pages/global/JavaPage.cpp new file mode 100644 index 000000000..86451411f --- /dev/null +++ b/gui/pages/global/JavaPage.cpp @@ -0,0 +1,146 @@ +/* Copyright 2013 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 "JavaPage.h" +#include "ui_JavaPage.h" + +#include +#include +#include + +#include + +#include "logic/NagUtils.h" + +#include "gui/Platform.h" +#include "gui/dialogs/VersionSelectDialog.h" +#include + +#include "logic/java/JavaUtils.h" +#include "logic/java/JavaVersionList.h" +#include "logic/java/JavaChecker.h" + +#include "logic/settings/SettingsObject.h" +#include "MultiMC.h" + +JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage) +{ + ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + + auto resizer = new ColumnResizer(this); + resizer->addWidgetsFromLayout(ui->javaSettingsGroupBox->layout(), 0); + resizer->addWidgetsFromLayout(ui->customCommandsGroupBox->layout(), 0); + + loadSettings(); +} + +JavaPage::~JavaPage() +{ + delete ui; +} + +bool JavaPage::apply() +{ + applySettings(); + return true; +} + +void JavaPage::applySettings() +{ + auto s = MMC->settings(); + // Memory + s->set("MinMemAlloc", ui->minMemSpinBox->value()); + s->set("MaxMemAlloc", ui->maxMemSpinBox->value()); + s->set("PermGen", ui->permGenSpinBox->value()); + + // Java Settings + s->set("JavaPath", ui->javaPathTextBox->text()); + s->set("JvmArgs", ui->jvmArgsTextBox->text()); + NagUtils::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget()); + + // Custom Commands + s->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text()); + s->set("PostExitCommand", ui->postExitCmdTextBox->text()); +} +void JavaPage::loadSettings() +{ + auto s = MMC->settings(); + // Memory + ui->minMemSpinBox->setValue(s->get("MinMemAlloc").toInt()); + ui->maxMemSpinBox->setValue(s->get("MaxMemAlloc").toInt()); + ui->permGenSpinBox->setValue(s->get("PermGen").toInt()); + + // Java Settings + ui->javaPathTextBox->setText(s->get("JavaPath").toString()); + ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString()); + + // Custom Commands + ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString()); + ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString()); +} + +void JavaPage::on_javaDetectBtn_clicked() +{ + JavaVersionPtr java; + + VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true); + vselect.setResizeOn(2); + vselect.exec(); + + if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) + { + java = std::dynamic_pointer_cast(vselect.selectedVersion()); + ui->javaPathTextBox->setText(java->path); + } +} +void JavaPage::on_javaBrowseBtn_clicked() +{ + QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable")); + if (!dir.isNull()) + { + ui->javaPathTextBox->setText(dir); + } +} +void JavaPage::on_javaTestBtn_clicked() +{ + checker.reset(new JavaChecker()); + connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this, + SLOT(checkFinished(JavaCheckResult))); + checker->path = ui->javaPathTextBox->text(); + checker->performCheck(); +} + +void JavaPage::checkFinished(JavaCheckResult result) +{ + if (result.valid) + { + QString text; + text += "Java test succeeded!\n"; + if (result.is_64bit) + text += "Using 64bit java.\n"; + text += "\n"; + text += "Platform reported: " + result.realPlatform + "\n"; + text += "Java version reported: " + result.javaVersion; + QMessageBox::information(this, tr("Java test success"), text); + } + else + { + QMessageBox::warning( + this, tr("Java test failure"), + tr("The specified java binary didn't work. You should use the auto-detect feature, " + "or set the path to the java executable.")); + } +} diff --git a/gui/pages/global/JavaPage.h b/gui/pages/global/JavaPage.h new file mode 100644 index 000000000..d0228bd2e --- /dev/null +++ b/gui/pages/global/JavaPage.h @@ -0,0 +1,72 @@ +/* Copyright 2013 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 +#include + +#include "logic/java/JavaChecker.h" +#include "gui/pages/BasePage.h" + +class SettingsObject; + +namespace Ui +{ +class JavaPage; +} + +class JavaPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit JavaPage(QWidget *parent = 0); + ~JavaPage(); + + QString displayName() const override + { + return tr("Java"); + } + QIcon icon() const override + { + return QIcon::fromTheme("java"); + } + QString id() const override + { + return "java-settings"; + } + QString helpPage() const override + { + return "Java-settings"; + } + bool apply() override; + +private: + void applySettings(); + void loadSettings(); + +private +slots: + void on_javaDetectBtn_clicked(); + void on_javaTestBtn_clicked(); + void on_javaBrowseBtn_clicked(); + + void checkFinished(JavaCheckResult result); + +private: + Ui::JavaPage *ui; + std::shared_ptr checker; +}; diff --git a/gui/pages/global/JavaPage.ui b/gui/pages/global/JavaPage.ui new file mode 100644 index 000000000..6ae41a495 --- /dev/null +++ b/gui/pages/global/JavaPage.ui @@ -0,0 +1,303 @@ + + + JavaPage + + + + 0 + 0 + 545 + 609 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + Tab 1 + + + + + + Memory + + + + + + The maximum amount of memory Minecraft is allowed to use. + + + MB + + + 512 + + + 65536 + + + 128 + + + 1024 + + + + + + + Minimum memory allocation: + + + + + + + Maximum memory allocation: + + + + + + + The amount of memory Minecraft is started with. + + + MB + + + 256 + + + 65536 + + + 128 + + + 256 + + + + + + + PermGen: + + + + + + + The amount of memory available to store loaded Java classes. + + + MB + + + 64 + + + 999999999 + + + 8 + + + 64 + + + + + + + + + + Java Runtime + + + + + + + 0 + 0 + + + + Java path: + + + + + + + + 0 + 0 + + + + Auto-detect... + + + + + + + + 0 + 0 + + + + Test + + + + + + + + 0 + 0 + + + + JVM arguments: + + + + + + + + + + + + + 0 + 0 + + + + + 28 + 16777215 + + + + ... + + + + + + + + + + + + + + + Custom Commands + + + + + + Post-exit command: + + + + + + + Pre-launch command: + + + + + + + + + + + + + + + + + 0 + 0 + + + + Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + minMemSpinBox + maxMemSpinBox + permGenSpinBox + javaPathTextBox + javaBrowseBtn + javaDetectBtn + javaTestBtn + jvmArgsTextBox + preLaunchCmdTextBox + postExitCmdTextBox + + + + diff --git a/gui/pages/global/MinecraftPage.cpp b/gui/pages/global/MinecraftPage.cpp new file mode 100644 index 000000000..0fe56fde6 --- /dev/null +++ b/gui/pages/global/MinecraftPage.cpp @@ -0,0 +1,104 @@ +/* Copyright 2013 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 "MinecraftPage.h" +#include "ui_MinecraftPage.h" + +#include +#include +#include + +#include + +#include "gui/Platform.h" +#include "gui/dialogs/VersionSelectDialog.h" +#include "gui/dialogs/CustomMessageBox.h" + +#include "logic/NagUtils.h" + +#include "logic/java/JavaUtils.h" +#include "logic/java/JavaVersionList.h" +#include "logic/java/JavaChecker.h" + +#include "logic/updater/UpdateChecker.h" + +#include "logic/tools/BaseProfiler.h" + +#include "logic/settings/SettingsObject.h" +#include "MultiMC.h" + +MinecraftPage::MinecraftPage(QWidget *parent) : QWidget(parent), ui(new Ui::MinecraftPage) +{ + ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + loadSettings(); + updateCheckboxStuff(); +} + +MinecraftPage::~MinecraftPage() +{ + delete ui; +} + +bool MinecraftPage::apply() +{ + applySettings(); + return true; +} + +void MinecraftPage::updateCheckboxStuff() +{ + ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); + ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); +} + +void MinecraftPage::on_maximizedCheckBox_clicked(bool checked) +{ + Q_UNUSED(checked); + updateCheckboxStuff(); +} + + +void MinecraftPage::applySettings() +{ + auto s = MMC->settings(); + // Minecraft version updates + s->set("AutoUpdateMinecraftVersions", ui->autoupdateMinecraft->isChecked()); + + // Console + s->set("ShowConsole", ui->showConsoleCheck->isChecked()); + s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked()); + + // Window Size + s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked()); + s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value()); + s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value()); +} + +void MinecraftPage::loadSettings() +{ + auto s = MMC->settings(); + // Minecraft version updates + ui->autoupdateMinecraft->setChecked(s->get("AutoUpdateMinecraftVersions").toBool()); + + // Console + ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool()); + ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool()); + + // Window Size + ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool()); + ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt()); + ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt()); +} diff --git a/gui/pages/global/MinecraftPage.h b/gui/pages/global/MinecraftPage.h new file mode 100644 index 000000000..902990204 --- /dev/null +++ b/gui/pages/global/MinecraftPage.h @@ -0,0 +1,69 @@ +/* Copyright 2013 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 +#include + +#include "logic/java/JavaChecker.h" +#include "gui/pages/BasePage.h" + +class SettingsObject; + +namespace Ui +{ +class MinecraftPage; +} + +class MinecraftPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit MinecraftPage(QWidget *parent = 0); + ~MinecraftPage(); + + QString displayName() const override + { + return tr("Minecraft"); + } + QIcon icon() const override + { + return QIcon::fromTheme("minecraft"); + } + QString id() const override + { + return "minecraft-settings"; + } + QString helpPage() const override + { + return "Minecraft-settings"; + } + bool apply() override; + +private: + void updateCheckboxStuff(); + void applySettings(); + void loadSettings(); + +private +slots: + void on_maximizedCheckBox_clicked(bool checked); + +private: + Ui::MinecraftPage *ui; + +}; diff --git a/gui/pages/global/MinecraftPage.ui b/gui/pages/global/MinecraftPage.ui new file mode 100644 index 000000000..e938d09da --- /dev/null +++ b/gui/pages/global/MinecraftPage.ui @@ -0,0 +1,184 @@ + + + MinecraftPage + + + + 0 + 0 + 545 + 609 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTabWidget::Rounded + + + 0 + + + + Minecraft + + + + + + Minecraft Version Updates + + + + + + Automatically update to latest version revision + + + + + + + + + + Window Size + + + + + + Start Minecraft maximized? + + + + + + + + + Window height: + + + + + + + Window width: + + + + + + + 854 + + + 65536 + + + 1 + + + 854 + + + + + + + 480 + + + 65536 + + + 480 + + + + + + + + + + + + Console Settings + + + + + + Show console while the game is running? + + + + + + + Automatically close console when the game quits? + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + tabWidget + autoupdateMinecraft + maximizedCheckBox + windowWidthSpinBox + windowHeightSpinBox + showConsoleCheck + autoCloseConsoleCheck + + + + diff --git a/gui/pages/global/SettingsPage.cpp b/gui/pages/global/MultiMCPage.cpp similarity index 54% rename from gui/pages/global/SettingsPage.cpp rename to gui/pages/global/MultiMCPage.cpp index 37b0539ce..2d6eb7d54 100644 --- a/gui/pages/global/SettingsPage.cpp +++ b/gui/pages/global/MultiMCPage.cpp @@ -13,8 +13,8 @@ * limitations under the License. */ -#include "SettingsPage.h" -#include "ui_SettingsPage.h" +#include "MultiMCPage.h" +#include "ui_MultiMCPage.h" #include #include @@ -25,6 +25,7 @@ #include "gui/Platform.h" #include "gui/dialogs/VersionSelectDialog.h" #include "gui/dialogs/CustomMessageBox.h" +#include #include "logic/NagUtils.h" @@ -48,22 +49,20 @@ enum InstSortMode Sort_LastLaunch }; -SettingsPage::SettingsPage(QWidget *parent) : QWidget(parent), ui(new Ui::SettingsPage) +MultiMCPage::MultiMCPage(QWidget *parent) : QWidget(parent), ui(new Ui::MultiMCPage) { - MultiMCPlatform::fixWM_CLASS(this); ui->setupUi(this); ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name); ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch); -#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) - ui->jsonEditorTextBox->setClearButtonEnabled(true); -#endif + auto resizer = new ColumnResizer(this); + resizer->addWidgetsFromLayout(ui->groupBox->layout(), 1); + resizer->addWidgetsFromLayout(ui->foldersBox->layout(), 1); - restoreGeometry( - QByteArray::fromBase64(MMC->settings()->get("SettingsGeometry").toByteArray())); + loadSettings(); QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this, - &SettingsPage::refreshUpdateChannelList); + &MultiMCPage::refreshUpdateChannelList); if (MMC->updateChecker()->hasChannels()) { @@ -73,32 +72,20 @@ SettingsPage::SettingsPage(QWidget *parent) : QWidget(parent), ui(new Ui::Settin { MMC->updateChecker()->updateChanList(false); } - connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int))); } -SettingsPage::~SettingsPage() +MultiMCPage::~MultiMCPage() { delete ui; } -void SettingsPage::closeEvent(QCloseEvent *ev) +bool MultiMCPage::apply() { - MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64()); - - QWidget::closeEvent(ev); + applySettings(); + return true; } -void SettingsPage::updateCheckboxStuff() -{ - ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); - ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); - ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() && - !ui->proxyDefaultBtn->isChecked()); - ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() && - !ui->proxyDefaultBtn->isChecked()); -} - -void SettingsPage::on_ftbLauncherBrowseBtn_clicked() +void MultiMCPage::on_ftbLauncherBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("FTB Launcher Directory"), ui->ftbLauncherBox->text()); @@ -110,7 +97,7 @@ void SettingsPage::on_ftbLauncherBrowseBtn_clicked() ui->ftbLauncherBox->setText(cooked_dir); } } -void SettingsPage::on_ftbBrowseBtn_clicked() +void MultiMCPage::on_ftbBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("FTB Directory"), ui->ftbBox->text()); @@ -123,7 +110,7 @@ void SettingsPage::on_ftbBrowseBtn_clicked() } } -void SettingsPage::on_instDirBrowseBtn_clicked() +void MultiMCPage::on_instDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Instance Directory"), ui->instDirTextBox->text()); @@ -135,7 +122,7 @@ void SettingsPage::on_instDirBrowseBtn_clicked() ui->instDirTextBox->setText(cooked_dir); } } -void SettingsPage::on_iconsDirBrowseBtn_clicked() +void MultiMCPage::on_iconsDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Directory"), ui->iconsDirTextBox->text()); @@ -147,7 +134,7 @@ void SettingsPage::on_iconsDirBrowseBtn_clicked() ui->iconsDirTextBox->setText(cooked_dir); } } -void SettingsPage::on_modsDirBrowseBtn_clicked() +void MultiMCPage::on_modsDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Directory"), ui->modsDirTextBox->text()); @@ -159,7 +146,7 @@ void SettingsPage::on_modsDirBrowseBtn_clicked() ui->modsDirTextBox->setText(cooked_dir); } } -void SettingsPage::on_lwjglDirBrowseBtn_clicked() +void MultiMCPage::on_lwjglDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("LWJGL Directory"), ui->lwjglDirTextBox->text()); @@ -172,48 +159,7 @@ void SettingsPage::on_lwjglDirBrowseBtn_clicked() } } -void SettingsPage::on_jsonEditorBrowseBtn_clicked() -{ - QString raw_file = QFileDialog::getOpenFileName( - this, tr("JSON Editor"), - ui->jsonEditorTextBox->text().isEmpty() -#if defined(Q_OS_LINUX) - ? QString("/usr/bin") -#else - ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first() -#endif - : ui->jsonEditorTextBox->text()); - QString cooked_file = NormalizePath(raw_file); - - if (cooked_file.isEmpty()) - { - return; - } - - // it has to exist and be an executable - if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable()) - { - ui->jsonEditorTextBox->setText(cooked_file); - } - else - { - QMessageBox::warning(this, tr("Invalid"), - tr("The file chosen does not seem to be an executable")); - } -} - -void SettingsPage::on_maximizedCheckBox_clicked(bool checked) -{ - Q_UNUSED(checked); - updateCheckboxStuff(); -} - -void SettingsPage::proxyChanged(int) -{ - updateCheckboxStuff(); -} - -void SettingsPage::refreshUpdateChannelList() +void MultiMCPage::refreshUpdateChannelList() { // Stop listening for selection changes. It's going to change a lot while we update it and // we don't need to update the @@ -258,12 +204,12 @@ void SettingsPage::refreshUpdateChannelList() ui->updateChannelComboBox->setEnabled(true); } -void SettingsPage::updateChannelSelectionChanged(int index) +void MultiMCPage::updateChannelSelectionChanged(int index) { refreshUpdateChannelDesc(); } -void SettingsPage::refreshUpdateChannelDesc() +void MultiMCPage::refreshUpdateChannelDesc() { // Get the channel list. QList channelList = MMC->updateChecker()->getChannelList(); @@ -285,8 +231,9 @@ void SettingsPage::refreshUpdateChannelDesc() } } -void SettingsPage::applySettings(SettingsObject *s) +void MultiMCPage::applySettings() { + auto s = MMC->settings(); // Language s->set("Language", ui->languageBox->itemData(ui->languageBox->currentIndex()).toLocale().bcp47Name()); @@ -325,62 +272,6 @@ void SettingsPage::applySettings(SettingsObject *s) s->set("LWJGLDir", ui->lwjglDirTextBox->text()); s->set("IconsDir", ui->iconsDirTextBox->text()); - // Editors - QString jsonEditor = ui->jsonEditorTextBox->text(); - if (!jsonEditor.isEmpty() && - (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable())) - { - QString found = QStandardPaths::findExecutable(jsonEditor); - if (!found.isEmpty()) - { - jsonEditor = found; - } - } - s->set("JsonEditor", jsonEditor); - - // Minecraft version updates - s->set("AutoUpdateMinecraftVersions", ui->autoupdateMinecraft->isChecked()); - - // Console - s->set("ShowConsole", ui->showConsoleCheck->isChecked()); - s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked()); - - // Window Size - s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked()); - s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value()); - s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value()); - - // Proxy - QString proxyType = "None"; - if (ui->proxyDefaultBtn->isChecked()) - proxyType = "Default"; - else if (ui->proxyNoneBtn->isChecked()) - proxyType = "None"; - else if (ui->proxySOCKS5Btn->isChecked()) - proxyType = "SOCKS5"; - else if (ui->proxyHTTPBtn->isChecked()) - proxyType = "HTTP"; - - s->set("ProxyType", proxyType); - s->set("ProxyAddr", ui->proxyAddrEdit->text()); - s->set("ProxyPort", ui->proxyPortEdit->value()); - s->set("ProxyUser", ui->proxyUserEdit->text()); - s->set("ProxyPass", ui->proxyPassEdit->text()); - - // Memory - s->set("MinMemAlloc", ui->minMemSpinBox->value()); - s->set("MaxMemAlloc", ui->maxMemSpinBox->value()); - s->set("PermGen", ui->permGenSpinBox->value()); - - // Java Settings - s->set("JavaPath", ui->javaPathTextBox->text()); - s->set("JvmArgs", ui->jvmArgsTextBox->text()); - NagUtils::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget()); - - // Custom Commands - s->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text()); - s->set("PostExitCommand", ui->postExitCmdTextBox->text()); - auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId(); switch (sortMode) { @@ -392,11 +283,10 @@ void SettingsPage::applySettings(SettingsObject *s) s->set("InstSortMode", "Name"); break; } - - s->set("PostExitCommand", ui->postExitCmdTextBox->text()); } -void SettingsPage::loadSettings(SettingsObject *s) +void MultiMCPage::loadSettings() { + auto s = MMC->settings(); // Language ui->languageBox->clear(); ui->languageBox->addItem(tr("English"), QLocale(QLocale::English)); @@ -437,26 +327,6 @@ void SettingsPage::loadSettings(SettingsObject *s) ui->lwjglDirTextBox->setText(s->get("LWJGLDir").toString()); ui->iconsDirTextBox->setText(s->get("IconsDir").toString()); - // Editors - ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString()); - - // Minecraft version updates - ui->autoupdateMinecraft->setChecked(s->get("AutoUpdateMinecraftVersions").toBool()); - - // Console - ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool()); - ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool()); - - // Window Size - ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool()); - ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt()); - ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt()); - - // Memory - ui->minMemSpinBox->setValue(s->get("MinMemAlloc").toInt()); - ui->maxMemSpinBox->setValue(s->get("MaxMemAlloc").toInt()); - ui->permGenSpinBox->setValue(s->get("PermGen").toInt()); - QString sortMode = s->get("InstSortMode").toString(); if (sortMode == "LastLaunch") @@ -467,81 +337,4 @@ void SettingsPage::loadSettings(SettingsObject *s) { ui->sortByNameBtn->setChecked(true); } - - // Proxy - QString proxyType = s->get("ProxyType").toString(); - if (proxyType == "Default") - ui->proxyDefaultBtn->setChecked(true); - else if (proxyType == "None") - ui->proxyNoneBtn->setChecked(true); - else if (proxyType == "SOCKS5") - ui->proxySOCKS5Btn->setChecked(true); - else if (proxyType == "HTTP") - ui->proxyHTTPBtn->setChecked(true); - - ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString()); - ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); - ui->proxyUserEdit->setText(s->get("ProxyUser").toString()); - ui->proxyPassEdit->setText(s->get("ProxyPass").toString()); - - // Java Settings - ui->javaPathTextBox->setText(s->get("JavaPath").toString()); - ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString()); - - // Custom Commands - ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString()); - ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString()); -} - -void SettingsPage::on_javaDetectBtn_clicked() -{ - JavaVersionPtr java; - - VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true); - vselect.setResizeOn(2); - vselect.exec(); - - if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) - { - java = std::dynamic_pointer_cast(vselect.selectedVersion()); - ui->javaPathTextBox->setText(java->path); - } -} -void SettingsPage::on_javaBrowseBtn_clicked() -{ - QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable")); - if (!dir.isNull()) - { - ui->javaPathTextBox->setText(dir); - } -} -void SettingsPage::on_javaTestBtn_clicked() -{ - checker.reset(new JavaChecker()); - connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this, - SLOT(checkFinished(JavaCheckResult))); - checker->path = ui->javaPathTextBox->text(); - checker->performCheck(); -} - -void SettingsPage::checkFinished(JavaCheckResult result) -{ - if (result.valid) - { - QString text; - text += "Java test succeeded!\n"; - if (result.is_64bit) - text += "Using 64bit java.\n"; - text += "\n"; - text += "Platform reported: " + result.realPlatform + "\n"; - text += "Java version reported: " + result.javaVersion; - QMessageBox::information(this, tr("Java test success"), text); - } - else - { - QMessageBox::warning( - this, tr("Java test failure"), - tr("The specified java binary didn't work. You should use the auto-detect feature, " - "or set the path to the java executable.")); - } } diff --git a/gui/pages/global/SettingsPage.h b/gui/pages/global/MultiMCPage.h similarity index 65% rename from gui/pages/global/SettingsPage.h rename to gui/pages/global/MultiMCPage.h index 46a38ec74..b465355f6 100644 --- a/gui/pages/global/SettingsPage.h +++ b/gui/pages/global/MultiMCPage.h @@ -19,47 +19,44 @@ #include #include "logic/java/JavaChecker.h" -#include "BaseSettingsPage.h" +#include "gui/pages/BasePage.h" class SettingsObject; namespace Ui { -class SettingsPage; +class MultiMCPage; } -class SettingsPage : public QWidget, public BaseSettingsPage +class MultiMCPage : public QWidget, public BasePage { Q_OBJECT public: - explicit SettingsPage(QWidget *parent = 0); - ~SettingsPage(); + explicit MultiMCPage(QWidget *parent = 0); + ~MultiMCPage(); QString displayName() const override { - return tr("Settings"); + return tr("MultiMC"); } QIcon icon() const override { - return QIcon::fromTheme("settings"); + return QIcon::fromTheme("multimc"); } QString id() const override { - return "global-settings"; + return "multimc-settings"; } QString helpPage() const override { - return "Global-settings"; + return "MultiMC-settings"; } + bool apply() override; - void updateCheckboxStuff(); - - -protected: - void applySettings(SettingsObject *s) override; - void loadSettings(SettingsObject *s) override; - virtual void closeEvent(QCloseEvent *ev); +private: + void applySettings(); + void loadSettings(); private slots: @@ -71,16 +68,6 @@ slots: void on_lwjglDirBrowseBtn_clicked(); void on_iconsDirBrowseBtn_clicked(); - void on_jsonEditorBrowseBtn_clicked(); - - void on_maximizedCheckBox_clicked(bool checked); - - void on_javaDetectBtn_clicked(); - void on_javaTestBtn_clicked(); - void on_javaBrowseBtn_clicked(); - - void checkFinished(JavaCheckResult result); - /*! * Updates the list of update channels in the combo box. */ @@ -92,11 +79,9 @@ slots: void refreshUpdateChannelDesc(); void updateChannelSelectionChanged(int index); - void proxyChanged(int); private: - Ui::SettingsPage *ui; - std::shared_ptr checker; + Ui::MultiMCPage *ui; /*! * Stores the currently selected update channel. diff --git a/gui/pages/global/MultiMCPage.ui b/gui/pages/global/MultiMCPage.ui new file mode 100644 index 000000000..f456ebc12 --- /dev/null +++ b/gui/pages/global/MultiMCPage.ui @@ -0,0 +1,399 @@ + + + MultiMCPage + + + + 0 + 0 + 545 + 609 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTabWidget::Rounded + + + 0 + + + + Features + + + + + + Update Settings + + + + + + Check for updates when MultiMC starts? + + + + + + + Update Channel: + + + + + + + false + + + + + + + No channel selected. + + + true + + + + + + + + + + FTB + + + + + + Launcher: + + + + + + + false + + + + + + + + + + Files: + + + + + + + true + + + ... + + + + + + + false + + + Qt::TabFocus + + + ... + + + + + + + Track FTB instances + + + + + + + + + + Folders + + + + + + Instances: + + + + + + + + + + ... + + + + + + + Mods: + + + + + + + + + + + + + ... + + + + + + + LWJGL: + + + + + + + ... + + + + + + + + + + Icons: + + + + + + + ... + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + User Interface + + + + + + MultiMC notifications + + + + + + Reset hidden notifications + + + true + + + + + + + + + + true + + + Instance view sorting mode + + + + + + By last launched + + + sortingModeGroup + + + + + + + By name + + + sortingModeGroup + + + + + + + + + + Language (needs restart): + + + + + + + + + + + + Icon Theme (needs restart, work in progress) + + + + + + + 0 + 0 + + + + Qt::StrongFocus + + + + Default + + + + + Simple + + + + + Simple (Light Icons) + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + tabWidget + autoUpdateCheckBox + updateChannelComboBox + trackFtbBox + ftbLauncherBox + ftbLauncherBrowseBtn + ftbBox + ftbBrowseBtn + instDirTextBox + instDirBrowseBtn + modsDirTextBox + modsDirBrowseBtn + lwjglDirTextBox + lwjglDirBrowseBtn + iconsDirTextBox + iconsDirBrowseBtn + resetNotificationsBtn + sortLastLaunchedBtn + sortByNameBtn + languageBox + themeComboBox + + + + + + + diff --git a/gui/pages/global/ProxyPage.cpp b/gui/pages/global/ProxyPage.cpp new file mode 100644 index 000000000..5578fbb7b --- /dev/null +++ b/gui/pages/global/ProxyPage.cpp @@ -0,0 +1,95 @@ +/* Copyright 2013 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 "ProxyPage.h" +#include "ui_ProxyPage.h" + +#include "logic/settings/SettingsObject.h" +#include "MultiMC.h" + +ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage) +{ + ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + loadSettings(); + updateCheckboxStuff(); + + connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int))); +} + +ProxyPage::~ProxyPage() +{ + delete ui; +} + +bool ProxyPage::apply() +{ + applySettings(); + return true; +} + +void ProxyPage::updateCheckboxStuff() +{ + ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() && + !ui->proxyDefaultBtn->isChecked()); + ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() && + !ui->proxyDefaultBtn->isChecked()); +} + +void ProxyPage::proxyChanged(int) +{ + updateCheckboxStuff(); +} + +void ProxyPage::applySettings() +{ + auto s = MMC->settings(); + + // Proxy + QString proxyType = "None"; + if (ui->proxyDefaultBtn->isChecked()) + proxyType = "Default"; + else if (ui->proxyNoneBtn->isChecked()) + proxyType = "None"; + else if (ui->proxySOCKS5Btn->isChecked()) + proxyType = "SOCKS5"; + else if (ui->proxyHTTPBtn->isChecked()) + proxyType = "HTTP"; + + s->set("ProxyType", proxyType); + s->set("ProxyAddr", ui->proxyAddrEdit->text()); + s->set("ProxyPort", ui->proxyPortEdit->value()); + s->set("ProxyUser", ui->proxyUserEdit->text()); + s->set("ProxyPass", ui->proxyPassEdit->text()); +} +void ProxyPage::loadSettings() +{ + auto s = MMC->settings(); + // Proxy + QString proxyType = s->get("ProxyType").toString(); + if (proxyType == "Default") + ui->proxyDefaultBtn->setChecked(true); + else if (proxyType == "None") + ui->proxyNoneBtn->setChecked(true); + else if (proxyType == "SOCKS5") + ui->proxySOCKS5Btn->setChecked(true); + else if (proxyType == "HTTP") + ui->proxyHTTPBtn->setChecked(true); + + ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString()); + ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); + ui->proxyUserEdit->setText(s->get("ProxyUser").toString()); + ui->proxyPassEdit->setText(s->get("ProxyPass").toString()); +} diff --git a/gui/pages/global/ProxyPage.h b/gui/pages/global/ProxyPage.h new file mode 100644 index 000000000..700a3af07 --- /dev/null +++ b/gui/pages/global/ProxyPage.h @@ -0,0 +1,66 @@ +/* Copyright 2013 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 +#include + +#include "logic/java/JavaChecker.h" +#include "gui/pages/BasePage.h" + +namespace Ui +{ +class ProxyPage; +} + +class ProxyPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit ProxyPage(QWidget *parent = 0); + ~ProxyPage(); + + QString displayName() const override + { + return tr("Proxy"); + } + QIcon icon() const override + { + return QIcon::fromTheme("proxy"); + } + QString id() const override + { + return "proxy-settings"; + } + QString helpPage() const override + { + return "Proxy-settings"; + } + bool apply() override; + +private: + void updateCheckboxStuff(); + void applySettings(); + void loadSettings(); + +private +slots: + void proxyChanged(int); + +private: + Ui::ProxyPage *ui; +}; diff --git a/gui/pages/global/ProxyPage.ui b/gui/pages/global/ProxyPage.ui new file mode 100644 index 000000000..7cddd66d6 --- /dev/null +++ b/gui/pages/global/ProxyPage.ui @@ -0,0 +1,197 @@ + + + ProxyPage + + + + 0 + 0 + 607 + 632 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + Type + + + + + + Uses your system's default proxy settings. + + + Default + + + proxyGroup + + + + + + + None + + + proxyGroup + + + + + + + SOCKS5 + + + proxyGroup + + + + + + + HTTP + + + proxyGroup + + + + + + + + + + Address and Port + + + + + + 127.0.0.1 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + QAbstractSpinBox::PlusMinus + + + 65535 + + + 8080 + + + + + + + + + + Authentication + + + + + + + + + Username: + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Note: Proxy username and password are stored in plain text inside MultiMC's configuration file! + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + diff --git a/gui/pages/global/SettingsPage.ui b/gui/pages/global/SettingsPage.ui deleted file mode 100644 index ed1d8cda8..000000000 --- a/gui/pages/global/SettingsPage.ui +++ /dev/null @@ -1,985 +0,0 @@ - - - SettingsPage - - - - 0 - 0 - 545 - 609 - - - - - 0 - 0 - - - - Settings - - - - :/icons/toolbar/settings:/icons/toolbar/settings - - - - - - QTabWidget::Rounded - - - 0 - - - - Features - - - - - - Update Settings - - - - - - Check for updates when MultiMC starts? - - - - - - - Update Channel: - - - - - - - false - - - - - - - No channel selected. - - - true - - - - - - - - - - FTB - - - - - - false - - - - 0 - 0 - - - - - 28 - 16777215 - - - - Qt::TabFocus - - - ... - - - - - - - Launcher: - - - - - - - false - - - - - - - Track FTB instances - - - - - - - - - - true - - - - 0 - 0 - - - - - 28 - 16777215 - - - - ... - - - - - - - Files: - - - - - - - - - - Folders - - - - - - Instances: - - - - - - - - - - ... - - - - - - - Mods: - - - - - - - - - - - - - ... - - - - - - - LWJGL: - - - - - - - ... - - - - - - - - - - Icons: - - - - - - - ... - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - User Interface - - - - - - - - - 0 - 0 - - - - Language (needs restart): - - - - - - - - - - - - Reset hidden notifications - - - true - - - - - - - true - - - Sorting Mode - - - - - - By last launched - - - sortingModeGroup - - - - - - - By name - - - sortingModeGroup - - - - - - - - - - Icon Theme - - - - - - - 0 - 0 - - - - Qt::StrongFocus - - - - Default - - - - - Simple - - - - - Simple (Light Icons) - - - - - - - - - - - External Editors (leave empty for system default) - - - - - - - - - JSON Editor: - - - - - - - ... - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Minecraft - - - - - - Minecraft Version Updates - - - - - - Automatically update to latest version revision - - - - - - - - - - Window Size - - - - - - Start Minecraft maximized? - - - - - - - - - Window height: - - - - - - - Window width: - - - - - - - 854 - - - 65536 - - - 1 - - - 854 - - - - - - - 480 - - - 65536 - - - 480 - - - - - - - - - - - - Console Settings - - - - - - Show console while the game is running? - - - - - - - Automatically close console when the game quits? - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Java - - - - - - Memory - - - - - - The maximum amount of memory Minecraft is allowed to use. - - - MB - - - 512 - - - 65536 - - - 128 - - - 1024 - - - - - - - Minimum memory allocation: - - - - - - - Maximum memory allocation: - - - - - - - The amount of memory Minecraft is started with. - - - MB - - - 256 - - - 65536 - - - 128 - - - 256 - - - - - - - PermGen: - - - - - - - The amount of memory available to store loaded Java classes. - - - MB - - - 64 - - - 999999999 - - - 8 - - - 64 - - - - - - - - - - Java Settings - - - - - - - 0 - 0 - - - - Java path: - - - - - - - - 0 - 0 - - - - Auto-detect... - - - - - - - - 0 - 0 - - - - Test - - - - - - - - 0 - 0 - - - - JVM arguments: - - - - - - - - - - - - - 0 - 0 - - - - - 28 - 16777215 - - - - ... - - - - - - - - - - - - - - - Custom Commands - - - - - - Post-exit command: - - - - - - - Pre-launch command: - - - - - - - - - - - - - - - - - 0 - 0 - - - - Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - Network settings. - - - Network - - - - - - Proxy - - - - - - Type - - - - - - Uses your system's default proxy settings. - - - Default - - - proxyGroup - - - - - - - None - - - proxyGroup - - - - - - - SOCKS5 - - - proxyGroup - - - - - - - HTTP - - - proxyGroup - - - - - - - - - - Address and Port - - - - - - 127.0.0.1 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - QAbstractSpinBox::PlusMinus - - - 65535 - - - 8080 - - - - - - - - - - Authentication - - - - - - - - - Username: - - - - - - - Password: - - - - - - - QLineEdit::Password - - - - - - - Note: Proxy username and password are stored in plain text inside MultiMC's configuration file! - - - true - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - settingsTabs - autoUpdateCheckBox - updateChannelComboBox - trackFtbBox - ftbLauncherBox - ftbLauncherBrowseBtn - ftbBox - ftbBrowseBtn - instDirTextBox - instDirBrowseBtn - modsDirTextBox - modsDirBrowseBtn - lwjglDirTextBox - lwjglDirBrowseBtn - iconsDirTextBox - iconsDirBrowseBtn - languageBox - resetNotificationsBtn - sortLastLaunchedBtn - sortByNameBtn - themeComboBox - jsonEditorTextBox - jsonEditorBrowseBtn - autoupdateMinecraft - maximizedCheckBox - windowWidthSpinBox - windowHeightSpinBox - showConsoleCheck - autoCloseConsoleCheck - minMemSpinBox - maxMemSpinBox - permGenSpinBox - javaPathTextBox - javaBrowseBtn - javaDetectBtn - javaTestBtn - jvmArgsTextBox - preLaunchCmdTextBox - postExitCmdTextBox - proxyDefaultBtn - proxyNoneBtn - proxySOCKS5Btn - proxyHTTPBtn - proxyAddrEdit - proxyPortEdit - proxyUserEdit - proxyPassEdit - - - - - - - - diff --git a/gui/widgets/PageContainer.cpp b/gui/widgets/PageContainer.cpp index a68f94cd0..0620c725a 100644 --- a/gui/widgets/PageContainer.cpp +++ b/gui/widgets/PageContainer.cpp @@ -124,6 +124,9 @@ void PageContainer::createUI() headerHLayout->addSpacerItem( new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); headerHLayout->addWidget(m_iconHeader); + const int rightMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutRightMargin); + headerHLayout->addSpacerItem( + new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored)); m_pageStack->setMargin(0); m_pageStack->addWidget(new QWidget(this)); diff --git a/resources/multimc/16x16/minecraft.png b/resources/multimc/16x16/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f2f2a5f583aa14c5ab25a2e8c75c51fa36a736 GIT binary patch literal 782 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!tou6nvShFJ90PTt!slge(<`^HdS-sUwvsIueYwNF*878}ay!#w~-$G!+ zw~LqiU---t#4yT~j7St!)e9TB>#?t?gG(>!msV<;HdI--@r>lf*cu?(xRRw*{S9 z#tG{lJ>F?|(LjyInPJymz4oxzI_u4L6t6yeR=+OscUAwpwoNe%#izg2#rH_Py>0u7 ze`@7}gQ>IJ!+vbueA-~w=}Q-_enu30{luSBdwc2TtLi3sEDxBbSV_4{S7jYac;&F| zbVB&XqLg_hQ3anLiasR( zzMHrw^1`hft{TpgjsKDl&G|6#QtJH!42zy@zA(k&?v%ay>?d}$XZ1?{O^eu2n-0-4`w;g7l%Q#zV&mY*h*6sVd8Oh$CD~uFQ z8`T6Z_}r9~mdMrn{)U9U!fEa<8}%=DPwjKe^^5z~dfIRKd5d`qO8ee&1f5Qwlv3do zpv^ub#@I8cr9kq?$=|;lyyw?{|8%ORU`|l3t+9Zs;KW%$-*j}iA7y%#FDS_2erfr7 z-D8>m8@GOc)R-Ps{q9Kc-f!o!`<~lw-WBlh*0J?IlX-6Q+jB3iet7KJx2^wcAKO>H vys}umy|8HCR%u0H7Y literal 0 HcmV?d00001 diff --git a/resources/multimc/24x24/minecraft.png b/resources/multimc/24x24/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..b31177c9cac2456db32e062614c322e993a323f1 GIT binary patch literal 1500 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuKT7kj!mhIn+&y?Qb~wp{eU z$M>@LW#`>bh`0BzT<7EzE4A8W#x{q;3%neABSKkKR3awva&vi!{o%gA>Lk+1dYCD- zH6n!RN|TpDsbqABDW_oH+0Dtned{jQmd~rx=}Kx*I{L_C|K0a<`p-@5>pQ~vxZ6I$ ze*LOf=Vguu&N};S`g*&sllRY6@vpkke)_tejk4#Z(_M>VX85SR*wy#gf`_fy_w=T9 zHUB^7|9SbJY2VLRpXDc~{!ER%KHrq5*`m+$@)V1{mnBvvvwc-Ooj5)oH{e;n=Tqzb zy`@SIK5gZm&#-TL>diI*rqi2NT+QlnQ%;Fo7PZ!BrjG$n^CAt6t|pBxk4aBteJ}6( zcUb>!#plKYQ{&@)ZF$eS{>HZ2bKh$ja&D(t&ApUk_OfjEmnvH`GqZx&>CMf|QoU?W z98C%e988x?QZox*e!KMY*!6uMfAp`v&%W>1;`4jLqBq)AXO+&pIMI9m?d3VsH6>MT z&L>;QBuTJM^=b`T$>K0A^~9z#-@ci3Eh>0+CNd=U(27+urN`g=FD-g}YrC2KQl>Ze zW#<>O8~&ZBjkg&%M;oSHFMQWw~^gU#M}na?|(5C+C^oe&Km`S+jY2+m9-r z$BT>4ToYb&b;{AFm0DLNZ?VhT++S=L{`AlB`H44*Z~i%|`|o4B^PMo4+;fgwm$5Vp zXkOTH-*N3Kf$hsGid@nf9%i%b7EDVhOi!PmVEedp`LzHqp~EKy?`b?bc0PYo>E6@l z&N83z>YU22r*Ma9uew5r;pta~6Ve%{tu2T;Q?&c8diL`rK|Vh{xvLY3e!sQl+xBZs z-HOKYkPq)(=T_ZL7U6$YCAoEp!98ig?;={8`eIoZFOg?nE>*gX@7I&VEk`Fg2S^uQ z;M?)Ls@wgV*oJqWU#7M7{C`yZ{uoEF*$n&W^j*fTFF8M{DEAwk+SR#8e8na=#Uq9W z-;$?giG4lBlxwc`?bnp$R+IPpXKW2UwXbPnW0LocNxnuNCu{k=SBOOQc@(WOHuJli zV$nOJ&9LoTyz-@xnH$3czTA@7x!W@Dee;q8PpveS51*N? zh7{<`Ht>|J=5%UUr`7TQ%?6$Tvl5ZWMfRLCei;7#%ei~5V20H5S!$xTt}9=y(YbnI zbBoQ_le*kjwUk9I-z01=5>7njEY*05yiw+qQfR~kfb zw0P6+C?exq^T)t(V(KE5<7TB?3a5jrl;t-sS*Y>qcYjmk?4(y(p|>sGCEQ%8(30@H z;J^Xi3#pDvrp+uCTQN&3J?zev0nw!pS3Qk>atI`v!Wwm2oyL>8-o8Hr%uBX0MZZbJ~!89lM_{yn)p;L7} z2}brXJldk*SsY`(t62WW%l!L)pFDbVhI@7ItGJswh1-pf%Jxh2yNP&|vw5jkS_QB8T|008zsk&i?*B1w{kR=ZsxRli zFHw8FY~80DuWY)MKF{91eI|?H*G-NB&sUUvz1A}+?(UwOzrHrVvib62|BpAx=Wn+U=d{3$Uhi2w3%|}?+k9Ov?6FJX&r3hM&)a@H@vhx|!;b2QF`plKe*VXM Ys(8zopr0C^|j=l}o! literal 0 HcmV?d00001 diff --git a/resources/multimc/256x256/minecraft.png b/resources/multimc/256x256/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..77e3f03e232da96142e969a91461f4d3255818e1 GIT binary patch literal 49869 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4mJh`hM1xiX$%Ys44y8IAr*7p?9H5zdNWM! z+gs!L*7xUZ-n44hu3fX`umxt*)xS@dk4=cI({YU!mx zoSu_j?BB)qU^iopYQucC50MP%aVuU#9yV}U8+Q2fdHa3?p7S={uXk0vTsnQj_U-LK zD^0%hIdO!n4!yCh_Svn>S%(T`BBq5}Yzy)_Qdslsx#y$>F?z|RrJ=IR?fV6o*6;hJ zb;zJ4b5{B}bDrdfJAUuuzh26HT(R$Q>;2~Y+W)QXUZ0(9uGlhTx8DD|@4t(`YMfG3 zm&3x~e8@VYacA`5<#B&}9#-p2-n{usklm?IEDiHnKBzVPmpc&7_+vRk9P5YD9dr2O zONxFTw11Q|ORYuVIztWHf!7TG7#Y;dZxo;4IryCMPcFl|>R%J4f7*9)DdP{0?kS(L zB--o~XFbzBy~&RAfc5h!;tYR`8Rj#8C})g#|IIk=)Nk$SY!4P|UT65zlR0a>yuAGX z!++U-->a}`OO4#H=BbtKQO$iOzL)Q_d|1w~@1bqQJ@3l-PcAXkY638#o20WtgC_fdTFZub#t-5rY?w;lEUhsCX=HKns#Ny9 zT+j1BpRq=|L91T9r6KpW0T1)tJn`!4Y6}aC0|gc#96y+zUVr+Sp)T0#XO@U-y#CTJ za;nkAn({F_O&H|!cJe(qUUUC{Q)=Y>Nh+S16NR`H6C%YfnYeDh?YjTIyNIjDq$hVo z=Vq?e=$aQF8Ts?7cKEtKj+0d4KkMx|zjV*>BF;}W7Ee7H{wp`+PYa5AS|qvdb&}D{ z1RFVRKZfv3P1Q*%jhVAnT+Lb$qO~D6x{$d=F`?s8O@)Z-grG%Xs}qxxnYFdG1)Tn< zI|}@nCh(}8;m>)7f8`7ptG|Al{^6+DbxAS1~YvOX8K%t zl{ZUm)m5!iPmN@b2R;u-(VCc$X2Nqg;K*#RrA=qg`kF}b&REuI(Kk_rv-ha+iA(MG znIE*b2>hS^*kZEMp|eYC44z(MsIhpmYsx2A&8PRpokX6!IH_gq8?5;&#i%h+LSy>r z4>tUnvz|#drms_MagaH_Ay@jm?RS~5urPt+hD{1HDtXdvTc7Kk{^fhTFiw)M-QGy9 zzy7d6&r$PTQ}}ygq#F3Q-C_6;>(sHnICi^;tKcP*P{Zmt!JS#sZH)K72d=-KD8V*K zCGg7CMW4USUz*uvz$4hE$j8U0u+(L5T>I-?T}*4+#g@G1Yj?i0xB7eX?%lihi@9E0 zZgc*(A;bPJ>w3>DwGjhFqt8yR2f+;c1RW$#SiF9+^z{STz#0z*rUDuEzQ-$maqN0M zEmhG|DAi%bkzJ22?_GXpcR4@5oXvr2*Tl-o%0g;cD!=wUPB4*r`0noR8@F#CF0g1x zjVzFP&Z_xTU+J_*ja1}}0!?`bkWD%}JJ)zT&z_k4w(#n5#S7u3hYb=U#d2-^=HjION_>h&^RJ(VO|h!3okqr~J7T|5-Eq+r+%HYVw)G7V}SS*Ey!HkP#_% z?6Kjo#~WA8Q2sDo{IEfQ)>Hvk!Lsu5i+S5OZrEcf#2Hxir&xv)-tF$?r>F+{`)*pLW^I)Q;3I+ zS+t)y{brTRk7k7f2?hZl_himGHA6(xa4+ZSO&hjt<2t?RV&3+|+h*IgZ8MPT4_#%@ z|L-z)p$z-J_lFDT^e@f)l^t|Sp5;S7!=GY?$>j!h(?9V&y~MD`zDW3hI%AD7L-c=E z$;wLS1N+rInVK4Z&hI~-EIRwLzz3^Dfg}T&1f!V>zQHq=tqiM`628W@!EEmF%6aDP z+81W{Jg#j?T*1?r=MrdxXt$3M0uDs(N{*(TxItHH3MV&18fYQl~Z3_@J`C+06-{NF@rX;7x$$Im;M zM6Z3enW~x)@$k1@&h4=4aSG>|euQd1Eob_%Mc~nVFHLc|8qNNAy_E;v_ugUo(CyR_ z-YQV6GEeE^)ZVTamGh!zPG38rvcSJ|-N8o}oc1plVCs9U@vb3J!u$Qn&ohK{rg~{i z_2Mds`L<@3VCBKmyYYs;pF=gDnltZ65!&ls^pbJU?jqR(<%~b77*rWnx=3i( zy46X=noEtCCZA+ke9`0S@2_)g*5}V!)^*(XvdiL&4iarMeAGA&2kiW~M?Sgc{`Ww= z>4~$Jd2xT5^}LY%i&*3t6N$Ek=g#i__C-$Tbkb!Z56$_kAN(hn>i#roh-WW&DY&P* zD3jryY^79W&2LVfh_@>nRNi06O+Pb7^TQe81x^jeqnW0WJ z^4AA-hCh=8ly)6qm)jpB)o@(focHh#K8E{KmaUAwA`v29`*m&D>f#6Sfp^yY?{Qlc zw?5fMPTRR4&e-!_x5J|MzgKx}Sn+b1Ud=jF~t-pn5=o=7t2dui@J`Pt_1CLI<>gXd1K4~5>}q;utU>6O=| z74zB+cnl@ZO!%dAefIS)wes27*(<_UdrV?kzI?fbrRBj4lc1gd_PlUA@cpmltPe)6 zS2nXc3anUnJS6QAOZU6u8(OY+F3LEk9Z~jv<-{60-^=lWPA^^_zIbS|-qS;%K%HsB z`@nj_!e3?v*_P){?KI$->g~Jz<|Z8zDc++SpRdZ2V0-n|%4_MQqW3R<1s|-r@4hw4 zb!A9Xq69}1LtA1(ZLMst8}nR0_O)T$%?A_sxG&tz+k1=u0MAqZAdfRn?EmI;&9|R- ztRbScPn+R$m%r=t_Zbg9C3e4)e6g2nS=$G;O?=@guv&)QFCZBX!%ChoDw?w^(2@n6V#~ZnVD|+n2Lc*ljCv~m3^0Uv` zrvK1|hPHkJ}u zPh0H0nX@QF>*0e349k}ZN|y+?|iy0$a*<_a01OU?{F-@VI$(y)UZ?5A#$n*N1{RN|)Z26&4gU_$^<2 zr}l2@^q_O1N*`r2eYS|)zw`U$9A?{^2bQi+Pg^}-5Tdp6O{>78l@@*VYzO`~QG+Q(et`1%LLrBPTj>bGj$5VCt`~Uu}EwPeq z<(Ft1#4^+4YF9Qhx+Z%5i~MPwrhDTqhr_<*4?i>132y%K(B9DZ zvr+917d>8w#wD4*dZv7Gy=<~y(Q}fqp`Af|&f{HrHs?=Uy`3egaQtdTWNDn;@;H|_ zC%ylDSNYL%Jh_!q=M=+)io+4JeVxB}Io;(j+$Zj|AZ~qfYAWm9Jn{T}Kh>5@d9}xN ziJG0ZCHuVR2S0DpdY)>M7o2e%KYv+MAJJkJ_Da=aMFPYsaxk;`~@zz_jUw`)n=^ZZ=E8?ioS1^uP8kDK0 z6RA>inQ_70yvIL&MC9%`74l$F`qj&Gd)=6O-ICXdSmu8zN&J>%BbUCF$Faf0cjLZ& z>&zr{z2b$MXZWa9e0Xs1^6}%x_fJ{&l7H5+pUx-BY^8K+Zt6SjG+~%&)2=i3J1>Kd zBFiETr{$L$AMf~3o8Q;%FFxmE+3vexFD*11e}8}f_`?T*?Ck7_`1tncm0bE3i+{}e zq*~ad;`i)ANrK&z2e$2p7i!%x0`s*PWh^pRZP0$vIA&zplrmZf_hvJ3G6D zm6el-E7yrPU#m9cMoY@e9`T;UvMm=B{Jn0@ORZlX+uUtv%u!>%Nl<+<=dZtZYLh#w zj!m8{yd_H4M2a^jFK*3^>kYIZ_aA}04*M7m%wLfzxVOq|2|QLGit5auDk29PAoiraN1PH7En9f z*7oSDS6bJuT@w+Ve(Kco6WpR5R}yv|TpQ;7_4D$H7h1ax-=Fwz_2jaOId*&u6HbX3 zO?(w`*@RnkzMjqbr@t-w7QZ;LEq8I;`tzD~c6V2rYhUF(SYZ<;!*TZmV`NmQSLfx+ z!6mz6ue>hJ$;nx8F(XC$-@lNL#~F2Q2eJ8l7MkZ4mia+9QgbDyP*u<#(n$h+Wg~HY}gn; ziH3tAy~p=rrBn8wgWK+{xgFo)DRC&^y_EzHD5U=Wt@TlxY}{pEey`+edadK)iwADq zl9K9WV_5NM@tzlVn53HgmNze6ytwuD^pCQcA%6b;7hjf$$W~d%r0r-dfA{Q|Kl6{u z!v_1JIX*rWNdvkZ4wKG-^S_^Wt6TFLo%R~P?!|FGDNk1gCpTuTjVSZ94bfTe*;(rxj?sMyCEw}nBa)3gUa->@Xtgvk^g7L;1+wUp`p_s~;YGIBa6 zdT0jfP5=00vj3vXFBe>XtH5(;r^rIRs>xTvRxH_r2kbZ>EN7_EW+*fK zx9Ahcz6hQJ#SHu858OYv<=Px!1CAzRy)|*3?n~3(tY7c7OX-u0R@d{&tW@T-%6!eG zMU^iXy^do%xHoS7at4!QZvrJ0`yLrrmdDw5EwWr^SNv-7NtW{W_l|!2Xn5_~wF^0B zQ>}GX4dl*?#G48i%C?q9Oj~NBpr!r!f3F+!)hyAz$7f1q`3?&#U%os`CWGTgb(>|C zaZp@vx^bD6EQ_N-I>)EBmdBe=cZH?OXEG}+{WHnL zcYiR)$FEKuhsu`%2w`SST^O~e`a?9!bu7eBu z#q30uQ_pUYn+GyD^0*w30!@$RhMkxzl94Ei3L@n3A-OEa7iy*ej+m)CZ)^G?w! zR`27#D@}X)pYhDX?|1XUKfe2XWR_CmWPxSJ8O|*HU1`(I<=d~o!DLhOBVg^DBcffG zDov6SB@TVIxwE4X)Gzgz#4^{<{jE{V7Fh{i#tD^CYrGZY6K+~u3>I+G*ivsHbI#N` za><37`tzTsG$x&QvJ1ahe$^w`zhd5Z?rEvD@w1lw*KWAaa6y01&Gs0(EVc)gDY0ey z1SOQ%$xb%)Aji)A0z(QPd+ah?2PW;Esc%YS;U&1o&Bmp zbF)~&;fDfy$1>sQADzmy^NviNKR+%FpS+QMGtF1U1NTZz>*e-F+2Jgen)&1-}{DvL_hyx=_$Vz|%6 z%X8hnS%0k#uZvo{%0yUQH1Ln>$EALiS8vBL2CUvYFY5IAc_u7-_{0BP%vds`dRgY7 zE$6mfe#UZDb2pFlj!92@Sypb|C4R8;?EkOjS9%xh%j78JKVG(&R}KSpv(>L> zC@o$j;w$zyCP6Oel=cmyCo?C{(=#|c(PqI6`*!J~U;FyszRi`9mrt&*k6-#kZ0GAB zuO7EZx9$^r)=lYdNftS7XmkGXw{K>%&MtGhwe!&P^NDRuAAh}jr`L8^G3I(~)CZTx zqQ^I$l6rAO{qKxL&qbUxT9-dei2meyQ&LK#NZW0(;F2k;jzsC#>Io?xnaogEw(CX> z+X4Lt&hza4Y>;Y5XQ)}9C{b_Dr5jVW+P*M@RCMvYqM?$na71UJK_m-J?9 z9N4qkUV75Cq|__b-f zE;xUzl|P#%d^IbyQnsY_XU@;+OT{;C-aL5h7~83*n?B7Dn>ejxaYao{&*aI%U#e_N zeZziwM*W%Lt6+tT#N=rqrW{ElqJb3cNWuwv8G>u=jmVQ>f z5%zT#Z62Io{(ZmN(m$MvN47Kl@Jz`)Z8znro4gtG2c}IW_v(4iUhSWpdG%(9<5zzF zqw;+29ET;}P7$-`Ic&+pFk^m6NJQM{MP2f)7w4=#Z@@5PDOaVAXycOEudlCve5_YG z!)*4~FD?A~Dil;thG;4FJ+|C3Ut6b;X%p+xDH+>ugBlRaFEcWn>+p6foGs&@gwd?3y)eQkEVF?rYMk zl4Wd-X?^@SIaJQ)=<*jcTIVIHJoG5P{Ppvfe9zY9f|2p@?rXz>&o5domwD!E!IJy$ zSFiKf#iYMmy;9)kJbu^bnMJ%a)j!BOb;wT(`lr?qcd=34l^p(h5h_hBQ>dh zQdIQHkPlBL`>(3LmSxH?WA+-?Lp}}?ZCR$Nox1B|O-}B7RBj!6bm#I-I?~|@`;3Kb z_3v^=mB`(1Ufcflrc&R#w5shJEFcT+QC>-5{~&V16zu9;Q+?6v2lKQXhG%@=a| zqp>OXqWy)Jhxu1A{xC{eIeq<6)-wG^SxK{&Et+3+_3o`(hf<6JS8ACpxe#8TaPR8# zQ?9BPSHCW4=+ZX695v^PmGN2);{)fcK<>VE%V}+x^Q>hSmX?i{cf0lPTScosF0qo` z^YNIpg{5Vn*OjcT=Qc=w4ejnSm+QZ3;iD$J=gTGU71v+yD0<5E>g%pUJQjXA&e!s` zZ`{AXKX3c&rTn(?0_m~IT#r-hgqfx@1gyS#u0?s5;)AU_gf?@1TD$$8)6SShO4msGX!xPPe?{`_3nVa~au(oP-! zc_XhqI6k4VRsO`Q!~C-tEBGR9zHZ%d;9I~imCJ&O>kJ&e6?!e5${NNXyW+v15?_ZHTl+4CZfsZnj)8?_fx*=5CT^Czifm`GJTo0%T4 zHcZrLzPPQenN;tURb>SQ4S)aEdT354ouFjMR;RtUv@&kSHd(&*7vFzd z*xDYwbxW#huN)sgf9Q?{$zt8dW-L(XP}Fv+_>Iq8I6tRer{u z-c;wr@v-y7ICl#9FUR_!Regao35f*yi}Cb)B7-epa{Y`on@1Vdqob zx+X`jf7QLnqgCy1T|8rD_q&zPFPz+Qdh?%8-&MBnkI~bfKJRMxo6Q?KlFq!hlj<$_ z|F8Dx+?bZ>ior8e`{Wuwoek(toMNXwZE2h3eXpfL*REYFn|1ct@}*PmD=qz_net@O z_pOyLf2T6+AJIhkMB zy>|2TU;T1Vy%gu9O{=cHifIg(wG1*XaY|r=`ol#Zy5tzedG4Ng{+#uG`26UfA2nui z|B1BYJ(2y?kjb`0XZqBjlYAe1?ZI9%hWIv~tN&S+b@^Z9 zG7RzYJhxlm^BVmH6-Tc>KL1(7Uf=4$F&~ESd!IjfYHJyJvwr^D&AadFT{4-w>xG@q z=Qn?| zc@;W2H|6Q^`)VyedITO_XDpdkcjUOv`>BjSj2Pw%In_K`q_F67)8AqqC@%Z9- zg4g)`YMImApTFsZTokp}|JAi&-@d-HXMI^57li3O$m#Mi4=9vb{rAtTv&&{3admYO zS@((U-3p2e7u>#|XSLGgouOv>mD=a7iq8;qme~GO)Z735#>BK)%TDQDzI))0ZR1Zb%VmdNToVs; z*}3V$t?8$qYF<2gzG<`AxhiFk7Y3{iOPsarl=bJzZVrzx9EUWHoGf(P-8(sA z?VZy+vb@V*@6wol+ACAuu7>0M=MeMxuJc$9x+=C5UH<*ouCK2zBxAwk#!nTz&MO`k zG<>WuxvrTx&5oHTS?s>>lgqYzVwxXkzc{~Y`R6abVP8M$2*rMU{dE^t>kGxXbLKpF z@q**=$BMp44Mo9r!=Ra-ajW>nvA&T;NNH1Rph!WXSle-7+gcp=%(HhlH<9l;+P zlf?VEmiWu8`{8aFN-)pVdV^FAX=m z(z`F?Y@YIGzMc`M(K~$Agy+ne z^WejWfWV%|7H%s;4t@J(cJ2E0t6l5+b?h(5Ow=8i-xNDn&n&L+p&&FhTxRdrZ;PH^3O4d#H~jX@L0{NU zVV%b>%hSi2+IHt`hOGsdJl$9AT(n`ME;)^ewy4J7%vFj0Y_sl6KuL@;AgJs8$9|tun%*@QLn8%4|oeFW1 za7xwmU{h8rX#7wjf56{cv);?glABkqnXw{9@c=i&zId;nS7&^?8n0F@S0Le zT)(^JMoyt^QEM%y+v=NWRo%5vKeQ=if}Q6|i8BZFZwE9#|K$IUw_sl5<6?uSN3@*Y z>7BXyMd{S~$7BOoMneVRWefcLwFZ}q= zq@?@Z$>h~nwLpXCPo4*^cv)Gr@loaT(mEp^=4H8B52nxF`s&RI?j?)YduY~2c>UBp zvCZc9afWl(()aULE|)tno%shNL;dSBt=wupaUZ{)JZfKiKb%3vAUMXhEtQ#*DQ#J% zmePrnCpi~s1huN~iuQZgaPIZ9tzW0kna4TtZqZJg?Mt_xGtvp-@^f0o899Ic{4=h3 zrpKEePkw&Jc-t9i-Pn(%t&e_N_bomoYHNPJ{JRbR)vVA&pK`jv6z>lWSpzVlL!6l(p_i%HR%$~EikvRly;<}I^Xas~<-YF) ztk3@bsupIddG-I_>j{3JL^D>Xr@A?2UTFXQ&+=WulYS=O|91!s zzCT)`{3F7|?$`auP2T+)_f>bixLYB!``LxF%NifI#Ime;$)MBe_Qw0f)S8Je_M7uK zS0?V7xGdnI`sB`A4X*wNU!C9aqP8@dfnjNoXXA7h-_Hy5=KHe0i+H^-|HL9~!}+bV z7hcIS6_x69Q+CZd)!)Bwg{bKy+w+?l7&t4BZ|R-CzTB*yfBWkCZ*T8^JKR6VvLc1~ z!^!`T_y1DSsX4ZGR!1|-C#KjdmOH=ZE|^wpaqZabWh+mGe(l`ha(aY{c5+UuLlzv)~?kB6#@&=A|n=yFZ}ZRujTh|dkPc(c+9Jl`x2v4BmPe6 z$lqV*ioa$yXix3R`o2|zcLld4kD~ynJ<)tH;oR3awVGuQ3pmbyF8KSaRHDr={9TNS z%8f5owr}3P)m*&q%!R-&m3udCY<&ARck0QAZ@Cq6kN>vw%WKIU-n22*bm{xwH}2dC zaZ%IbIqjmawAlT?e0?#-{b`2<*yQ%zIedEm-rw*4-LL=l{QuKS(xNAnlNtV=TT%Zf zO@6lj)xg`I5`VKz(r}eJEwfeq`;N=vDpj-kwO8ILQ8qU-+pu%z${CqepE>00zbj2+ zbxvV5UK_@}H_m_Uv8snY_m*CIoV)9FqQs+re}BLD{yQQzHdIebFnL!G%gz~m*;}JL zE|<)DzwX>y&I$g{3q_Ost)<+at?w=nSSJYh!H zA16;etMO^VjNXn#9H6$oon4sp9E0RwlXW)YCw3X}w>$H+N4jMjNF)>&3xBPOU3#XZ zjy?RQ0>_1{tp;-aiMP$9dfT$rZd)^FM)DcM?5$B8O$@zm%ukCd^^${4{4K?Km2bbC zxtG0r#`G_4zL!IMy*h+VX8TT^cwxS#ewBu)RBuSsw5>9)W_vhDG=vv7h9v#}Y8LmK zfA@~xrxcqEY8HNY^!$W!HADUD`d_R3ecCRjyK+r=r8mnu^~yGzh+K4n^N ztUGmb{%Mz|S!T0u+`8qoH?CbENzd(Z`|0TovzB#U%vchXx8{x!uW;uXw);kFcfQ+e zHM#fq#h2@J9v2)h1oh{8dwGvud+c@l_17tnCM)^yt8pvJOz{%^@$Zblg{M!yB~|u& z^t*puBq94}P1tHJo1~o6HCDWgwoLn0=iXiswpwHQ>8wL9cd$3=rnxh$nDF4o4~gT) zkH7f-yI6ac-1f^mKHr_mmTGMxdm&kTS=#26Rs2RaPnaCLw(eupnmSod$(Ez`PuHXR zbLN*#u9`hx8uYSfb*xEz<=c}fM&I@R=$RZlvNl7YV%@(ruJ`iqJ$U6d@BWce+ZoFm zo=O_{Fte}U{^8a8w-49aS9hG$a9a89kV$X!`oHzR&(B+Zz_K!h`NQ@7uh-Wc+HxfQ zvWUl{9B0q{uNG8p?YXs#eS3;>r^+OYqe}X|+c)uW&pP{Trfj@;WCnwm=kLG!f@(f( z>egBNu5g3(*#e6>x4*4=VIw7TtYY@;*&T~K9`c+?pI@q}Iw{5Neri+?&(Y79Lg%EM z$qLaDZMFIQy}Rgh=B!m`O(v;0E)5ENaBtBT)o_>dpF=uxS6>bCv6wsE;QO?lCr?jk zc_ORjd9l)j1=J-}4E{J>aQ2V29nBLy6vt&aC?`uqG723$(EWm;_d<$MpwIc4O}n^{ zPkq0jSVYX!_@sUItR)Q$vtEZzIV~!)-}Hd={{8*8=T~=VbUX-^nbCJJuVs7O|GCZX zW(@r@OcKi)rZfmNq)IpN`m_o1#pN$9ez0I?uv_ir_Q%m4k1{hROt!gueOvC)eT%ln zE%|fiIA6Q-o40QtzIfrWb|1@YG0yP(Wet-ooHKShiFKYcc=P@DitDde9rT#DWKwmM zXw(LCxx2TN8uBmJ?)26(mOsMNb#Jl-cX;?Wk(6_llK&Q&-`i3Ayl<7Kfp2iDWcRUY zQ|_g0?woC&zv%kwhf~Aj4kj1`$X1l5$j)eODU?}!{q0IWk25oL7Ms0JFg)q2az)2@ z&6jsKiXGE6p3T?SpEEgU>ba@&B4@hZ4_2S^G9n~U!lv5(z!sh#q3i|?zt_t?UTa^+ z+Mds&kj%I}>9Fo^Eu9MWPbcIK-2ZWJ|1VC4`Dg#fcyZ2T$YiPz<^DQXXjZhUg{t;p zj!BZMc`R;+&!0T`w(rxM8GUaLY)Oj_lb4ZMVf(janP|h#e$VeSU(T93RaEpc_r$km z#T6ADWxLmgRcXoFTkXEE;jP&H#dq@_fB6!!b;~vD^98P#RzIxpZ>n=$U>)y}NUjx$Mzvvlm~w{K#vif7o5+ML}PxY_BeFNIbEqP18}p!K-uXR8gCc zM})gXoSn;mf6KkIueN$!v|wz7RBV-5)sF@3>fH?1cNJdBF}~*e)YfoarEHP7{mb{W z%vr1!tp3jRq%h`Yw}{pJU01&sUocL3Wvjrz_#>2k-uXja6M$UY_Y4!7V-P2AIZCdGT-=B3q zs;=%(?_bOGgqQJhjMeo9r`GSa_3MsIIq!P(JadQD1yA#k?`$WQsTljl*LGh@{^NHw zOVr=yBg-}OYl+d{V!HLU{uEdonQLAC;aYTlqJhK;!|Tqo_WWL>z4p|-4j;#o!*M46 zGaNq6ZL7KOzBkT&Ym}}}dC|WDAB(;(CZDXeUf!Q{zwMrE|7F|tf3`o_zjTVnBbH8| zgx_ovn2wkK+VPdW-J)V|Z-UI>ueuW38ge5G?zYCg`<>6wP+6|lsd~wxHG1QQqNP1= z)58L@!vuVVj$BL}opd_OB1y@>wEoPR^2zldhJ<>3DCS*9KZ#`m`wWZ_UJlCgUZE zQ}3o2&3t@Syfg2J*HWQ*_5Uhkc9;1+-Q9hu(!}dc!zx;1h3C#;J=&QW^ka=@{Z4!9}~_WPm}*sdGX1@?-Q44g8B{bzi-^PuW#$t zt;P!*^-3Zc4{Xa>vu4c!1D?>r<>^LWK3+9ueKT>wR3>S!nceSB=HJZP8nV9r+2hY= z4k=yS%P;E_EhZK4GUocxTeoHvedXMz*R{L!N}Yj(MzW1m?}ZGL0IjLd)~)ZpH#xxH zv3Si7y;nBNK5Ow^3VC$!weFpNhm~zA_V#{E;5jU|!esj6$bRp8q5KN^4^^Cm)K{3) z=G@Im`g~G!hpO~Nl}1ILr9a%=-9clX>+J4^KbyySM`UThC*kQI>o?y#a_m@JR)y!E z0|uM=cI9k4DWj*Ju{P}Rv14r4u3ZbU&edGXG-EV9wU4taSN*a~^yD+Ugg%G<-=vKckn!fo;YC@4tKr`Kq%( zd#ye9|K|};_dmb$=F+7TOD4X)Z{-_&^|{0ISC+CWnmzOIg+ZKM4S4cM8udmEKZPWAV8@$DQf*(B4-(B&UUoPqUXWf>^5=(bAyQJOw zcr)Z#rCh_FufN{g)bKksy#IY_CZk31J65$lERQT4g_deumyM}Rb-o&0xW+V>}nBiOW`g1n0Wm5 zp?L8k#=J^Z9jj^AxtbgrizL?{n9D5n*(u=U_u8DCoP^ZW)N{%aTe5^ErXM`@@}*|m z;f0Gh=PNGBc?P~7cT}T+P5fOOn&*fYt5I4`CP9n=P_lK&O5y5bB4^# zR?p?3&-X7qr@SI;^{T126AS{}CZCEs;y6KQLoWB#sX{uJk3F0nyXU8S`;PygI3F1_ zMsG{J#m2(&$ihixes0y~8w@M<@8@S@I3d~S9{q8VLL-CG>F0eDcM0E^$Lc&|0=G>D zlg+l=$ET)hf2fTwWH_hIuI3f9`s#*l+uH8l1&zOHxkXPjaFg#pUJxsO-tM&fiJRZl5xQ-v$iP!A%<@>k?`UI&R6$llqW2QR zE7r?0SKaxh9lkE1xHx!c@>DNZ!v~*YBN`%Y&V@FuzI*N*->kE0QESEA7Eg4l|N42y zE}Oq!E=R=2hp+p1?b@_kOlvxnR_$ILqR`iQ&sxvkFJ`CBdFQoZ&Re5GeLZ&HU6*zA z=$tK5RcCcmXRc0^cu}_7;OxzPoURgG_Y$XvX8+P!Rc-OBGQ?!vmYl+4Kc=(k)cgON zBXR8DK}M^&e3wi@bN7Aa^(yUe(A*cb*6ey!_nU)x+q(}Y7<`Z0vs~`+=iL*N&dlmp zl5_m`KIi|@HQseG8hJ;XrZ~L*$FaNq;=za6wk?w-rsXdPQ8z1iw#8T})os=3eT_$~ z{r+WtI%mt^dnqNXO8dy4mdGu?QiL^TE?O43>i9R_3SP$Ld>r0NT*({~U6W4huHWfY z@Ra|sz+69f!;=-Y)8@WXJ#;{4tE*e$?z>@Mf;5-j>d&jKjV;{sb&sKX^SwH+^Ly1j znLM+$_D%V_Y`*q)RJLr5=lOvjT_F9QCONXKu<|vy|*Uq@l>dbGaed zNKv@++dGNx|F-l#zRlb+Sz=rI!A-m>o-r$ae3o-alWDQo?f90da=sHo90yaOkaE{z zo(sl45n?;v9K8~naF5}_>L5Tm#H?|pH_&oMtIs|3z-*?jZJvukQK*WE?V&zkn6^^}n7#9Ld_B=^UN zKVl3@OHmeEJz>V?7q>4gmFHo*ardsP%<-;$yLHYkO=mo@F=4&6P{%Y|?fcUiUR0iS zYN&iP{rztV9=09z|MxLTi?_yo`N6P)H*{XzugsjBoH>ah&sycgR{xCP*|OxTSVQH7 zX}ZtODXX0IW0SF;T|f7C@}1wC_4@v8>MxKvygEW_?)1IUo31dp2)?%d^7d85nM3Lo z^PL*zbgWEs^XyUSOq{8vbDGVCEk)w_k^Kw`Yu;#mbWxIESnkPSZhQ3DSGGM}+#JTA zxjq$6@|k$-W=qOanTDla2k#q~L_|g&Jax+J*)A!yrh;v`;S&Q^wg{|pP``g`_luah z2A4BTLTv3G-*!DTb+*E^dHb)Qbap+~y#ITx{M9Vcb+1>|n8v<#UEMRU^}+n-4<((> zWC`z(7PgjoIlJOXY)&nY)>N)**RO{b&hT5U_iNb~qeU7{tFIpV`0-<_*V57)1r8=r zwGVrobex$C7`Ep)svUSaSF!B>qUOoBosUdxc{@wv>RaxeKO5p=QV(rPYcSz{bMA28 zy}mu!HVn=3MxFxdoHC~yQzbesNwgVESs0;qh$ZK=%kwS$m)m2n#OXhNW&C=_rz=uk zq4~4I<~*GwDHb!uV9`6{SW%0WEds@p+cwUVJN80F)Rz6+DGR3dpIxTAzW9V29y?!r zs{7LwmM6E~Zd>(3x!~&i@6Ye#COm6<-F03>QuOVwudi?1xN+d*Nlrh1f9}9)+cN?J z6DF*xm9}M+t+{M0r*r?Q`Nim+y>5$lF4JTXNn9Pb{&A=JyaV69nbq7sUSM%#Z}s;F zmGfTRInC$G!)Vd>`}glv5#Ii`dP4Vhuc!+2XMMG!*MQ-+v7%4owY!34{}**1j%Ggc zm?iIO)BDs1_l{19cRKZRnbCnyw_5hRkUO^c#Nu$~y7%!vSsKnuCB^NOU=rDRs?#TM zQ;f-7DL2msPa&mgoIHvN9FKiC0#t+?gw#3~v0QEIe|GubXt(!Q`sCvZ=BF{i30Bu6B2e#D6#Xv1jo`kH&UaAD?r~hfj2s zu(0^O>-+HFsUBbad*#lc8>+%>mhUx1J;j(jL?0J_6kJpxZTffTb3JY2d`YzleNWb! z|9f2B!1!mc{EzeYf+v4$c9dddGFW!D{=6~6zNbk?*E%{WP1I~saZ+$rncy%>VMdEL zZ-d@NmDfk(qSronb@_Eh&h&)pXNO)ncg3wRlIp#3Y|+nMANIV^mhx2k8Co{8;M0w5 z%;#snHQDmU#`c=pily&m3j{qUv8-ObdPn7FHJ#HzJM;Dh|ND6&#@f#A*zEj$oQDlU zR=(bpzBI{WW~lzR-?dkdlt`|fxmr8CCavtnOP#KdU$1EO3K##BneTdjb-Q?WcD6*X z+m6!L(;oR>IBaRz%oe|p?p-*eK^?L3ED z1cDEga&6O_?Z1mrK#k$FgO%UJImbHuA4iw-Tfets3)mFn@lwGj+2@jg<0-D?PhI+Z zm{lj95@BoD^z_hVJ|@Y;DSi`9urRTGn&&$4#ynP!gd1`XuRZ@35Urd1w@Oqye04#s zbm5E@uMWStxlB5%MX_qH99uKvB8{Nv;;XMqMOQ!Lb=;TPvCrGUnEOEFtNdAN!9^3> zv$ifus@Yq&w?q5@r_6CftGRqubNg;BdTkRP#_t`$bNE_F__~;x&R4#^;jx{4F{9=7 z_WZ|Bo`@t$Xe3OzIeF2^lk;EmSTFnc<Xo zHe=c4^Glx}e($ct=d3kXZ=U|Qg^#X77H8hfapGuPyH@wk&SLiJ>grW%r^|h|PGxRz z`0m)ye4f9cB)cO+=&;_*5378b_5PadG&FwR^Q=`oaorEG34N-Qngvc~vPgPy{7!n9 z7bka<`Ny&PFYz@_4D-(>)o3^iEHez6sMI+*XMgb9YGam+9idC2gdG_fojHzVHr=ae zC=^ndcJj+}@k&L`+nXk;H2A1`m9l4F&x+U`)%y761Wkp@JyR~d|86M3bEQpc*YCF$ z=gtU3m`ySXT-|d|mt%$`%d_sU-+T}B2pmomtYVjoefT+bNyrC{uH|0017|o0DhK_y zKFoXU@vciRUtXFzRrJl9Hwn49zP8NP-$66DFJ5>|HG6IQH}dWZ;jR@^&dmQjuSU$) zcg6GTnKM@WFweWw@VrthMq!zuTz{x^Zc|&&$K8ANqL%CW924e9-u9?irqg&r_JrlS zuUYMUguOKjOG-ddlU)Cw!O0_JcB%u@U3SKA@$VjgImhwPqV=hyL9U_qM=_6y?4Sj; za}C+LOY&E;CvbMKbo3{yyp=HWP~>So{bQ|l{$b{dXf}o@sS5%#e+!-B*!z!R;`{>} zc$XZWxk%rL;ifQ$!c>n%5}iJVo=!cJ7&h)-FX}dEoW@+B>1cL(~KW=<<`?7M>7vGGWn)~6qKd)Q6R`-qB(emV8&-yC|-)_HmWOaQJ zJHNgCk(bfJE{`S3EVBjI&EM|vNipnMZ%Rl-G3VnACm1*wF0njOaIC3c^`no$XJK*E zy=jaU$0Hj;mNf`yOtt+I|88OR?$%S`R};~SR--_?{*7Q`bmpib|`-)lZk5utYCGOeNU)hvQa^Epa&%5+v zdDXYZj9RhUV&aPxc8nV)PZkcHxFe%A@v2;8`O~7vuZ9WyM^hJF z-}O4QQk*d`QY3g~NJ#Ld)X;8+G?pD*lb^b;&zO1e;$fkGb3g9o`*XH7oH1fwgO7^U zZpOU7xAo%w-W5|@EYO#KaBXD2!-2^PUGq= zsjMy6>euAen8?+6WlBdGGY`A%4QsPI>9rBzbI*wOAKA%2hp}bm?^r|IineA2P6Mw) z-IXjgn%0}I9FA*nR6nw0?xI}}7j1fX;2V$1M3-5oGH0cQy*lN2XhXx)BGuS>Uz$4^qZapOk7f(!wc2`lHk{VtBZ(wnz$SBgE^mYZB$99)@Zl^ytBjbX}kr|a{sN5;n= zKX;Dr)YDCm>Livm2I(HQ$g6#4_wPmg-mdVv|GF%PC6>0a?@zNg`hCsdjOK0s;6K|H zZ_1qQ>SSSQnfaGL?wjEWYd*$Js~N&h9=a$m|M&wxf8zAqC67gz8n!+@P3K zNIT;`CyphaT?Sm|HMS?j+b)@LMA7XdOQ2NxiI-PwUMV){wVklq$(G2mgeg<$;WXbX z+ia#>mx);CAe1V>6g`14J=VZ>+SziJN9)W&)MO(TA1c1gyKDX%fXHH+%LAI9lPf$*ZYp~<=t|PkUz#PYcpT2O_bPC z^;IkH-k#2_TTLb0u0?~!b~WqlbP~fHp9{X&%l-9`o-9ksil-KQX4lL&)TT;j-}XIH z*ku0iiJaZ{+v^{G-v3=}k%HUKcZbV#R8Brx`|#)7pX#>!mkk&hTO~#3uwJ&2W_qER z$fjUCXSQ4d_ldBsFOG9|{!8aQP%X^Fk!<=nm7HPA64*gb7;@* zUELeW+&By?aqE)@p z1Pv^dmy0jUTy!yGMe--74W~_fL&Z*?Gnw~X^SoO9x_5k=KW}_q`6{aF|L#2#ub$VP z>g91cq%`W#1&ope}8|UoS*N%S9`aXq1t)w;O3t}sZ#P%JNC?2);THONhw*T zTz-*!N#XOYT=)JQcHZ;Fdb@!f+X|DKDX;C8eBwJFllJZ1&TQ$ng(ob$zdr8akZ{{} ztJqJ%P49j^W960BIiFs{Hs%Vq=?eHKop_OBV_UswWvDjykywV>POqgr%7&ZvUU(d- zc)n6;sf&&(OT(&Ir<0!yy3{4yggYiNPUJdqa#H%tuFUjz5f*(HcNsh0dB1R<x9Q(cd)tX#Nh+wI&h zziUn17GGSkVVB>2_3&gxmay>ftNXvkR&-4X3NL6%*O{;PD#F3+DQqo({|tHgWsICA zdWZcQW`1{4O%oK~$=>a9>Sx&_X=&*d*I#Q*cDz@=Z#y%CMXE59nBP18kFECmy6>Lf zF5oXT<(1y6>`3+H-5U8?>9zk`4G$}yd%)%0ay<3DF}JbqX_svqza15^np6K?Zb|PYlRtmgGS*>UmYZ;i+whIgg?sX8Z_jM6u~^q?a?XHh z*|m_?8FT*j+S=Ijh3lTfkRkyuc(_By}vpVkk&!Ah2*03Bu zVdC4Gd?9+4@;{$W!(Y{fJvYubs-9;t1TA?5jqOBw8*nDAWKmX$sGc3PXE_)u)#(3N; zG5Wdw64y^B*cMdp?!OmZTXOG3!c*_?3l;15mOqTSkZ^KkwX5Dv+qXT|ZbIp64t-J5 zw`b+{z3%eGt>L45N#MT<)_0p#XZUizRB4Tg@n3wTghxVv!;SM>{QCvP1}??Bdwy-> zpCR-(v7tanY3k?M(E*G`adq5>6T?bRaNf+@9?E6te^YhmvllNomM>op8VNslj_=ji zU0O39{%dlb^GC&V%Ivk&IF@w z2OFpGntk`*q^7r~hSJ=x)Z~cbH8`;Z1ABhxhUezWxkeQ?sV?>-swliQXqv z*jl^Q5J$15&mF8*E6^Qw*e;c)|5#$c(|^^14!uX;CcZuOVkwO8LRTP^?i zO>;AI&++7({QT8Zx4f|VdN1kPrd{{ngJzaY`6EU8UL4Ba?AEyUG^37TR>!dNd=pV@sUh^cVW*K40om2Qcbdg%Y}{O=pp zPgy*t7<&9|t9^J>%QJY%gqe?``PO943R(8jMEAnz1%PJvSl0c$V;-o5#*>W+)i}$LDJ0!K_9?+QW!QA=Lo4KW2?ZZ4h z$9pHZRP|Jt404s3x!XC9xic-xKD=((hAg2&Y!lABkqXyqD!vmV%&=|SHnDF!Djn)e zUA9JrE{K*n&Xo}}CG4_feN64iq9^NIuV#flzLY*U<;xul^ZyU{oDwBgxvlmwf2Fs! zZ&&&5yT)rziyz$^Qd7nh7at#fll$A{%hCmU#w;cg`Fp=kdv)^oyVE^$eQ&$0e00cw z_1>S)>^~;gf3=GH*=)^moKxy`sKvi2x2hR)Jrxy~G$coEXyv_aqG%YMI(_nGivk86 z<{~A<{-hIrTs^5`OcCNe*I5~?e|z8ZODI$QGl@5`qkPSeDdoqQJydnhGsPrqxb2#m z&8n^cC$xv}z2cj>3cYFuKJ3qDdU0|F&uEx1;|QZ#A;a~Oz>TpMZebV8+8isMMKUCE zbKG{4^88Z2zk5<>+;|=z3JapO%GZXGVArOg1tJ|^QAVgJ^86Ceu~jjp~((Ucdc7xe}U0e z?sQPbwg+kc$6fDtu&ufMcG2y(e&#>V@Hp0h}IPFwPk!RxS-bh^!L+sU0+OG zZ}}$NVha$?xDtVA^$GLoC-XUm_#Zb7`iOwgYQYw%%Hn=w!h+$>O#51i#PL;y*|AZdD^0Fk&eY%xh`+myqA|NC_5xzQsa$^NnPhF_GxToI};YSZqwd4|F61dwm*OL zQRl!zzkN^kh;P*iey@?%YmgD~rO#Psj@9~g^KJ^>|Gsha=EY%|+a6tNJvOOrLD*_d z{WQr*ey2(&sl52QyW{S1aJFgHjHTD7nchm^IHIjMT8WdEZQv1}XKSjEz`g!U z%^{if#&iECX*BXF{0?TDq}i~2`mK7E$`s}VDW->8@^@zH1s}-dQtwQ#V4LLGWxcq{|^^)V!FLE=5bW^WQHxOiUlsKex z`>eq^(=|8$oG@S#W@`#;Vqaf+!A@df;nFF&O;MXBxD>gyL>*d`Jj3C9L&o;FdVke~ zQ+;~I*3A8G#;sQ`msBzzz7i|qy6T)`exFlbZJ?>b&CXwahxff-Eut1#TN!TOpZ?)y z$pu@)jwGt8aV&m28`-HM|L;AY) zi6(soS0ob*PDw<5t6Y($m1xB_r>)zwy6N`+UwnN3-Uvv`-#;*Q{f)Nh@#dF^| zmi?=k(8h6CB5+pBil6{-%cG1-rf@9gaGR9Uc3_i2&m*;Yt>=?CXH4t#v_JH3wd|Jf zY#DE+Y^Ynyxc-e2U-FT_T^FJsbsgu`-BBue_tl@`fJ&XyhkpICnsrtUw2WZ!;>A04 z_fFq=hvC__3)i}{#7dv2jl7OiPKq|{2F%u|HgM~{kDMr5zNO{F@~rLa3y#~>vt&{dH?pCr1*%%F&MFx&i=ii?^{-e@DMoVPR_1B4| zrJ~u{*&k~EpIIhhm2mv5&yp#ig@CJHE$VgsTF@}BVcn0@_a>iOtNkW>{oc02hn-{g z*U5gZvOOGDbkxCS+7iXuYTdod7kQPR%2Ag+zCB?E8(-em!q@!#8@~Sx=GiSAv9Gb{ z@Y%56?hzXwYq*KDuDZKT?vzcI!(86XXN60|Lu)do#2$C4(wW$oa?RrSvE=^O@~(0> z8IE{zsoZS26|*v7Ynul`~CUFZJKeOYI{FYw>~GPQEYD&sGw>}~%o zC}*iHT;H#CWTA)Y%hV}}_43#M-_8H?dZMd5Z_W3+qW0rT>Y;3((StXr&O<$>e-Z#`=_f5CJ_Vr6vy#jfh= zz+tOC9LpqoK?Q*QYn`nR5VE&U8E1Sa1&gSlGn7(jH zv)y75L&1PGVcM%Mc6`iespU<7@co^qX3o06or$G4KYh)gSMcSmdz1uFme(%#CMh+|9zqhaXG2!|7`JW#gWVZYDVzKGJ#ElUiXP=5@ocJd-`6Wv< z$AuTW>unyz|9hp$|Nmjjwla~&JxTGCQlDRn`O~m|qx|x{QkB=5@6Z1?cjD#RAJv~f zg)UhkaiVAG2Bk@huZT`5?|$%*eXDsEv(}TgSq}`&($|QWq{kn6!4UrD@n){TpLZTS zQd;5UIlo>kqds);{|ia>=MCkbYMlOF!Db%WBbdx zEuY)o9sDO3=N6df_jsK^o#NS<7B+0o^9nQ%iz#s2lu(M&?lM|_Lby(~SK@#4=Iw3F z9f}VoieJ8_KI558{F_Hz%t>3lLppsv9qU$cpP+rn=F*?5T)(#_|Jnaez?frh3)Af% zDakxqyOow#C{B6*d)0cwr6Sj6h|3%-F;YCwZKdy*z)`vKEKfwn^uA}a`>t+GF4~_^ zwEn=eSuaw5UD&OCsf*wK&jfzE9}b7Io;#jgW@m5jue@IOSj@u@>$90cLbu9E?<;=J z*WTVfXWqO|FD@#dJAZ!tjJm1E+O=(uuUd8OiN@dgU+?_c%lyjxT4{QL?9=CS9$#GS zE+Z>j`2Sz+z54&PW##3qW@|;YDrcVKw)ykdaR1Ns@gKk5w_h4->2|rPC@9a|e|}rr zI_ooU{c>B~1UX7BK5kuM=evw=14o9z&PImQi&alA=U%0A_{I@mgAZj+Q?7s9_VQTn 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 pTKQ+oxh|S( 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 scalable/console_error.svg + + scalable/proxy.svg + + + scalable/java.svg + + + 16x16/minecraft.png + 24x24/minecraft.png + 32x32/minecraft.png + 48x48/minecraft.png + 256x256/minecraft.png + 16x16/about.png 22x22/about.png diff --git a/resources/multimc/scalable/java.svg b/resources/multimc/scalable/java.svg new file mode 100644 index 000000000..fd15e5c66 --- /dev/null +++ b/resources/multimc/scalable/java.svg @@ -0,0 +1,773 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/multimc/scalable/proxy.svg b/resources/multimc/scalable/proxy.svg new file mode 100644 index 000000000..55ee6f937 --- /dev/null +++ b/resources/multimc/scalable/proxy.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + +