aboutsummaryrefslogtreecommitdiff
path: root/launcher/ui
diff options
context:
space:
mode:
authorRachel Powers <508861+Ryex@users.noreply.github.com>2023-07-08 01:27:30 -0700
committerRachel Powers <508861+Ryex@users.noreply.github.com>2023-07-08 01:27:30 -0700
commit7f138e353801d0dde7608f2900b78cbe48d9488d (patch)
tree42d146bd6a4f2a9cf026e106aa3aa1e5aaa95642 /launcher/ui
parentb8b8c8d4acab8c794555956fae699d5706e222f3 (diff)
parent3211b265d75dc7e28b1608935396bce2ac4648dd (diff)
downloadPrismLauncher-7f138e353801d0dde7608f2900b78cbe48d9488d.tar.gz
PrismLauncher-7f138e353801d0dde7608f2900b78cbe48d9488d.tar.bz2
PrismLauncher-7f138e353801d0dde7608f2900b78cbe48d9488d.zip
Merge branch 'develop' into ci/address-sanitiser_on_debug_builds
Diffstat (limited to 'launcher/ui')
-rw-r--r--launcher/ui/MainWindow.cpp17
-rw-r--r--launcher/ui/dialogs/ProgressDialog.cpp35
-rw-r--r--launcher/ui/instanceview/AccessibleInstanceView.cpp2
-rw-r--r--launcher/ui/instanceview/InstanceView.cpp26
-rw-r--r--launcher/ui/instanceview/InstanceView.h8
-rw-r--r--launcher/ui/pages/global/APIPage.cpp4
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.ui11
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp39
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h4
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.cpp64
-rw-r--r--launcher/ui/pages/instance/WorldListPage.cpp1
-rw-r--r--launcher/ui/setupwizard/JavaWizardPage.cpp1
-rw-r--r--launcher/ui/widgets/InfoFrame.cpp203
-rw-r--r--launcher/ui/widgets/InfoFrame.h43
14 files changed, 264 insertions, 194 deletions
diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp
index 496738e3..515abf07 100644
--- a/launcher/ui/MainWindow.cpp
+++ b/launcher/ui/MainWindow.cpp
@@ -927,21 +927,8 @@ void MainWindow::onCatToggled(bool state)
void MainWindow::setCatBackground(bool enabled)
{
- if (enabled) {
- view->setStyleSheet(QString(R"(
-InstanceView
-{
- background-image: url(:/backgrounds/%1);
- background-attachment: fixed;
- background-clip: padding;
- background-position: bottom right;
- background-repeat: none;
- background-color:palette(base);
-})")
- .arg(ThemeManager::getCatImage()));
- } else {
- view->setStyleSheet(QString());
- }
+ view->setPaintCat(enabled);
+ view->viewport()->repaint();
}
void MainWindow::runModalTask(Task *task)
diff --git a/launcher/ui/dialogs/ProgressDialog.cpp b/launcher/ui/dialogs/ProgressDialog.cpp
index 246a0fd4..3368a8c4 100644
--- a/launcher/ui/dialogs/ProgressDialog.cpp
+++ b/launcher/ui/dialogs/ProgressDialog.cpp
@@ -34,6 +34,7 @@
*/
#include "ProgressDialog.h"
+#include <QPoint>
#include "ui_ProgressDialog.h"
#include <limits>
@@ -68,6 +69,7 @@ ProgressDialog::ProgressDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Pr
setAttribute(Qt::WidgetAttribute::WA_QuitOnClose, true);
setSkipButton(false);
changeProgress(0, 100);
+ updateSize();
}
void ProgressDialog::setSkipButton(bool present, QString label)
@@ -96,22 +98,29 @@ ProgressDialog::~ProgressDialog()
void ProgressDialog::updateSize()
{
QSize lastSize = this->size();
- QSize qSize = QSize(480, minimumSizeHint().height());
-
+ QPoint lastPos = this->pos();
+ int minHeight = ui->globalStatusDetailsLabel->minimumSize().height() + (ui->verticalLayout->spacing() * 2);
+ minHeight += ui->globalProgressBar->minimumSize().height() + ui->verticalLayout->spacing();
+ if (!ui->taskProgressScrollArea->isHidden())
+ minHeight += ui->taskProgressScrollArea->minimumSizeHint().height() + ui->verticalLayout->spacing();
+ if (ui->skipButton->isVisible())
+ minHeight += ui->skipButton->height() + ui->verticalLayout->spacing();
+ minHeight = std::max(minHeight, 60);
+ QSize minSize = QSize(480, minHeight);
+
+ setMinimumSize(minSize);
+ adjustSize();
+
+ QSize newSize = this->size();
// if the current window is too small
- if ((lastSize != qSize) && (lastSize.height() < qSize.height()))
+ if ((lastSize != newSize) && (lastSize.height() < newSize.height()))
{
- resize(qSize);
-
- // keep the dialog in the center after a resize
- this->move(
- this->parentWidget()->x() + (this->parentWidget()->width() - this->width()) / 2,
- this->parentWidget()->y() + (this->parentWidget()->height() - this->height()) / 2
- );
+ QSize sizeDiff = lastSize - newSize; // last size was smaller, the results should be negative
+ // center on old position after resize
+ QPoint newPos(lastPos.x() + (sizeDiff.width() / 2), lastPos.y() + (sizeDiff.height() / 2));
+ this->move(newPos);
}
- setMinimumSize(qSize);
-
}
int ProgressDialog::execWithTask(Task* task)
@@ -201,7 +210,9 @@ void ProgressDialog::onTaskSucceeded()
void ProgressDialog::changeStatus(const QString& status)
{
ui->globalStatusLabel->setText(task->getStatus());
+ ui->globalStatusLabel->adjustSize();
ui->globalStatusDetailsLabel->setText(task->getDetails());
+ ui->globalStatusDetailsLabel->adjustSize();
updateSize();
}
diff --git a/launcher/ui/instanceview/AccessibleInstanceView.cpp b/launcher/ui/instanceview/AccessibleInstanceView.cpp
index 7de3ac72..2e7b8300 100644
--- a/launcher/ui/instanceview/AccessibleInstanceView.cpp
+++ b/launcher/ui/instanceview/AccessibleInstanceView.cpp
@@ -248,8 +248,8 @@ bool AccessibleInstanceView::selectColumn(int column)
if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1) {
return false;
}
- // fallthrough intentional
}
+ /* fallthrough */
case QAbstractItemView::ContiguousSelection: {
if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
view()->clearSelection();
diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp
index fbeffe35..1911dd59 100644
--- a/launcher/ui/instanceview/InstanceView.cpp
+++ b/launcher/ui/instanceview/InstanceView.cpp
@@ -48,6 +48,7 @@
#include <QAccessible>
#include "VisualGroup.h"
+#include "ui/themes/ThemeManager.h"
#include <QDebug>
#include <Application.h>
@@ -73,6 +74,7 @@ InstanceView::InstanceView(QWidget *parent)
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setAcceptDrops(true);
setAutoScroll(true);
+ setPaintCat(APPLICATION->settings()->get("TheCat").toBool());
}
InstanceView::~InstanceView()
@@ -498,12 +500,34 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent *event)
}
}
-void InstanceView::paintEvent(QPaintEvent *event)
+void InstanceView::setPaintCat(bool visible)
+{
+ m_catVisible = visible;
+ if (visible)
+ m_catPixmap.load(QString(":/backgrounds/%1").arg(ThemeManager::getCatImage()));
+ else
+ m_catPixmap = QPixmap();
+}
+
+void InstanceView::paintEvent(QPaintEvent* event)
{
executeDelayedItemsLayout();
QPainter painter(this->viewport());
+ if (m_catVisible) {
+ int widWidth = this->viewport()->width();
+ int widHeight = this->viewport()->height();
+ if (m_catPixmap.width() < widWidth)
+ widWidth = m_catPixmap.width();
+ if (m_catPixmap.height() < widHeight)
+ widHeight = m_catPixmap.height();
+ auto pixmap = m_catPixmap.scaled(widWidth, widHeight, Qt::KeepAspectRatio);
+ QRect rectOfPixmap = pixmap.rect();
+ rectOfPixmap.moveBottomRight(this->viewport()->rect().bottomRight());
+ painter.drawPixmap(rectOfPixmap.topLeft(), pixmap);
+ }
+
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStyleOptionViewItem option;
initViewItemOption(&option);
diff --git a/launcher/ui/instanceview/InstanceView.h b/launcher/ui/instanceview/InstanceView.h
index ac338274..36405675 100644
--- a/launcher/ui/instanceview/InstanceView.h
+++ b/launcher/ui/instanceview/InstanceView.h
@@ -85,10 +85,8 @@ public:
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
- int spacing() const
- {
- return m_spacing;
- };
+ int spacing() const { return m_spacing; };
+ void setPaintCat(bool visible);
public slots:
virtual void updateGeometries() override;
@@ -139,6 +137,8 @@ private:
int m_currentItemsPerRow = -1;
int m_currentCursorColumn= -1;
mutable QCache<int, QRect> geometryCache;
+ bool m_catVisible = false;
+ QPixmap m_catPixmap;
// point where the currently active mouse action started in geometry coordinates
QPoint m_pressedPosition;
diff --git a/launcher/ui/pages/global/APIPage.cpp b/launcher/ui/pages/global/APIPage.cpp
index dca1b3a6..668aa007 100644
--- a/launcher/ui/pages/global/APIPage.cpp
+++ b/launcher/ui/pages/global/APIPage.cpp
@@ -81,6 +81,8 @@ APIPage::APIPage(QWidget *parent) :
connect(ui->pasteTypeComboBox, currentIndexChangedSignal, this, &APIPage::updateBaseURLPlaceholder);
// This function needs to be called even when the ComboBox's index is still in its default state.
updateBaseURLPlaceholder(ui->pasteTypeComboBox->currentIndex());
+ // NOTE: this allows http://, but we replace that with https later anyway
+ ui->metaURL->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->metaURL));
ui->baseURLEntry->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->baseURLEntry));
ui->msaClientID->setValidator(new QRegularExpressionValidator(validMSAClientID, ui->msaClientID));
ui->flameKey->setValidator(new QRegularExpressionValidator(validFlameKey, ui->flameKey));
@@ -163,7 +165,7 @@ void APIPage::applySettings()
QString msaClientID = ui->msaClientID->text();
s->set("MSAClientIDOverride", msaClientID);
- QUrl metaURL = ui->metaURL->text();
+ QUrl metaURL(ui->metaURL->text());
// Add required trailing slash
if (!metaURL.isEmpty() && !metaURL.path().endsWith('/'))
{
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.ui b/launcher/ui/pages/instance/ExternalResourcesPage.ui
index f676361c..3c836691 100644
--- a/launcher/ui/pages/instance/ExternalResourcesPage.ui
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.ui
@@ -157,6 +157,17 @@
<string>Try to check or update all selected resources (all resources if none are selected)</string>
</property>
</action>
+ <action name="actionVisitItemPage">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Visit mod's page</string>
+ </property>
+ <property name="toolTip">
+ <string>Go to mods home page</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index 90e7d0d6..041d1bfd 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -45,6 +45,7 @@
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>
+#include <algorithm>
#include "Application.h"
@@ -60,6 +61,7 @@
#include "minecraft/mod/Mod.h"
#include "minecraft/mod/ModFolderModel.h"
+#include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h"
#include "Version.h"
@@ -86,12 +88,30 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
ui->actionsToolbar->insertActionAfter(ui->actionAddItem, ui->actionUpdateItem);
connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
+ ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
+ ui->actionsToolbar->insertActionAfter(ui->actionViewFolder, ui->actionVisitItemPage);
+ connect(ui->actionVisitItemPage, &QAction::triggered, this, &ModFolderPage::visitModPages);
+
auto check_allow_update = [this] {
return (!m_instance || !m_instance->isRunning()) && (ui->treeView->selectionModel()->hasSelection() || !m_model->empty());
};
- connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
- [this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
+ connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this, check_allow_update] {
+ ui->actionUpdateItem->setEnabled(check_allow_update());
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
+ auto mods_list = m_model->selectedMods(selection);
+ auto selected = std::count_if(mods_list.cbegin(), mods_list.cend(),
+ [](Mod* v) { return v->metadata() != nullptr || v->homeurl().size() != 0; });
+ if (selected <= 1) {
+ ui->actionVisitItemPage->setText(tr("Visit mod's page"));
+ ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
+ } else {
+ ui->actionVisitItemPage->setText(tr("Visit mods' pages"));
+ ui->actionVisitItemPage->setToolTip(tr("Go to the pages of the selected mods"));
+ }
+ ui->actionVisitItemPage->setEnabled(selected != 0);
+ });
connect(mods.get(), &ModFolderModel::rowsInserted, this,
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
@@ -133,7 +153,7 @@ bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelI
return true;
}
-void ModFolderPage::removeItems(const QItemSelection &selection)
+void ModFolderPage::removeItems(const QItemSelection& selection)
{
m_model->deleteMods(selection.indexes());
}
@@ -207,8 +227,7 @@ void ModFolderPage::updateMods()
message = tr("All selected mods are up-to-date! :)");
}
}
- CustomMessageBox::selectable(this, tr("Update checker"), message)
- ->exec();
+ CustomMessageBox::selectable(this, tr("Update checker"), message)->exec();
return;
}
@@ -275,3 +294,13 @@ bool NilModFolderPage::shouldDisplay() const
{
return m_model->dir().exists();
}
+
+void ModFolderPage::visitModPages()
+{
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
+ for (auto mod : m_model->selectedMods(selection)) {
+ auto url = mod->metaurl();
+ if (!url.isEmpty())
+ DesktopServices::openUrl(url);
+ }
+}
diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index 2fc7b574..2c1a9c77 100644
--- a/launcher/ui/pages/instance/ModFolderPage.h
+++ b/launcher/ui/pages/instance/ModFolderPage.h
@@ -4,6 +4,7 @@
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
+ * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,10 +61,11 @@ class ModFolderPage : public ExternalResourcesPage {
private slots:
void runningStateChanged(bool running);
- void removeItems(const QItemSelection &selection) override;
+ void removeItems(const QItemSelection& selection) override;
void installMods();
void updateMods();
+ void visitModPages();
protected:
std::shared_ptr<ModFolderModel> m_model;
diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp
index 35237594..bcce5f57 100644
--- a/launcher/ui/pages/instance/ScreenshotsPage.cpp
+++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp
@@ -97,37 +97,30 @@ public:
return;
if ((info.suffix().compare("png", Qt::CaseInsensitive) != 0))
return;
- int tries = 5;
- while (tries)
- {
- if (!m_cache->stale(m_path))
- return;
- QImage image(m_path);
- if (image.isNull())
- {
- QThread::msleep(500);
- tries--;
- continue;
- }
- QImage small;
- if (image.width() > image.height())
- small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
- else
- small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
- QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
- QImage square(QSize(256, 256), QImage::Format_ARGB32);
- square.fill(Qt::transparent);
-
- QPainter painter(&square);
- painter.drawImage(offset, small);
- painter.end();
-
- QIcon icon(QPixmap::fromImage(square));
- m_cache->add(m_path, icon);
- m_resultEmitter.emitResultsReady(m_path);
+ if (!m_cache->stale(m_path))
+ return;
+ QImage image(m_path);
+ if (image.isNull()) {
+ m_resultEmitter.emitResultsFailed(m_path);
+ qDebug() << "Error loading screenshot: " + m_path + ". Perhaps too large?";
return;
}
- m_resultEmitter.emitResultsFailed(m_path);
+ QImage small;
+ if (image.width() > image.height())
+ small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
+ else
+ small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
+ QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
+ QImage square(QSize(256, 256), QImage::Format_ARGB32);
+ square.fill(Qt::transparent);
+
+ QPainter painter(&square);
+ painter.drawImage(offset, small);
+ painter.end();
+
+ QIcon icon(QPixmap::fromImage(square));
+ m_cache->add(m_path, icon);
+ m_resultEmitter.emitResultsReady(m_path);
}
QString m_path;
SharedIconCachePtr m_cache;
@@ -146,9 +139,12 @@ public:
m_thumbnailCache = std::make_shared<SharedIconCache>();
m_thumbnailCache->add("placeholder", APPLICATION->getThemedIcon("screenshot-placeholder"));
connect(&watcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
- // FIXME: the watched file set is not updated when files are removed
}
- virtual ~FilterModel() { m_thumbnailingPool.waitForDone(500); }
+ virtual ~FilterModel() {
+ m_thumbnailingPool.clear();
+ if (!m_thumbnailingPool.waitForDone(500))
+ qDebug() << "Thumbnail pool took longer than 500ms to finish";
+ }
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const
{
auto model = sourceModel();
@@ -215,10 +211,12 @@ private slots:
void fileChanged(QString filepath)
{
m_thumbnailCache->setStale(filepath);
- thumbnailImage(filepath);
// reinsert the path...
watcher.removePath(filepath);
- watcher.addPath(filepath);
+ if (QFile::exists(filepath)) {
+ watcher.addPath(filepath);
+ thumbnailImage(filepath);
+ }
}
private:
diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp
index b6ad159e..b2200b1a 100644
--- a/launcher/ui/pages/instance/WorldListPage.cpp
+++ b/launcher/ui/pages/instance/WorldListPage.cpp
@@ -339,6 +339,7 @@ void WorldListPage::mceditState(LoggedProcess::State state)
{
failed = true;
}
+ /* fallthrough */
case LoggedProcess::Running:
case LoggedProcess::Finished:
{
diff --git a/launcher/ui/setupwizard/JavaWizardPage.cpp b/launcher/ui/setupwizard/JavaWizardPage.cpp
index 14683778..2b70c47c 100644
--- a/launcher/ui/setupwizard/JavaWizardPage.cpp
+++ b/launcher/ui/setupwizard/JavaWizardPage.cpp
@@ -69,6 +69,7 @@ bool JavaWizardPage::validatePage()
case JavaSettingsWidget::ValidationStatus::AllOK:
{
settings->set("JavaPath", m_java_widget->javaPath());
+ return true;
}
case JavaSettingsWidget::ValidationStatus::JavaBad:
{
diff --git a/launcher/ui/widgets/InfoFrame.cpp b/launcher/ui/widgets/InfoFrame.cpp
index 9c041bfe..a0fda952 100644
--- a/launcher/ui/widgets/InfoFrame.cpp
+++ b/launcher/ui/widgets/InfoFrame.cpp
@@ -1,54 +1,70 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
-* PolyMC - Minecraft Launcher
-* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, version 3.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <https://www.gnu.org/licenses/>.
-*
-* This file incorporates work covered by the following copyright and
-* permission notice:
-*
-* Copyright 2013-2021 MultiMC Contributors
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QLabel>
#include <QMessageBox>
+#include <QToolTip>
#include "InfoFrame.h"
#include "ui_InfoFrame.h"
#include "ui/dialogs/CustomMessageBox.h"
-InfoFrame::InfoFrame(QWidget *parent) :
- QFrame(parent),
- ui(new Ui::InfoFrame)
+void setupLinkToolTip(QLabel* label)
+{
+ QObject::connect(label, &QLabel::linkHovered, [label](const QString& link) {
+ if (auto url = QUrl(link); !url.isValid() || (url.scheme() != "http" && url.scheme() != "https"))
+ return;
+ label->setToolTip(link);
+ });
+}
+
+InfoFrame::InfoFrame(QWidget* parent) : QFrame(parent), ui(new Ui::InfoFrame)
{
ui->setupUi(this);
ui->descriptionLabel->setHidden(true);
ui->nameLabel->setHidden(true);
ui->licenseLabel->setHidden(true);
ui->issueTrackerLabel->setHidden(true);
+
+ setupLinkToolTip(ui->iconLabel);
+ setupLinkToolTip(ui->descriptionLabel);
+ setupLinkToolTip(ui->nameLabel);
+ setupLinkToolTip(ui->licenseLabel);
+ setupLinkToolTip(ui->issueTrackerLabel);
updateHiddenState();
}
@@ -59,45 +75,43 @@ InfoFrame::~InfoFrame()
void InfoFrame::updateWithMod(Mod const& m)
{
- if (m.type() == ResourceType::FOLDER)
- {
+ if (m.type() == ResourceType::FOLDER) {
clear();
return;
}
QString text = "";
QString name = "";
+ QString link = m.metaurl();
if (m.name().isEmpty())
name = m.internal_id();
else
name = m.name();
- if (m.homeurl().isEmpty())
+ if (link.isEmpty())
text = name;
- else
- text = "<a href=\"" + m.homeurl() + "\">" + name + "</a>";
+ else {
+ text = "<a href=\"" + link + "\">" + name + "</a>";
+ }
if (!m.authors().isEmpty())
text += " by " + m.authors().join(", ");
setName(text);
- if (m.description().isEmpty())
- {
+ if (m.description().isEmpty()) {
setDescription(QString());
- }
- else
- {
+ } else {
setDescription(m.description());
}
- setImage(m.icon({64,64}));
+ setImage(m.icon({ 64, 64 }));
auto licenses = m.licenses();
QString licenseText = "";
if (!licenses.empty()) {
for (auto l : licenses) {
if (!licenseText.isEmpty()) {
- licenseText += "\n"; // add newline between licenses
+ licenseText += "\n"; // add newline between licenses
}
if (!l.name.isEmpty()) {
if (l.url.isEmpty()) {
@@ -109,9 +123,9 @@ void InfoFrame::updateWithMod(Mod const& m)
licenseText += "<a href=\"" + l.url + "\">" + l.url + "</a>";
}
if (!l.description.isEmpty() && l.description != l.name) {
- licenseText += " " + l.description;
+ licenseText += " " + l.description;
}
- }
+ }
}
if (!licenseText.isEmpty()) {
setLicense(tr("License: %1").arg(licenseText));
@@ -123,7 +137,7 @@ void InfoFrame::updateWithMod(Mod const& m)
if (!m.issueTracker().isEmpty()) {
issueTracker += tr("Report issues to: ");
issueTracker += "<a href=\"" + m.issueTracker() + "\">" + m.issueTracker() + "</a>";
- }
+ }
setIssueTracker(issueTracker);
}
@@ -133,7 +147,8 @@ void InfoFrame::updateWithResource(const Resource& resource)
setImage();
}
-QString InfoFrame::renderColorCodes(QString input) {
+QString InfoFrame::renderColorCodes(QString input)
+{
// We have to manually set the colors for use.
//
// A color is set using §x, with x = a hex number from 0 to f.
@@ -144,16 +159,12 @@ QString InfoFrame::renderColorCodes(QString input) {
// TODO: Wrap links inside <a> tags
// https://minecraft.fandom.com/wiki/Formatting_codes#Color_codes
- const QMap<QChar, QString> color_codes_map = {
- {'0', "#000000"}, {'1', "#0000AA"}, {'2', "#00AA00"}, {'3', "#00AAAA"}, {'4', "#AA0000"},
- {'5', "#AA00AA"}, {'6', "#FFAA00"}, {'7', "#AAAAAA"}, {'8', "#555555"}, {'9', "#5555FF"},
- {'a', "#55FF55"}, {'b', "#55FFFF"}, {'c', "#FF5555"}, {'d', "#FF55FF"}, {'e', "#FFFF55"},
- {'f', "#FFFFFF"}
- };
+ const QMap<QChar, QString> color_codes_map = { { '0', "#000000" }, { '1', "#0000AA" }, { '2', "#00AA00" }, { '3', "#00AAAA" },
+ { '4', "#AA0000" }, { '5', "#AA00AA" }, { '6', "#FFAA00" }, { '7', "#AAAAAA" },
+ { '8', "#555555" }, { '9', "#5555FF" }, { 'a', "#55FF55" }, { 'b', "#55FFFF" },
+ { 'c', "#FF5555" }, { 'd', "#FF55FF" }, { 'e', "#FFFF55" }, { 'f', "#FFFFFF" } };
// https://minecraft.fandom.com/wiki/Formatting_codes#Formatting_codes
- const QMap<QChar, QString> formatting_codes_map = {
- {'l', "b"}, {'m', "s"}, {'n', "u"}, {'o', "i"}
- };
+ const QMap<QChar, QString> formatting_codes_map = { { 'l', "b" }, { 'm', "s" }, { 'n', "u" }, { 'o', "i" } };
QString html("<html>");
QList<QString> tags{};
@@ -198,14 +209,14 @@ void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack)
{
setName(renderColorCodes(resource_pack.name()));
setDescription(renderColorCodes(resource_pack.description()));
- setImage(resource_pack.image({64, 64}));
+ setImage(resource_pack.image({ 64, 64 }));
}
void InfoFrame::updateWithTexturePack(TexturePack& texture_pack)
{
setName(renderColorCodes(texture_pack.name()));
setDescription(renderColorCodes(texture_pack.description()));
- setImage(texture_pack.image({64, 64}));
+ setImage(texture_pack.image({ 64, 64 }));
}
void InfoFrame::clear()
@@ -229,12 +240,9 @@ void InfoFrame::updateHiddenState()
void InfoFrame::setName(QString text)
{
- if(text.isEmpty())
- {
+ if (text.isEmpty()) {
ui->nameLabel->setHidden(true);
- }
- else
- {
+ } else {
ui->nameLabel->setText(text);
ui->nameLabel->setHidden(false);
}
@@ -243,14 +251,11 @@ void InfoFrame::setName(QString text)
void InfoFrame::setDescription(QString text)
{
- if(text.isEmpty())
- {
+ if (text.isEmpty()) {
ui->descriptionLabel->setHidden(true);
updateHiddenState();
return;
- }
- else
- {
+ } else {
ui->descriptionLabel->setHidden(false);
updateHiddenState();
}
@@ -260,9 +265,8 @@ void InfoFrame::setDescription(QString text)
QChar rem('\n');
QString finaltext;
finaltext.reserve(intermediatetext.size());
- foreach(const QChar& c, intermediatetext)
- {
- if(c == rem && prev){
+ foreach (const QChar& c, intermediatetext) {
+ if (c == rem && prev) {
continue;
}
prev = c == rem;
@@ -270,17 +274,14 @@ void InfoFrame::setDescription(QString text)
}
QString labeltext;
labeltext.reserve(300);
- if(finaltext.length() > 290)
- {
+ if (finaltext.length() > 290) {
ui->descriptionLabel->setOpenExternalLinks(false);
ui->descriptionLabel->setTextFormat(Qt::TextFormat::RichText);
m_description = text;
// This allows injecting HTML here.
labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>");
QObject::connect(ui->descriptionLabel, &QLabel::linkActivated, this, &InfoFrame::descriptionEllipsisHandler);
- }
- else
- {
+ } else {
ui->descriptionLabel->setTextFormat(Qt::TextFormat::AutoText);
labeltext.append(finaltext);
}
@@ -289,14 +290,11 @@ void InfoFrame::setDescription(QString text)
void InfoFrame::setLicense(QString text)
{
- if(text.isEmpty())
- {
+ if (text.isEmpty()) {
ui->licenseLabel->setHidden(true);
updateHiddenState();
return;
- }
- else
- {
+ } else {
ui->licenseLabel->setHidden(false);
updateHiddenState();
}
@@ -306,9 +304,8 @@ void InfoFrame::setLicense(QString text)
QChar rem('\n');
QString finaltext;
finaltext.reserve(intermediatetext.size());
- foreach(const QChar& c, intermediatetext)
- {
- if(c == rem && prev){
+ foreach (const QChar& c, intermediatetext) {
+ if (c == rem && prev) {
continue;
}
prev = c == rem;
@@ -316,17 +313,14 @@ void InfoFrame::setLicense(QString text)
}
QString labeltext;
labeltext.reserve(300);
- if(finaltext.length() > 290)
- {
+ if (finaltext.length() > 290) {
ui->licenseLabel->setOpenExternalLinks(false);
ui->licenseLabel->setTextFormat(Qt::TextFormat::RichText);
m_description = text;
// This allows injecting HTML here.
labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>");
QObject::connect(ui->licenseLabel, &QLabel::linkActivated, this, &InfoFrame::licenseEllipsisHandler);
- }
- else
- {
+ } else {
ui->licenseLabel->setTextFormat(Qt::TextFormat::AutoText);
labeltext.append(finaltext);
}
@@ -335,12 +329,9 @@ void InfoFrame::setLicense(QString text)
void InfoFrame::setIssueTracker(QString text)
{
- if(text.isEmpty())
- {
+ if (text.isEmpty()) {
ui->issueTrackerLabel->setHidden(true);
- }
- else
- {
+ } else {
ui->issueTrackerLabel->setText(text);
ui->issueTrackerLabel->setHidden(false);
}
@@ -359,28 +350,22 @@ void InfoFrame::setImage(QPixmap img)
void InfoFrame::descriptionEllipsisHandler(QString link)
{
- if(!m_current_box)
- {
+ if (!m_current_box) {
m_current_box = CustomMessageBox::selectable(this, "", m_description);
connect(m_current_box, &QMessageBox::finished, this, &InfoFrame::boxClosed);
m_current_box->show();
- }
- else
- {
+ } else {
m_current_box->setText(m_description);
}
}
void InfoFrame::licenseEllipsisHandler(QString link)
{
- if(!m_current_box)
- {
+ if (!m_current_box) {
m_current_box = CustomMessageBox::selectable(this, "", m_license);
connect(m_current_box, &QMessageBox::finished, this, &InfoFrame::boxClosed);
m_current_box->show();
- }
- else
- {
+ } else {
m_current_box->setText(m_license);
}
}
diff --git a/launcher/ui/widgets/InfoFrame.h b/launcher/ui/widgets/InfoFrame.h
index 7eb679a9..d6764baa 100644
--- a/launcher/ui/widgets/InfoFrame.h
+++ b/launcher/ui/widgets/InfoFrame.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#pragma once
@@ -21,8 +41,7 @@
#include "minecraft/mod/ResourcePack.h"
#include "minecraft/mod/TexturePack.h"
-namespace Ui
-{
+namespace Ui {
class InfoFrame;
}