From a501441e6ee6a4bba3bbf9c0847b6ee9c0007197 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Mon, 17 Mar 2025 21:32:37 +0000 Subject: [PATCH 01/15] Paint project item backgrounds with native style Signed-off-by: TheKodeToad --- launcher/ui/widgets/ProjectItem.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index 6946df41f..f313b58e8 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -2,6 +2,7 @@ #include "Common.h" +#include #include #include @@ -16,12 +17,12 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o auto rect = opt.rect; - if (opt.state & QStyle::State_Selected) { - painter->fillRect(rect, opt.palette.highlight()); + const QStyle* style = opt.widget == nullptr ? QApplication::style() : opt.widget->style(); + + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); + + if (option.state & QStyle::State_Selected) painter->setPen(opt.palette.highlightedText().color()); - } else if (opt.state & QStyle::State_MouseOver) { - painter->fillRect(rect, opt.palette.window()); - } // The default icon size will be a square (and height is usually the lower value). auto icon_width = rect.height(), icon_height = rect.height(); From 5f70335a07f8502f49a965f93f77fff49fd1bf1f Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 18 Mar 2025 19:44:13 +0000 Subject: [PATCH 02/15] Render checkbox in project items Signed-off-by: TheKodeToad --- .../ui/pages/modplatform/ResourceModel.cpp | 2 + launcher/ui/widgets/ProjectItem.cpp | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 6b8309fb7..b571ead0a 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -84,6 +84,8 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant return pack->description; case UserDataTypes::SELECTED: return pack->isAnyVersionSelected(); + case Qt::CheckStateRole: + return pack->isAnyVersionSelected() ? Qt::Checked : Qt::Unchecked; case UserDataTypes::INSTALLED: return this->isPackInstalled(pack); default: diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index f313b58e8..141a5191b 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -1,10 +1,11 @@ #include "ProjectItem.h" -#include "Common.h" - #include + +#include #include #include +#include "Common.h" ProjectItemDelegate::ProjectItemDelegate(QWidget* parent) : QStyledItemDelegate(parent) {} @@ -24,6 +25,27 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o if (option.state & QStyle::State_Selected) painter->setPen(opt.palette.highlightedText().color()); + if (opt.features & QStyleOptionViewItem::HasCheckIndicator) { + // 5px will be the typical margin with 48px icon size + // we don't want the checkbox to be all over the place + rect.translate(5, 0); + + QStyleOptionViewItem checkboxOpt = opt; + + checkboxOpt.state &= ~QStyle::State_HasFocus; + + if (checkboxOpt.checkState == Qt::Checked) + checkboxOpt.state |= QStyle::State_On; + + QRect checkboxRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &checkboxOpt, opt.widget); + checkboxOpt.rect = + QRect(rect.x(), rect.y() + (rect.height() / 2 - checkboxRect.height() / 2), checkboxRect.width(), checkboxRect.height()); + + style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &checkboxOpt, painter, opt.widget); + + rect.setX(rect.x() + checkboxRect.width()); + } + // The default icon size will be a square (and height is usually the lower value). auto icon_width = rect.height(), icon_height = rect.height(); int icon_x_margin = (rect.height() - icon_width) / 2; @@ -43,6 +65,9 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o int x = rect.x() + icon_x_margin; int y = rect.y() + icon_y_margin; + if (opt.features & QStyleOptionViewItem::HasCheckIndicator) + rect.translate(icon_x_margin / 2, 0); + // Prevent 'scaling null pixmap' warnings if (icon_width > 0 && icon_height > 0) opt.icon.paint(painter, x, y, icon_width, icon_height); @@ -60,23 +85,6 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o painter->save(); auto font = opt.font; - if (index.data(UserDataTypes::SELECTED).toBool()) { - // Set nice font - font.setBold(true); - font.setUnderline(true); - } - if (index.data(UserDataTypes::INSTALLED).toBool()) { - auto hRect = opt.rect; - hRect.setX(hRect.x() + 1); - hRect.setY(hRect.y() + 1); - hRect.setHeight(hRect.height() - 2); - hRect.setWidth(hRect.width() - 2); - // Set nice font - font.setItalic(true); - font.setOverline(true); - painter->drawRect(hRect); - } - font.setPointSize(font.pointSize() + 2); painter->setFont(font); From 8577f58fe3b807c504656fdbaac2c64016e91f59 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 18 Mar 2025 20:44:01 +0000 Subject: [PATCH 03/15] Remove UserDataTypes::SELECTED Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourceModel.cpp | 3 --- launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp | 2 -- launcher/ui/pages/modplatform/flame/FlameModel.cpp | 2 -- launcher/ui/pages/modplatform/import_ftb/ListModel.cpp | 2 -- launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp | 2 -- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 -- launcher/ui/pages/modplatform/technic/TechnicModel.cpp | 2 -- launcher/ui/widgets/ProjectItem.h | 1 - 8 files changed, 16 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index b571ead0a..7fcb6edb1 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -82,8 +82,6 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant return pack->name; case UserDataTypes::DESCRIPTION: return pack->description; - case UserDataTypes::SELECTED: - return pack->isAnyVersionSelected(); case Qt::CheckStateRole: return pack->isAnyVersionSelected() ? Qt::Checked : Qt::Unchecked; case UserDataTypes::INSTALLED: @@ -105,7 +103,6 @@ QHash ResourceModel::roleNames() const roles[Qt::UserRole] = "pack"; roles[UserDataTypes::TITLE] = "title"; roles[UserDataTypes::DESCRIPTION] = "description"; - roles[UserDataTypes::SELECTED] = "selected"; roles[UserDataTypes::INSTALLED] = "installed"; return roles; diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp index f116ca915..e381f2a16 100644 --- a/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp +++ b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp @@ -82,8 +82,6 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return pack.name; case UserDataTypes::DESCRIPTION: return pack.description; - case UserDataTypes::SELECTED: - return false; case UserDataTypes::INSTALLED: return false; default: diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 18a2adc49..d501bf9f4 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -65,8 +65,6 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return pack.name; case UserDataTypes::DESCRIPTION: return pack.description; - case UserDataTypes::SELECTED: - return false; case UserDataTypes::INSTALLED: return false; default: diff --git a/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp index f3c737977..eaec76a04 100644 --- a/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp +++ b/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp @@ -128,8 +128,6 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return pack.name; case UserDataTypes::DESCRIPTION: return tr("Minecraft %1").arg(pack.mcVersion); - case UserDataTypes::SELECTED: - return false; case UserDataTypes::INSTALLED: return false; default: diff --git a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp index 98922123c..4ddc6da5d 100644 --- a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp +++ b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp @@ -195,8 +195,6 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return pack.name; case UserDataTypes::DESCRIPTION: return pack.description; - case UserDataTypes::SELECTED: - return false; case UserDataTypes::INSTALLED: return false; default: diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 416c69d28..4681b1a7f 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -106,8 +106,6 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian return pack.name; case UserDataTypes::DESCRIPTION: return pack.description; - case UserDataTypes::SELECTED: - return false; case UserDataTypes::INSTALLED: return false; default: diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp index f7e7f4433..c689ab0d2 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp @@ -89,8 +89,6 @@ QVariant Technic::ListModel::data(const QModelIndex& index, int role) const return pack.name; case UserDataTypes::DESCRIPTION: return pack.description; - case UserDataTypes::SELECTED: - return false; case UserDataTypes::INSTALLED: return false; default: diff --git a/launcher/ui/widgets/ProjectItem.h b/launcher/ui/widgets/ProjectItem.h index c3d0dce70..96e62af12 100644 --- a/launcher/ui/widgets/ProjectItem.h +++ b/launcher/ui/widgets/ProjectItem.h @@ -6,7 +6,6 @@ enum UserDataTypes { TITLE = 257, // QString DESCRIPTION = 258, // QString - SELECTED = 259, // bool INSTALLED = 260 // bool }; From 900579eea6f0732239b5dd1c7907fb8cb7ee3f7e Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 01:17:25 +0000 Subject: [PATCH 04/15] Handle checkbox toggle Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ModModel.cpp | 4 +- launcher/ui/pages/modplatform/ModModel.h | 4 +- launcher/ui/pages/modplatform/ModPage.cpp | 1 - launcher/ui/pages/modplatform/ModPage.h | 2 +- .../ui/pages/modplatform/ResourceModel.cpp | 6 +- launcher/ui/pages/modplatform/ResourceModel.h | 14 +-- .../pages/modplatform/ResourcePackModel.cpp | 4 +- .../ui/pages/modplatform/ResourcePackModel.h | 4 +- .../ui/pages/modplatform/ResourcePackPage.cpp | 4 +- .../ui/pages/modplatform/ResourcePackPage.h | 2 +- .../ui/pages/modplatform/ResourcePage.cpp | 113 +++++++++++++----- launcher/ui/pages/modplatform/ResourcePage.h | 7 +- .../ui/pages/modplatform/ShaderPackModel.cpp | 4 +- .../ui/pages/modplatform/ShaderPackModel.h | 4 +- .../ui/pages/modplatform/ShaderPackPage.cpp | 5 +- .../ui/pages/modplatform/ShaderPackPage.h | 2 +- .../ui/pages/modplatform/TexturePackModel.cpp | 2 +- .../ui/pages/modplatform/TexturePackModel.h | 2 +- .../ui/pages/modplatform/TexturePackPage.h | 7 +- .../modplatform/flame/FlameResourceModels.cpp | 2 +- .../modplatform/flame/FlameResourceModels.h | 2 +- launcher/ui/widgets/ProjectItem.cpp | 70 ++++++++--- launcher/ui/widgets/ProjectItem.h | 10 +- tests/ResourceModel_test.cpp | 4 +- 24 files changed, 185 insertions(+), 94 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index cfc262b62..6e98a88bc 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -44,7 +44,7 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments() }; } -ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry) +ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(const QModelIndex& entry) { auto& pack = *m_packs[entry.row()]; auto profile = static_cast(m_base_instance).getPackProfile(); @@ -62,7 +62,7 @@ ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& en return { pack, versions, loaders }; } -ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(QModelIndex& entry) +ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(const QModelIndex& entry) { auto& pack = *m_packs[entry.row()]; return { pack }; diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 5c994f373..bb9255cd0 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -39,8 +39,8 @@ class ModModel : public ResourceModel { public slots: ResourceAPI::SearchArgs createSearchArguments() override; - ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) override; - ResourceAPI::ProjectInfoArgs createInfoArguments(QModelIndex&) override; + ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override; + ResourceAPI::ProjectInfoArgs createInfoArguments(const QModelIndex&) override; protected: auto documentToArray(QJsonDocument& obj) const -> QJsonArray override = 0; diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index f0cc2df54..8b4919015 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -59,7 +59,6 @@ namespace ResourceDownload { ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance) { connect(m_ui->resourceFilterButton, &QPushButton::clicked, this, &ModPage::filterMods); - connect(m_ui->packView, &QListView::doubleClicked, this, &ModPage::onResourceSelected); } void ModPage::setFilterWidget(unique_qobject_ptr& widget) diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index 5c9a82303..397b77d94 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -35,7 +35,7 @@ class ModPage : public ResourcePage { page->setFilterWidget(filter_widget); model->setFilter(page->getFilter()); - connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::updateVersionList); + connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); return page; diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 7fcb6edb1..8e3be5e8f 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -192,7 +192,7 @@ void ResourceModel::search() runSearchJob(job); } -void ResourceModel::loadEntry(QModelIndex& entry) +void ResourceModel::loadEntry(const QModelIndex& entry) { auto const& pack = m_packs[entry.row()]; @@ -503,7 +503,7 @@ void ResourceModel::versionRequestSucceeded(QJsonDocument& doc, ModPlatform::Ind return; } - emit versionListUpdated(); + emit versionListUpdated(index); } void ResourceModel::infoRequestSucceeded(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index) @@ -530,7 +530,7 @@ void ResourceModel::infoRequestSucceeded(QJsonDocument& doc, ModPlatform::Indexe return; } - emit projectInfoUpdated(); + emit projectInfoUpdated(index); } void ResourceModel::addPack(ModPlatform::IndexedPack::Ptr pack, diff --git a/launcher/ui/pages/modplatform/ResourceModel.h b/launcher/ui/pages/modplatform/ResourceModel.h index 4c7ea33a0..3f1e633ec 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.h +++ b/launcher/ui/pages/modplatform/ResourceModel.h @@ -80,17 +80,17 @@ class ResourceModel : public QAbstractListModel { virtual ResourceAPI::SearchArgs createSearchArguments() = 0; virtual ResourceAPI::SearchCallbacks createSearchCallbacks() { return {}; } - virtual ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) = 0; - virtual ResourceAPI::VersionSearchCallbacks createVersionsCallbacks(QModelIndex&) { return {}; } + virtual ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) = 0; + virtual ResourceAPI::VersionSearchCallbacks createVersionsCallbacks(const QModelIndex&) { return {}; } - virtual ResourceAPI::ProjectInfoArgs createInfoArguments(QModelIndex&) = 0; - virtual ResourceAPI::ProjectInfoCallbacks createInfoCallbacks(QModelIndex&) { return {}; } + virtual ResourceAPI::ProjectInfoArgs createInfoArguments(const QModelIndex&) = 0; + virtual ResourceAPI::ProjectInfoCallbacks createInfoCallbacks(const QModelIndex&) { return {}; } /** Requests the API for more entries. */ virtual void search(); /** Applies any processing / extra requests needed to fully load the specified entry's information. */ - virtual void loadEntry(QModelIndex&); + virtual void loadEntry(const QModelIndex&); /** Schedule a refresh, clearing the current state. */ void refresh(); @@ -170,8 +170,8 @@ class ResourceModel : public QAbstractListModel { void infoRequestSucceeded(QJsonDocument&, ModPlatform::IndexedPack&, const QModelIndex&); signals: - void versionListUpdated(); - void projectInfoUpdated(); + void versionListUpdated(const QModelIndex& index); + void projectInfoUpdated(const QModelIndex& index); }; } // namespace ResourceDownload diff --git a/launcher/ui/pages/modplatform/ResourcePackModel.cpp b/launcher/ui/pages/modplatform/ResourcePackModel.cpp index d436f320f..0de980ed8 100644 --- a/launcher/ui/pages/modplatform/ResourcePackModel.cpp +++ b/launcher/ui/pages/modplatform/ResourcePackModel.cpp @@ -20,13 +20,13 @@ ResourceAPI::SearchArgs ResourcePackResourceModel::createSearchArguments() return { ModPlatform::ResourceType::RESOURCE_PACK, m_next_search_offset, m_search_term, sort }; } -ResourceAPI::VersionSearchArgs ResourcePackResourceModel::createVersionsArguments(QModelIndex& entry) +ResourceAPI::VersionSearchArgs ResourcePackResourceModel::createVersionsArguments(const QModelIndex& entry) { auto& pack = m_packs[entry.row()]; return { *pack }; } -ResourceAPI::ProjectInfoArgs ResourcePackResourceModel::createInfoArguments(QModelIndex& entry) +ResourceAPI::ProjectInfoArgs ResourcePackResourceModel::createInfoArguments(const QModelIndex& entry) { auto& pack = m_packs[entry.row()]; return { *pack }; diff --git a/launcher/ui/pages/modplatform/ResourcePackModel.h b/launcher/ui/pages/modplatform/ResourcePackModel.h index e2b4a1957..4f00808e8 100644 --- a/launcher/ui/pages/modplatform/ResourcePackModel.h +++ b/launcher/ui/pages/modplatform/ResourcePackModel.h @@ -31,8 +31,8 @@ class ResourcePackResourceModel : public ResourceModel { public slots: ResourceAPI::SearchArgs createSearchArguments() override; - ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) override; - ResourceAPI::ProjectInfoArgs createInfoArguments(QModelIndex&) override; + ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override; + ResourceAPI::ProjectInfoArgs createInfoArguments(const QModelIndex&) override; protected: const BaseInstance& m_base_instance; diff --git a/launcher/ui/pages/modplatform/ResourcePackPage.cpp b/launcher/ui/pages/modplatform/ResourcePackPage.cpp index 99039476e..8a7ed2720 100644 --- a/launcher/ui/pages/modplatform/ResourcePackPage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePackPage.cpp @@ -14,9 +14,7 @@ namespace ResourceDownload { ResourcePackResourcePage::ResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance) -{ - connect(m_ui->packView, &QListView::doubleClicked, this, &ResourcePackResourcePage::onResourceSelected); -} +{} /******** Callbacks to events in the UI (set up in the derived classes) ********/ diff --git a/launcher/ui/pages/modplatform/ResourcePackPage.h b/launcher/ui/pages/modplatform/ResourcePackPage.h index 440d91ab0..3f925fd23 100644 --- a/launcher/ui/pages/modplatform/ResourcePackPage.h +++ b/launcher/ui/pages/modplatform/ResourcePackPage.h @@ -25,7 +25,7 @@ class ResourcePackResourcePage : public ResourcePage { auto page = new T(dialog, instance); auto model = static_cast(page->getModel()); - connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::updateVersionList); + connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); return page; diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 2dd5ccf0f..407684f8b 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -78,10 +78,14 @@ ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& base_in m_ui->verticalLayout->insertWidget(1, &m_fetchProgress); - m_ui->packView->setItemDelegate(new ProjectItemDelegate(this)); + auto delegate = new ProjectItemDelegate(this); + m_ui->packView->setItemDelegate(delegate); m_ui->packView->installEventFilter(this); connect(m_ui->packDescription, &QTextBrowser::anchorClicked, this, &ResourcePage::openUrl); + + connect(m_ui->packView, &QListView::doubleClicked, this, &ResourcePage::onToggle); + connect(delegate, &ProjectItemDelegate::checkboxClicked, this, &ResourcePage::onToggle); } ResourcePage::~ResourcePage() @@ -177,8 +181,11 @@ ModPlatform::IndexedPack::Ptr ResourcePage::getCurrentPack() const return m_model->data(m_ui->packView->currentIndex(), Qt::UserRole).value(); } -void ResourcePage::updateUi() +void ResourcePage::updateUi(const QModelIndex& index) { + if (index != m_ui->packView->currentIndex()) + return; + auto current_pack = getCurrentPack(); if (!current_pack) { m_ui->packDescription->setHtml({}); @@ -268,39 +275,48 @@ void ResourcePage::updateSelectionButton() } } -void ResourcePage::updateVersionList() +void ResourcePage::versionListUpdated(const QModelIndex& index) { - auto current_pack = getCurrentPack(); + if (index == m_ui->packView->currentIndex()) { + auto current_pack = getCurrentPack(); - m_ui->versionSelectionBox->blockSignals(true); - m_ui->versionSelectionBox->clear(); - m_ui->versionSelectionBox->blockSignals(false); + m_ui->versionSelectionBox->blockSignals(true); + m_ui->versionSelectionBox->clear(); + m_ui->versionSelectionBox->blockSignals(false); - if (current_pack) { - auto installedVersion = m_model->getInstalledPackVersion(current_pack); + if (current_pack) { + auto installedVersion = m_model->getInstalledPackVersion(current_pack); - for (int i = 0; i < current_pack->versions.size(); i++) { - auto& version = current_pack->versions[i]; - if (!m_model->checkVersionFilters(version)) - continue; + for (int i = 0; i < current_pack->versions.size(); i++) { + auto& version = current_pack->versions[i]; + if (!m_model->checkVersionFilters(version)) + continue; - auto versionText = version.version; - if (version.version_type.isValid()) { - versionText += QString(" [%1]").arg(version.version_type.toString()); + auto versionText = version.version; + if (version.version_type.isValid()) { + versionText += QString(" [%1]").arg(version.version_type.toString()); + } + if (version.fileId == installedVersion) { + versionText += tr(" [installed]", "Mod version select"); + } + + m_ui->versionSelectionBox->addItem(versionText, QVariant(i)); } - if (version.fileId == installedVersion) { - versionText += tr(" [installed]", "Mod version select"); - } - - m_ui->versionSelectionBox->addItem(versionText, QVariant(i)); } - } - if (m_ui->versionSelectionBox->count() == 0) { - m_ui->versionSelectionBox->addItem(tr("No valid version found."), QVariant(-1)); - m_ui->resourceSelectionButton->setText(tr("Cannot select invalid version :(")); - } + if (m_ui->versionSelectionBox->count() == 0) { + m_ui->versionSelectionBox->addItem(tr("No valid version found."), QVariant(-1)); + m_ui->resourceSelectionButton->setText(tr("Cannot select invalid version :(")); + } - updateSelectionButton(); + if (m_enableQueue.contains(index.row())) { + m_enableQueue.remove(index.row()); + onToggle(index); + } else + updateSelectionButton(); + } else if (m_enableQueue.contains(index.row())) { + m_enableQueue.remove(index.row()); + onToggle(index); + } } void ResourcePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev) @@ -318,16 +334,20 @@ void ResourcePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI request_load = true; } else { - updateVersionList(); + versionListUpdated(curr); } if (current_pack && !current_pack->extraDataLoaded) request_load = true; + // we are already requesting this + if (m_enableQueue.contains(curr.row())) + request_load = false; + if (request_load) m_model->loadEntry(curr); - updateUi(); + updateUi(curr); } void ResourcePage::onVersionSelectionChanged(int index) @@ -385,6 +405,41 @@ void ResourcePage::onResourceSelected() m_ui->packView->repaint(); } +void ResourcePage::onToggle(const QModelIndex& index) +{ + const bool is_selected = index == m_ui->packView->currentIndex(); + auto pack = m_model->data(index, Qt::UserRole).value(); + + if (pack->versionsLoaded) { + if (pack->isAnyVersionSelected()) + removeResourceFromDialog(pack->name); + else { + auto version = std::find_if(pack->versions.begin(), pack->versions.end(), [this](const ModPlatform::IndexedVersion& version) { + return m_model->checkVersionFilters(version); + }); + + if (version != pack->versions.end()) + addResourceToDialog(pack, *version); + } + + if (is_selected) + updateSelectionButton(); + + // force update + QVariant variant; + variant.setValue(pack); + m_model->setData(index, variant, Qt::UserRole); + } else { + // the model is just 1 dimensional so this is fine + m_enableQueue.insert(index.row()); + + // we can't be sure that this hasn't already been requested... + // but this does the job well enough and there's not much point preventing edgecases + if (!is_selected) + m_model->loadEntry(index); + } +} + void ResourcePage::openUrl(const QUrl& url) { // do not allow other url schemes for security reasons diff --git a/launcher/ui/pages/modplatform/ResourcePage.h b/launcher/ui/pages/modplatform/ResourcePage.h index 09c512df4..6a44dcf6d 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.h +++ b/launcher/ui/pages/modplatform/ResourcePage.h @@ -71,9 +71,9 @@ class ResourcePage : public QWidget, public BasePage { void addSortings(); public slots: - virtual void updateUi(); + virtual void updateUi(const QModelIndex& index); virtual void updateSelectionButton(); - virtual void updateVersionList(); + virtual void versionListUpdated(const QModelIndex& index); void addResourceToDialog(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&); void removeResourceFromDialog(const QString& pack_name); @@ -91,6 +91,7 @@ class ResourcePage : public QWidget, public BasePage { void onSelectionChanged(QModelIndex first, QModelIndex second); void onVersionSelectionChanged(int index); void onResourceSelected(); + void onToggle(const QModelIndex& index); // NOTE: Can't use [[nodiscard]] here because of https://bugreports.qt.io/browse/QTBUG-58628 on Qt 5.12 @@ -115,6 +116,8 @@ class ResourcePage : public QWidget, public BasePage { QTimer m_searchTimer; bool m_doNotJumpToMod = false; + + QSet m_enableQueue; }; } // namespace ResourceDownload diff --git a/launcher/ui/pages/modplatform/ShaderPackModel.cpp b/launcher/ui/pages/modplatform/ShaderPackModel.cpp index 8c913657a..efc6bfaf9 100644 --- a/launcher/ui/pages/modplatform/ShaderPackModel.cpp +++ b/launcher/ui/pages/modplatform/ShaderPackModel.cpp @@ -20,13 +20,13 @@ ResourceAPI::SearchArgs ShaderPackResourceModel::createSearchArguments() return { ModPlatform::ResourceType::SHADER_PACK, m_next_search_offset, m_search_term, sort }; } -ResourceAPI::VersionSearchArgs ShaderPackResourceModel::createVersionsArguments(QModelIndex& entry) +ResourceAPI::VersionSearchArgs ShaderPackResourceModel::createVersionsArguments(const QModelIndex& entry) { auto& pack = m_packs[entry.row()]; return { *pack }; } -ResourceAPI::ProjectInfoArgs ShaderPackResourceModel::createInfoArguments(QModelIndex& entry) +ResourceAPI::ProjectInfoArgs ShaderPackResourceModel::createInfoArguments(const QModelIndex& entry) { auto& pack = m_packs[entry.row()]; return { *pack }; diff --git a/launcher/ui/pages/modplatform/ShaderPackModel.h b/launcher/ui/pages/modplatform/ShaderPackModel.h index f3c695e9f..5bb9e58b1 100644 --- a/launcher/ui/pages/modplatform/ShaderPackModel.h +++ b/launcher/ui/pages/modplatform/ShaderPackModel.h @@ -31,8 +31,8 @@ class ShaderPackResourceModel : public ResourceModel { public slots: ResourceAPI::SearchArgs createSearchArguments() override; - ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) override; - ResourceAPI::ProjectInfoArgs createInfoArguments(QModelIndex&) override; + ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override; + ResourceAPI::ProjectInfoArgs createInfoArguments(const QModelIndex&) override; protected: const BaseInstance& m_base_instance; diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.cpp b/launcher/ui/pages/modplatform/ShaderPackPage.cpp index 08acf361a..ace07db0e 100644 --- a/launcher/ui/pages/modplatform/ShaderPackPage.cpp +++ b/launcher/ui/pages/modplatform/ShaderPackPage.cpp @@ -15,10 +15,7 @@ namespace ResourceDownload { -ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance) -{ - connect(m_ui->packView, &QListView::doubleClicked, this, &ShaderPackResourcePage::onResourceSelected); -} +ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance) {} /******** Callbacks to events in the UI (set up in the derived classes) ********/ diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.h b/launcher/ui/pages/modplatform/ShaderPackPage.h index 4b92c33dc..68fdf6699 100644 --- a/launcher/ui/pages/modplatform/ShaderPackPage.h +++ b/launcher/ui/pages/modplatform/ShaderPackPage.h @@ -25,7 +25,7 @@ class ShaderPackResourcePage : public ResourcePage { auto page = new T(dialog, instance); auto model = static_cast(page->getModel()); - connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::updateVersionList); + connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); return page; diff --git a/launcher/ui/pages/modplatform/TexturePackModel.cpp b/launcher/ui/pages/modplatform/TexturePackModel.cpp index cb4cafd41..d56f9334b 100644 --- a/launcher/ui/pages/modplatform/TexturePackModel.cpp +++ b/launcher/ui/pages/modplatform/TexturePackModel.cpp @@ -70,7 +70,7 @@ ResourceAPI::SearchArgs TexturePackResourceModel::createSearchArguments() return args; } -ResourceAPI::VersionSearchArgs TexturePackResourceModel::createVersionsArguments(QModelIndex& entry) +ResourceAPI::VersionSearchArgs TexturePackResourceModel::createVersionsArguments(const QModelIndex& entry) { auto args = ResourcePackResourceModel::createVersionsArguments(entry); if (!m_version_list->isLoaded()) { diff --git a/launcher/ui/pages/modplatform/TexturePackModel.h b/launcher/ui/pages/modplatform/TexturePackModel.h index 607a03be3..45b5734ee 100644 --- a/launcher/ui/pages/modplatform/TexturePackModel.h +++ b/launcher/ui/pages/modplatform/TexturePackModel.h @@ -18,7 +18,7 @@ class TexturePackResourceModel : public ResourcePackResourceModel { [[nodiscard]] inline ::Version maximumTexturePackVersion() const { return { "1.6" }; } ResourceAPI::SearchArgs createSearchArguments() override; - ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) override; + ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override; protected: Meta::VersionList::Ptr m_version_list; diff --git a/launcher/ui/pages/modplatform/TexturePackPage.h b/launcher/ui/pages/modplatform/TexturePackPage.h index 42aa921c5..393ccc21e 100644 --- a/launcher/ui/pages/modplatform/TexturePackPage.h +++ b/launcher/ui/pages/modplatform/TexturePackPage.h @@ -27,7 +27,7 @@ class TexturePackResourcePage : public ResourcePackResourcePage { auto page = new T(dialog, instance); auto model = static_cast(page->getModel()); - connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::updateVersionList); + connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); return page; @@ -39,10 +39,7 @@ class TexturePackResourcePage : public ResourcePackResourcePage { [[nodiscard]] inline QString resourceString() const override { return tr("texture pack"); } protected: - TexturePackResourcePage(TexturePackDownloadDialog* dialog, BaseInstance& instance) : ResourcePackResourcePage(dialog, instance) - { - connect(m_ui->packView, &QListView::doubleClicked, this, &TexturePackResourcePage::onResourceSelected); - } + TexturePackResourcePage(TexturePackDownloadDialog* dialog, BaseInstance& instance) : ResourcePackResourcePage(dialog, instance) {} }; } // namespace ResourceDownload diff --git a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp index ae4562be4..d2dc29dfd 100644 --- a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp @@ -122,7 +122,7 @@ ResourceAPI::SearchArgs FlameTexturePackModel::createSearchArguments() return args; } -ResourceAPI::VersionSearchArgs FlameTexturePackModel::createVersionsArguments(QModelIndex& entry) +ResourceAPI::VersionSearchArgs FlameTexturePackModel::createVersionsArguments(const QModelIndex& entry) { auto args = TexturePackResourceModel::createVersionsArguments(entry); diff --git a/launcher/ui/pages/modplatform/flame/FlameResourceModels.h b/launcher/ui/pages/modplatform/flame/FlameResourceModels.h index 458fd85d0..9b86a0944 100644 --- a/launcher/ui/pages/modplatform/flame/FlameResourceModels.h +++ b/launcher/ui/pages/modplatform/flame/FlameResourceModels.h @@ -69,7 +69,7 @@ class FlameTexturePackModel : public TexturePackResourceModel { void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; ResourceAPI::SearchArgs createSearchArguments() override; - ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) override; + ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override; auto documentToArray(QJsonDocument& obj) const -> QJsonArray override; }; diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index 141a5191b..b20a3e013 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -16,34 +16,20 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o QStyleOptionViewItem opt(option); initStyleOption(&opt, index); - auto rect = opt.rect; - const QStyle* style = opt.widget == nullptr ? QApplication::style() : opt.widget->style(); + auto rect = opt.rect; + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); if (option.state & QStyle::State_Selected) painter->setPen(opt.palette.highlightedText().color()); if (opt.features & QStyleOptionViewItem::HasCheckIndicator) { - // 5px will be the typical margin with 48px icon size - // we don't want the checkbox to be all over the place - rect.translate(5, 0); - - QStyleOptionViewItem checkboxOpt = opt; - - checkboxOpt.state &= ~QStyle::State_HasFocus; - - if (checkboxOpt.checkState == Qt::Checked) - checkboxOpt.state |= QStyle::State_On; - - QRect checkboxRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &checkboxOpt, opt.widget); - checkboxOpt.rect = - QRect(rect.x(), rect.y() + (rect.height() / 2 - checkboxRect.height() / 2), checkboxRect.width(), checkboxRect.height()); - + QStyleOptionViewItem checkboxOpt = makeCheckboxStyleOption(opt, style); style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &checkboxOpt, painter, opt.widget); - rect.setX(rect.x() + checkboxRect.width()); + rect.setX(checkboxOpt.rect.right()); } // The default icon size will be a square (and height is usually the lower value). @@ -141,3 +127,51 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o painter->restore(); } + +bool ProjectItemDelegate::editorEvent(QEvent* event, + QAbstractItemModel* model, + const QStyleOptionViewItem& option, + const QModelIndex& index) +{ + if (!(event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonDblClick)) + return false; + + auto mouseEvent = (QMouseEvent*)event; + + QStyleOptionViewItem opt(option); + initStyleOption(&opt, index); + + const QStyle* style = opt.widget == nullptr ? QApplication::style() : opt.widget->style(); + + const QStyleOptionViewItem checkboxOpt = makeCheckboxStyleOption(opt, style); + + if (!checkboxOpt.rect.contains(mouseEvent->x(), mouseEvent->y())) + return false; + + // swallow other events + // (prevents item being selected or double click action triggering) + if (event->type() != QEvent::MouseButtonRelease) + return true; + + emit checkboxClicked(index); + return true; +} + +QStyleOptionViewItem ProjectItemDelegate::makeCheckboxStyleOption(const QStyleOptionViewItem& opt, const QStyle* style) const +{ + QStyleOptionViewItem checkboxOpt = opt; + + checkboxOpt.state &= ~QStyle::State_HasFocus; + + if (checkboxOpt.checkState == Qt::Checked) + checkboxOpt.state |= QStyle::State_On; + + QRect checkboxRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &checkboxOpt, opt.widget); + // 5px is the typical top margin for image + // we don't want the checkboxes to be all over the place :) + checkboxOpt.rect = QRect(opt.rect.x() + 5, opt.rect.y() + (opt.rect.height() / 2 - checkboxRect.height() / 2), checkboxRect.width(), + checkboxRect.height()); + + return checkboxOpt; +} diff --git a/launcher/ui/widgets/ProjectItem.h b/launcher/ui/widgets/ProjectItem.h index 96e62af12..068358ade 100644 --- a/launcher/ui/widgets/ProjectItem.h +++ b/launcher/ui/widgets/ProjectItem.h @@ -6,7 +6,7 @@ enum UserDataTypes { TITLE = 257, // QString DESCRIPTION = 258, // QString - INSTALLED = 260 // bool + INSTALLED = 259 // bool }; /** This is an item delegate composed of: @@ -21,4 +21,12 @@ class ProjectItemDelegate final : public QStyledItemDelegate { ProjectItemDelegate(QWidget* parent); void paint(QPainter*, const QStyleOptionViewItem&, const QModelIndex&) const override; + + bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override; + + signals: + void checkboxClicked(const QModelIndex& index); + + private: + QStyleOptionViewItem makeCheckboxStyleOption(const QStyleOptionViewItem& opt, const QStyle* style) const; }; diff --git a/tests/ResourceModel_test.cpp b/tests/ResourceModel_test.cpp index b589758aa..30bb99fb8 100644 --- a/tests/ResourceModel_test.cpp +++ b/tests/ResourceModel_test.cpp @@ -43,8 +43,8 @@ class DummyResourceModel : public ResourceModel { [[nodiscard]] auto metaEntryBase() const -> QString override { return ""; } ResourceAPI::SearchArgs createSearchArguments() override { return {}; } - ResourceAPI::VersionSearchArgs createVersionsArguments(QModelIndex&) override { return {}; } - ResourceAPI::ProjectInfoArgs createInfoArguments(QModelIndex&) override { return {}; } + ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override { return {}; } + ResourceAPI::ProjectInfoArgs createInfoArguments(const QModelIndex&) override { return {}; } QJsonArray documentToArray(QJsonDocument& doc) const override { return doc.object().value("hits").toArray(); } From c6066fe6ecff2b2b374834894a7ab531ffa3b249 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 01:41:56 +0000 Subject: [PATCH 05/15] Add warning dialog if there are no versions available Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourcePage.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 407684f8b..1f2261e2c 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -418,7 +418,14 @@ void ResourcePage::onToggle(const QModelIndex& index) return m_model->checkVersionFilters(version); }); - if (version != pack->versions.end()) + if (version == pack->versions.end()) { + auto errorMessage = new QMessageBox( + QMessageBox::Warning, tr("No versions available"), + tr("No versions for '%1' are available.\nThe author likely blocked third-party launchers.").arg(pack->name), + QMessageBox::Ok, this); + + errorMessage->open(); + } else addResourceToDialog(pack, *version); } From a5c62e657aa95b50992b63d590e66d1a0d685c7c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 01:43:43 +0000 Subject: [PATCH 06/15] Snek case Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourcePage.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 1f2261e2c..4e5de4933 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -407,7 +407,7 @@ void ResourcePage::onResourceSelected() void ResourcePage::onToggle(const QModelIndex& index) { - const bool is_selected = index == m_ui->packView->currentIndex(); + const bool isSelected = index == m_ui->packView->currentIndex(); auto pack = m_model->data(index, Qt::UserRole).value(); if (pack->versionsLoaded) { @@ -429,7 +429,7 @@ void ResourcePage::onToggle(const QModelIndex& index) addResourceToDialog(pack, *version); } - if (is_selected) + if (isSelected) updateSelectionButton(); // force update @@ -442,7 +442,7 @@ void ResourcePage::onToggle(const QModelIndex& index) // we can't be sure that this hasn't already been requested... // but this does the job well enough and there's not much point preventing edgecases - if (!is_selected) + if (!isSelected) m_model->loadEntry(index); } } From 75321722339ff6df854131623774a8e7420b6e76 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 10:31:55 +0000 Subject: [PATCH 07/15] Clear enableQueue on model reset Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ModPage.h | 1 + launcher/ui/pages/modplatform/ResourcePackPage.h | 1 + launcher/ui/pages/modplatform/ResourcePage.cpp | 5 +++++ launcher/ui/pages/modplatform/ResourcePage.h | 2 ++ launcher/ui/pages/modplatform/ShaderPackPage.h | 1 + launcher/ui/pages/modplatform/TexturePackPage.h | 1 + 6 files changed, 11 insertions(+) diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index 397b77d94..47fe21e0f 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -37,6 +37,7 @@ class ModPage : public ResourcePage { connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); + connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset); return page; } diff --git a/launcher/ui/pages/modplatform/ResourcePackPage.h b/launcher/ui/pages/modplatform/ResourcePackPage.h index 3f925fd23..8d967f73a 100644 --- a/launcher/ui/pages/modplatform/ResourcePackPage.h +++ b/launcher/ui/pages/modplatform/ResourcePackPage.h @@ -27,6 +27,7 @@ class ResourcePackResourcePage : public ResourcePage { connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); + connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset); return page; } diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 4e5de4933..5acfec5da 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -374,6 +374,11 @@ void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, m_model->addPack(pack, ver, base_model, is_indexed); } +void ResourcePage::modelReset() +{ + m_enableQueue.clear(); +} + void ResourcePage::removeResourceFromPage(const QString& name) { m_model->removePack(name); diff --git a/launcher/ui/pages/modplatform/ResourcePage.h b/launcher/ui/pages/modplatform/ResourcePage.h index 6a44dcf6d..23309333b 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.h +++ b/launcher/ui/pages/modplatform/ResourcePage.h @@ -80,6 +80,8 @@ class ResourcePage : public QWidget, public BasePage { virtual void removeResourceFromPage(const QString& name); virtual void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, std::shared_ptr); + virtual void modelReset(); + QList selectedPacks() { return m_model->selectedPacks(); } bool hasSelectedPacks() { return !(m_model->selectedPacks().isEmpty()); } diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.h b/launcher/ui/pages/modplatform/ShaderPackPage.h index 68fdf6699..d436e218a 100644 --- a/launcher/ui/pages/modplatform/ShaderPackPage.h +++ b/launcher/ui/pages/modplatform/ShaderPackPage.h @@ -27,6 +27,7 @@ class ShaderPackResourcePage : public ResourcePage { connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); + connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset); return page; } diff --git a/launcher/ui/pages/modplatform/TexturePackPage.h b/launcher/ui/pages/modplatform/TexturePackPage.h index 393ccc21e..27fd8bcfc 100644 --- a/launcher/ui/pages/modplatform/TexturePackPage.h +++ b/launcher/ui/pages/modplatform/TexturePackPage.h @@ -29,6 +29,7 @@ class TexturePackResourcePage : public ResourcePackResourcePage { connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated); connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi); + connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset); return page; } From 0f3ac57fddc7a364e7313759cc3784ce01fa4818 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 10:42:38 +0000 Subject: [PATCH 08/15] Trigger onToggle instead of onResourceSelected when pressing enter Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourcePage.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 5acfec5da..07d296d48 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -132,13 +132,9 @@ auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool m_searchTimer.start(350); } } else if (watched == m_ui->packView) { + // stop the event from going to the confirm button if (keyEvent->key() == Qt::Key_Return) { - onResourceSelected(); - - // To have the 'select mod' button outlined instead of the 'review and confirm' one - m_ui->resourceSelectionButton->setFocus(Qt::FocusReason::ShortcutFocusReason); - m_ui->packView->setFocus(Qt::FocusReason::NoFocusReason); - + onToggle(m_ui->packView->currentIndex()); keyEvent->accept(); return true; } From 6c44a3f6dfb629682a3741336d1a83faa973250c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 10:46:32 +0000 Subject: [PATCH 09/15] onToggle -> onResourceToggle Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourcePage.cpp | 12 ++++++------ launcher/ui/pages/modplatform/ResourcePage.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 07d296d48..153392075 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -84,8 +84,8 @@ ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& base_in connect(m_ui->packDescription, &QTextBrowser::anchorClicked, this, &ResourcePage::openUrl); - connect(m_ui->packView, &QListView::doubleClicked, this, &ResourcePage::onToggle); - connect(delegate, &ProjectItemDelegate::checkboxClicked, this, &ResourcePage::onToggle); + connect(m_ui->packView, &QListView::doubleClicked, this, &ResourcePage::onResourceToggle); + connect(delegate, &ProjectItemDelegate::checkboxClicked, this, &ResourcePage::onResourceToggle); } ResourcePage::~ResourcePage() @@ -134,7 +134,7 @@ auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool } else if (watched == m_ui->packView) { // stop the event from going to the confirm button if (keyEvent->key() == Qt::Key_Return) { - onToggle(m_ui->packView->currentIndex()); + onResourceToggle(m_ui->packView->currentIndex()); keyEvent->accept(); return true; } @@ -306,12 +306,12 @@ void ResourcePage::versionListUpdated(const QModelIndex& index) if (m_enableQueue.contains(index.row())) { m_enableQueue.remove(index.row()); - onToggle(index); + onResourceToggle(index); } else updateSelectionButton(); } else if (m_enableQueue.contains(index.row())) { m_enableQueue.remove(index.row()); - onToggle(index); + onResourceToggle(index); } } @@ -406,7 +406,7 @@ void ResourcePage::onResourceSelected() m_ui->packView->repaint(); } -void ResourcePage::onToggle(const QModelIndex& index) +void ResourcePage::onResourceToggle(const QModelIndex& index) { const bool isSelected = index == m_ui->packView->currentIndex(); auto pack = m_model->data(index, Qt::UserRole).value(); diff --git a/launcher/ui/pages/modplatform/ResourcePage.h b/launcher/ui/pages/modplatform/ResourcePage.h index 23309333b..055db441a 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.h +++ b/launcher/ui/pages/modplatform/ResourcePage.h @@ -93,7 +93,7 @@ class ResourcePage : public QWidget, public BasePage { void onSelectionChanged(QModelIndex first, QModelIndex second); void onVersionSelectionChanged(int index); void onResourceSelected(); - void onToggle(const QModelIndex& index); + void onResourceToggle(const QModelIndex& index); // NOTE: Can't use [[nodiscard]] here because of https://bugreports.qt.io/browse/QTBUG-58628 on Qt 5.12 From 6dc16c48a2b1c6056fa06762f5d4a34602adaab5 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 10:56:07 +0000 Subject: [PATCH 10/15] Append [installed] to installed mods Signed-off-by: TheKodeToad --- launcher/ui/widgets/ProjectItem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index b20a3e013..d1634591f 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -68,6 +68,9 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o { // Title painting auto title = index.data(UserDataTypes::TITLE).toString(); + if (index.data(UserDataTypes::INSTALLED).toBool()) + title += " [installed]"; + painter->save(); auto font = opt.font; From 9f768f76bbf309a80685f5870c5d881cfb7900df Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 11:00:51 +0000 Subject: [PATCH 11/15] Translate installed indicator Signed-off-by: TheKodeToad --- launcher/ui/widgets/ProjectItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index d1634591f..1224b853b 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -69,7 +69,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o auto title = index.data(UserDataTypes::TITLE).toString(); if (index.data(UserDataTypes::INSTALLED).toBool()) - title += " [installed]"; + title = tr("%1 [installed]").arg(title); painter->save(); From 5832fb8b95b8853c66ddea114e3b9f3a888e287b Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 11:09:25 +0000 Subject: [PATCH 12/15] Implement middle click Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourcePage.cpp | 8 ++++++++ launcher/ui/widgets/ProjectItem.cpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 153392075..ea8e8d5e9 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -81,6 +81,7 @@ ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& base_in auto delegate = new ProjectItemDelegate(this); m_ui->packView->setItemDelegate(delegate); m_ui->packView->installEventFilter(this); + m_ui->packView->viewport()->installEventFilter(this); connect(m_ui->packDescription, &QTextBrowser::anchorClicked, this, &ResourcePage::openUrl); @@ -139,6 +140,13 @@ auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool return true; } } + } else if (watched == m_ui->packView->viewport() && event->type() == QEvent::MouseButtonPress) { + auto* mouseEvent = static_cast(event); + + if (mouseEvent->button() == Qt::MiddleButton) { + onResourceToggle(m_ui->packView->indexAt(mouseEvent->pos())); + return true; + } } return QWidget::eventFilter(watched, event); diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index 1224b853b..fee743c23 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -142,6 +142,9 @@ bool ProjectItemDelegate::editorEvent(QEvent* event, auto mouseEvent = (QMouseEvent*)event; + if (mouseEvent->button() != Qt::LeftButton) + return false; + QStyleOptionViewItem opt(option); initStyleOption(&opt, index); From e89f96e9e9087c6b49cceb8e7e710d85ca46d68d Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 11:48:31 +0000 Subject: [PATCH 13/15] Hack for broken windowsvista Signed-off-by: TheKodeToad --- launcher/ui/widgets/ProjectItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index fee743c23..c11939b00 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -22,7 +22,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); - if (option.state & QStyle::State_Selected) + if (option.state & QStyle::State_Selected && style->objectName() != "windowsvista") painter->setPen(opt.palette.highlightedText().color()); if (opt.features & QStyleOptionViewItem::HasCheckIndicator) { From a108b5e9eb05ee0072fc02d2ab0ef482025a2820 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 12:35:24 +0000 Subject: [PATCH 14/15] Correctly set objectName for HintOverrideProxyStyle Signed-off-by: TheKodeToad --- launcher/ui/themes/HintOverrideProxyStyle.cpp | 4 ++++ launcher/ui/themes/HintOverrideProxyStyle.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/launcher/ui/themes/HintOverrideProxyStyle.cpp b/launcher/ui/themes/HintOverrideProxyStyle.cpp index 80e821349..f31969fce 100644 --- a/launcher/ui/themes/HintOverrideProxyStyle.cpp +++ b/launcher/ui/themes/HintOverrideProxyStyle.cpp @@ -18,6 +18,10 @@ #include "HintOverrideProxyStyle.h" +HintOverrideProxyStyle::HintOverrideProxyStyle(QStyle* style) : QProxyStyle(style) { + setObjectName(style->objectName()); +} + int HintOverrideProxyStyle::styleHint(QStyle::StyleHint hint, const QStyleOption* option, const QWidget* widget, diff --git a/launcher/ui/themes/HintOverrideProxyStyle.h b/launcher/ui/themes/HintOverrideProxyStyle.h index 09b296018..e9c489d09 100644 --- a/launcher/ui/themes/HintOverrideProxyStyle.h +++ b/launcher/ui/themes/HintOverrideProxyStyle.h @@ -25,7 +25,7 @@ class HintOverrideProxyStyle : public QProxyStyle { Q_OBJECT public: - HintOverrideProxyStyle(QStyle* style) : QProxyStyle(style) {} + explicit HintOverrideProxyStyle(QStyle* style); int styleHint(QStyle::StyleHint hint, const QStyleOption* option = nullptr, From 947ca679520d4656a9002aaed1ac63acfbc59f42 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 19 Mar 2025 13:32:14 +0000 Subject: [PATCH 15/15] Fix windows 9x and possibly other styles Signed-off-by: TheKodeToad --- launcher/ui/widgets/ProjectItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index c11939b00..950c5fe0a 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -172,6 +172,8 @@ QStyleOptionViewItem ProjectItemDelegate::makeCheckboxStyleOption(const QStyleOp if (checkboxOpt.checkState == Qt::Checked) checkboxOpt.state |= QStyle::State_On; + else + checkboxOpt.state |= QStyle::State_Off; QRect checkboxRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &checkboxOpt, opt.widget); // 5px is the typical top margin for image