From 7dd1690947033efefdfd45565ff23290fe8a542d Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 28 Jun 2025 23:50:54 +0300 Subject: [PATCH] feat: display mod dependencies Signed-off-by: Trial97 --- launcher/minecraft/mod/ModFolderModel.cpp | 17 ++ launcher/minecraft/mod/ModFolderModel.h | 4 + launcher/ui/pages/instance/ModFolderPage.cpp | 2 +- launcher/ui/widgets/InfoFrame.cpp | 110 +++++--- launcher/ui/widgets/InfoFrame.h | 4 +- launcher/ui/widgets/InfoFrame.ui | 258 ++++++++++++------- 6 files changed, 258 insertions(+), 137 deletions(-) diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index 60ba0e6e2..fae832940 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -385,3 +385,20 @@ bool ModFolderModel::setResourceEnabled(const QModelIndexList& indexes, EnableAc auto affected = getAffectedMods(indexes, action); return ResourceFolderModel::setResourceEnabled(indexes + affected, action); } + +QStringList reqToList(QList l) +{ + QStringList req; + for (auto m : l) { + req << m->name(); + } + return req; +} +QStringList ModFolderModel::requiresList(QString id) +{ + return reqToList(m_requires[id]); +} +QStringList ModFolderModel::requiredByList(QString id) +{ + return reqToList(m_requiredBy[id]); +} diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h index ec1c60daa..e794cacdc 100644 --- a/launcher/minecraft/mod/ModFolderModel.h +++ b/launcher/minecraft/mod/ModFolderModel.h @@ -95,6 +95,10 @@ class ModFolderModel : public ResourceFolderModel { RESOURCE_HELPERS(Mod) + public: + QStringList requiresList(QString id); + QStringList requiredByList(QString id); + private slots: void onParseSucceeded(int ticket, QString resource_id) override; void onParseFinished(); diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp index 5951a5e33..bbaf7be94 100644 --- a/launcher/ui/pages/instance/ModFolderPage.cpp +++ b/launcher/ui/pages/instance/ModFolderPage.cpp @@ -119,7 +119,7 @@ void ModFolderPage::updateFrame(const QModelIndex& current, [[maybe_unused]] con auto sourceCurrent = m_filterModel->mapToSource(current); int row = sourceCurrent.row(); const Mod& mod = m_model->at(row); - ui->frame->updateWithMod(mod); + ui->frame->updateWithMod(mod, m_model->requiresList(mod.mod_id()), m_model->requiredByList(mod.mod_id())); } void ModFolderPage::removeItems(const QItemSelection& selection) diff --git a/launcher/ui/widgets/InfoFrame.cpp b/launcher/ui/widgets/InfoFrame.cpp index 2363b6592..cab2889ac 100644 --- a/launcher/ui/widgets/InfoFrame.cpp +++ b/launcher/ui/widgets/InfoFrame.cpp @@ -54,28 +54,34 @@ void setupLinkToolTip(QLabel* label) }); } -InfoFrame::InfoFrame(QWidget* parent) : QFrame(parent), ui(new Ui::InfoFrame) +InfoFrame::InfoFrame(QWidget* parent) : QFrame(parent), m_ui(new Ui::InfoFrame) { - ui->setupUi(this); - ui->descriptionLabel->setHidden(true); - ui->nameLabel->setHidden(true); - ui->licenseLabel->setHidden(true); - ui->issueTrackerLabel->setHidden(true); + m_ui->setupUi(this); + m_ui->descriptionLabel->setHidden(true); + m_ui->nameLabel->setHidden(true); + m_ui->licenseLabel->setHidden(true); + m_ui->issueTrackerLabel->setHidden(true); - setupLinkToolTip(ui->iconLabel); - setupLinkToolTip(ui->descriptionLabel); - setupLinkToolTip(ui->nameLabel); - setupLinkToolTip(ui->licenseLabel); - setupLinkToolTip(ui->issueTrackerLabel); + setupLinkToolTip(m_ui->iconLabel); + setupLinkToolTip(m_ui->descriptionLabel); + setupLinkToolTip(m_ui->nameLabel); + setupLinkToolTip(m_ui->licenseLabel); + setupLinkToolTip(m_ui->issueTrackerLabel); updateHiddenState(); + connect(m_ui->moreInfoBtn, &QPushButton::clicked, this, [this]() { + auto nextIndex = (m_ui->infoStacked->currentIndex() + 1) % 2; + m_ui->infoStacked->setCurrentIndex(nextIndex); + m_ui->moreInfoBtn->setText(nextIndex == 0 ? ">" : "<"); + }); + m_ui->moreInfoBtn->hide(); } InfoFrame::~InfoFrame() { - delete ui; + delete m_ui; } -void InfoFrame::updateWithMod(Mod const& m) +void InfoFrame::updateWithMod(Mod const& m, QStringList requiresList, QStringList requiredByList) { if (m.type() == ResourceType::FOLDER) { clear(); @@ -141,6 +147,26 @@ void InfoFrame::updateWithMod(Mod const& m) issueTracker += "" + m.issueTracker() + ""; } setIssueTracker(issueTracker); + if (requiredByList.isEmpty()) { + m_ui->requiredGB->hide(); + } else { + m_ui->requiredGB->show(); + m_ui->requiredView->clear(); + m_ui->requiredView->addItems(requiredByList); + } + + if (requiresList.isEmpty()) { + m_ui->requiresGB->hide(); + } else { + m_ui->requiresGB->show(); + m_ui->requiresView->clear(); + m_ui->requiresView->addItems(requiresList); + } + if (requiresList.isEmpty() && requiredByList.isEmpty()) { + m_ui->infoStacked->setCurrentIndex(0); + m_ui->moreInfoBtn->setText(">"); + } + m_ui->moreInfoBtn->setHidden(requiresList.isEmpty() && requiredByList.isEmpty()); } void InfoFrame::updateWithResource(const Resource& resource) @@ -227,7 +253,8 @@ void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack) setImage(resource_pack.image({ 64, 64 })); } -void InfoFrame::updateWithDataPack(DataPack& data_pack) { +void InfoFrame::updateWithDataPack(DataPack& data_pack) +{ setName(renderColorCodes(data_pack.name())); setDescription(renderColorCodes(data_pack.description())); setImage(data_pack.image({ 64, 64 })); @@ -254,12 +281,13 @@ void InfoFrame::clear() setImage(); setLicense(); setIssueTracker(); + m_ui->moreInfoBtn->hide(); } void InfoFrame::updateHiddenState() { - if (ui->descriptionLabel->isHidden() && ui->nameLabel->isHidden() && ui->licenseLabel->isHidden() && - ui->issueTrackerLabel->isHidden()) { + if (m_ui->descriptionLabel->isHidden() && m_ui->nameLabel->isHidden() && m_ui->licenseLabel->isHidden() && + m_ui->issueTrackerLabel->isHidden()) { setHidden(true); } else { setHidden(false); @@ -269,10 +297,10 @@ void InfoFrame::updateHiddenState() void InfoFrame::setName(QString text) { if (text.isEmpty()) { - ui->nameLabel->setHidden(true); + m_ui->nameLabel->setHidden(true); } else { - ui->nameLabel->setText(text); - ui->nameLabel->setHidden(false); + m_ui->nameLabel->setText(text); + m_ui->nameLabel->setHidden(false); } updateHiddenState(); } @@ -280,14 +308,14 @@ void InfoFrame::setName(QString text) void InfoFrame::setDescription(QString text) { if (text.isEmpty()) { - ui->descriptionLabel->setHidden(true); + m_ui->descriptionLabel->setHidden(true); updateHiddenState(); return; } else { - ui->descriptionLabel->setHidden(false); + m_ui->descriptionLabel->setHidden(false); updateHiddenState(); } - ui->descriptionLabel->setToolTip(""); + m_ui->descriptionLabel->setToolTip(""); QString intermediatetext = text.trimmed(); bool prev(false); QChar rem('\n'); @@ -309,8 +337,8 @@ void InfoFrame::setDescription(QString text) doc.setHtml(text); if (doc.characterCount() > maxCharacterElide) { - ui->descriptionLabel->setOpenExternalLinks(false); - ui->descriptionLabel->setTextFormat(Qt::TextFormat::RichText); // This allows injecting HTML here. + m_ui->descriptionLabel->setOpenExternalLinks(false); + m_ui->descriptionLabel->setTextFormat(Qt::TextFormat::RichText); // This allows injecting HTML here. m_description = text; // move the cursor to the character elide, doesn't see html @@ -323,25 +351,25 @@ void InfoFrame::setDescription(QString text) cursor.insertHtml("..."); labeltext.append(doc.toHtml()); - connect(ui->descriptionLabel, &QLabel::linkActivated, this, &InfoFrame::descriptionEllipsisHandler); + connect(m_ui->descriptionLabel, &QLabel::linkActivated, this, &InfoFrame::descriptionEllipsisHandler); } else { - ui->descriptionLabel->setTextFormat(Qt::TextFormat::AutoText); + m_ui->descriptionLabel->setTextFormat(Qt::TextFormat::AutoText); labeltext.append(finaltext); } - ui->descriptionLabel->setText(labeltext); + m_ui->descriptionLabel->setText(labeltext); } void InfoFrame::setLicense(QString text) { if (text.isEmpty()) { - ui->licenseLabel->setHidden(true); + m_ui->licenseLabel->setHidden(true); updateHiddenState(); return; } else { - ui->licenseLabel->setHidden(false); + m_ui->licenseLabel->setHidden(false); updateHiddenState(); } - ui->licenseLabel->setToolTip(""); + m_ui->licenseLabel->setToolTip(""); QString intermediatetext = text.trimmed(); bool prev(false); QChar rem('\n'); @@ -357,26 +385,26 @@ void InfoFrame::setLicense(QString text) QString labeltext; labeltext.reserve(300); if (finaltext.length() > 290) { - ui->licenseLabel->setOpenExternalLinks(false); - ui->licenseLabel->setTextFormat(Qt::TextFormat::RichText); + m_ui->licenseLabel->setOpenExternalLinks(false); + m_ui->licenseLabel->setTextFormat(Qt::TextFormat::RichText); m_license = text; // This allows injecting HTML here. labeltext.append("" + finaltext.left(287) + "..."); - connect(ui->licenseLabel, &QLabel::linkActivated, this, &InfoFrame::licenseEllipsisHandler); + connect(m_ui->licenseLabel, &QLabel::linkActivated, this, &InfoFrame::licenseEllipsisHandler); } else { - ui->licenseLabel->setTextFormat(Qt::TextFormat::AutoText); + m_ui->licenseLabel->setTextFormat(Qt::TextFormat::AutoText); labeltext.append(finaltext); } - ui->licenseLabel->setText(labeltext); + m_ui->licenseLabel->setText(labeltext); } void InfoFrame::setIssueTracker(QString text) { if (text.isEmpty()) { - ui->issueTrackerLabel->setHidden(true); + m_ui->issueTrackerLabel->setHidden(true); } else { - ui->issueTrackerLabel->setText(text); - ui->issueTrackerLabel->setHidden(false); + m_ui->issueTrackerLabel->setText(text); + m_ui->issueTrackerLabel->setHidden(false); } updateHiddenState(); } @@ -384,10 +412,10 @@ void InfoFrame::setIssueTracker(QString text) void InfoFrame::setImage(QPixmap img) { if (img.isNull()) { - ui->iconLabel->setHidden(true); + m_ui->iconLabel->setHidden(true); } else { - ui->iconLabel->setHidden(false); - ui->iconLabel->setPixmap(img); + m_ui->iconLabel->setHidden(false); + m_ui->iconLabel->setPixmap(img); } } diff --git a/launcher/ui/widgets/InfoFrame.h b/launcher/ui/widgets/InfoFrame.h index 20c54e2e5..9cec3d2f2 100644 --- a/launcher/ui/widgets/InfoFrame.h +++ b/launcher/ui/widgets/InfoFrame.h @@ -61,7 +61,7 @@ class InfoFrame : public QFrame { void clear(); - void updateWithMod(Mod const& m); + void updateWithMod(Mod const& m, QStringList requiresList = {}, QStringList requiredByList = {}); void updateWithResource(Resource const& resource); void updateWithResourcePack(ResourcePack& rp); void updateWithDataPack(DataPack& rp); @@ -78,7 +78,7 @@ class InfoFrame : public QFrame { void updateHiddenState(); private: - Ui::InfoFrame* ui; + Ui::InfoFrame* m_ui; QString m_description; QString m_license; class QMessageBox* m_current_box = nullptr; diff --git a/launcher/ui/widgets/InfoFrame.ui b/launcher/ui/widgets/InfoFrame.ui index c4d8c83d3..3e044f06f 100644 --- a/launcher/ui/widgets/InfoFrame.ui +++ b/launcher/ui/widgets/InfoFrame.ui @@ -7,7 +7,7 @@ 0 0 527 - 113 + 130 @@ -19,7 +19,7 @@ 16777215 - 120 + 130 @@ -35,6 +35,169 @@ 0 + + + + > + + + + + + + + + + + + + + + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + Requires + + + + + + true + + + QListView::Adjust + + + 10 + + + QListView::IconMode + + + + + + + + + + Required by + + + + + + true + + + QListView::Static + + + QListView::Adjust + + + 10 + + + QListView::IconMode + + + + + + + + + + @@ -60,97 +223,6 @@ - - - - - - - - - - Qt::RichText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - Qt::RichText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - Qt::RichText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - Qt::RichText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - -