diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index bc0cce66..25c28063 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -730,6 +730,8 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/modrinth/ModrinthData.h ui/pages/modplatform/modrinth/ModrinthModel.cpp ui/pages/modplatform/modrinth/ModrinthModel.h + ui/pages/modplatform/modrinth/ModrinthDocument.cpp + ui/pages/modplatform/modrinth/ModrinthDocument.h ui/pages/modplatform/modrinth/ModrinthPage.cpp ui/pages/modplatform/modrinth/ModrinthPage.h diff --git a/launcher/HoeDown.h b/launcher/HoeDown.h index b9e06ffb..a8b831a1 100644 --- a/launcher/HoeDown.h +++ b/launcher/HoeDown.h @@ -57,7 +57,7 @@ public: HoeDown() { renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0); - document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8); + document = hoedown_document_new(renderer, (hoedown_extensions) HOEDOWN_EXT_TABLES, 8); } ~HoeDown() { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp new file mode 100644 index 00000000..f734610a --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2022 Petr Mrázek + * + * This source is subject to the Microsoft Permissive License (MS-PL). + * Please see the COPYING.md file for more information. + */ + +#include "ModrinthDocument.h" + +#include +#include +#include +#include +#include + +Modrinth::ModrinthDocument::ModrinthDocument(const QString &markdown, QObject* parent) : QTextDocument(parent) { + HoeDown hoedown; + // 100 MiB + QPixmapCache::setCacheLimit(102400); + setHtml(hoedown.process(markdown.toUtf8())); +} + +QVariant Modrinth::ModrinthDocument::loadResource(int type, const QUrl& name) { + if(type == QTextDocument::ResourceType::ImageResource) { + auto pixmap = QPixmapCache::find(name.toString()); + if(!pixmap) { + requestResource(name); + return QVariant(); + } + return QVariant(*pixmap); + } + return QTextDocument::loadResource(type, name); +} + +void Modrinth::ModrinthDocument::downloadFinished(const QString& key, const QPixmap& out) { + m_loading.remove(key); + QPixmapCache::insert(key, out); + emit layoutUpdateRequired(); +} + +void Modrinth::ModrinthDocument::downloadFailed(const QString& key) { + m_failed.append(key); + m_loading.remove(key); +} + +void Modrinth::ModrinthDocument::requestResource(const QUrl& url) { + QString key = url.toString(); + if(m_loading.contains(key) || m_failed.contains(key)) + { + return; + } + + qDebug() << "Loading resource" << key; + + ImageLoad *load = new ImageLoad; + load->job = new NetJob(QString("Modrinth Image Download %1").arg(key), APPLICATION->network()); + load->job->addNetAction(Net::Download::makeByteArray(url, &load->output)); + load->key = key; + + QObject::connect(load->job.get(), &NetJob::succeeded, this, [this, load] { + QPixmap pixmap; + if(!pixmap.loadFromData(load->output)) { + qDebug() << load->output; + downloadFailed(load->key); + } + if(pixmap.width() > 800) { + pixmap = pixmap.scaledToWidth(800); + } + downloadFinished(load->key, pixmap); + }); + + QObject::connect(load->job.get(), &NetJob::failed, this, [this, load] + { + downloadFailed(load->key); + }); + + load->job->start(); + + m_loading[key] = load; +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h new file mode 100644 index 00000000..218a59a7 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Petr Mrázek + * + * This source is subject to the Microsoft Permissive License (MS-PL). + * Please see the COPYING.md file for more information. + */ + +#pragma once + +#include +#include + +namespace Modrinth { + +using Callback = std::function; +struct ImageLoad { + QString key; + NetJob::Ptr job; + QByteArray output; + Callback handler; +}; + +class ModrinthDocument: public QTextDocument { + Q_OBJECT +public: + ModrinthDocument(const QString &markdown, QObject * parent = nullptr); + +signals: + void layoutUpdateRequired(); + +protected: + QVariant loadResource(int type, const QUrl & name) override; + +private: + void downloadFailed(const QString &key); + void downloadFinished(const QString &key, const QPixmap &out); + + void requestResource(const QUrl &url); + +private: + QMap m_loading; + QStringList m_failed; +}; + +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 7aebc2fa..70793185 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -17,12 +17,12 @@ #include "ModrinthModel.h" #include "ModrinthPage.h" +#include "ModrinthDocument.h" #include "ui/dialogs/NewInstanceDialog.h" #include "ui_ModrinthPage.h" #include -#include #include ModrinthPage::ModrinthPage(NewInstanceDialog *dialog, QWidget *parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) @@ -133,14 +133,6 @@ void ModrinthPage::onPackDataChanged(const QString& id) } } -namespace { -QString processMarkdown(QString input) -{ - HoeDown hoedown; - return hoedown.process(input.toUtf8()); -} -} - QString versionToString(const Modrinth::Version& version) { switch(version.type) { case Modrinth::VersionType::Alpha: { @@ -171,7 +163,9 @@ void ModrinthPage::updateCurrentPackUI() break; } case Modrinth::LoadState::Loaded: { - ui->packDescription->setText(processMarkdown(current.body)); + auto document = new Modrinth::ModrinthDocument(current.body); + connect(document, &Modrinth::ModrinthDocument::layoutUpdateRequired, this, &ModrinthPage::forceDocumentLayout); + ui->packDescription->setDocument(document); break; } } @@ -199,3 +193,7 @@ void ModrinthPage::updateCurrentPackUI() } suggestCurrent(); } + +void ModrinthPage::forceDocumentLayout() { + ui->packDescription->document()->adjustSize(); +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 8829ce2a..ddaa2db0 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -64,6 +64,7 @@ private slots: void onSelectionChanged(QModelIndex first, QModelIndex second); void onVersionSelectionChanged(const QString & version); void onPackDataChanged(const QString &id); + void forceDocumentLayout(); private: void updateCurrentPackUI(); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 7ef099d3..08dcc392 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -36,6 +36,9 @@ Qt::ScrollBarAlwaysOff + + QAbstractScrollArea::AdjustToContents + true