Updated filters

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2023-10-18 09:00:45 +03:00
parent b54376062e
commit fea4c4eba8
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
10 changed files with 311 additions and 178 deletions

View File

@ -23,6 +23,7 @@
#include <memory> #include <memory>
#include "Json.h" #include "Json.h"
#include "QObjectPtr.h" #include "QObjectPtr.h"
#include "minecraft/PackProfile.h"
#include "minecraft/mod/MetadataHandler.h" #include "minecraft/mod/MetadataHandler.h"
#include "modplatform/ModIndex.h" #include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h" #include "modplatform/ResourceAPI.h"

View File

@ -94,10 +94,9 @@ auto ProviderCapabilities::hash(ResourceProvider p, QIODevice* device, QString t
{ {
QCryptographicHash::Algorithm algo = QCryptographicHash::Sha1; QCryptographicHash::Algorithm algo = QCryptographicHash::Sha1;
switch (p) { switch (p) {
case ResourceProvider::MODRINTH: { case ResourceProvider::MODRINTH:
algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Sha512; algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Sha512;
break; break;
}
case ResourceProvider::FLAME: case ResourceProvider::FLAME:
algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Md5; algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Md5;
break; break;

View File

@ -27,6 +27,7 @@
#include "Application.h" #include "Application.h"
#include "ResourceDownloadTask.h" #include "ResourceDownloadTask.h"
#include "minecraft/PackProfile.h"
#include "minecraft/mod/ModFolderModel.h" #include "minecraft/mod/ModFolderModel.h"
#include "minecraft/mod/ResourcePackFolderModel.h" #include "minecraft/mod/ResourcePackFolderModel.h"
#include "minecraft/mod/ShaderPackFolderModel.h" #include "minecraft/mod/ShaderPackFolderModel.h"

View File

@ -25,15 +25,18 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
Q_ASSERT(m_filter); Q_ASSERT(m_filter);
std::optional<std::list<Version>> versions{}; std::optional<std::list<Version>> versions{};
auto loaders = profile->getSupportedModLoaders();
{ // Version filter { // Version filter
if (!m_filter->versions.empty()) if (!m_filter->versions.empty())
versions = m_filter->versions; versions = m_filter->versions;
if (m_filter->loaders)
loaders = m_filter->loaders;
} }
auto sort = getCurrentSortingMethodByIndex(); auto sort = getCurrentSortingMethodByIndex();
return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, profile->getSupportedModLoaders(), versions }; return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, loaders, versions };
} }
ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry) ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry)
@ -45,10 +48,13 @@ ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& en
Q_ASSERT(m_filter); Q_ASSERT(m_filter);
std::optional<std::list<Version>> versions{}; std::optional<std::list<Version>> versions{};
auto loaders = profile->getSupportedModLoaders();
if (!m_filter->versions.empty()) if (!m_filter->versions.empty())
versions = m_filter->versions; versions = m_filter->versions;
if (m_filter->loaders)
loaders = m_filter->loaders;
return { pack, versions, profile->getSupportedModLoaders() }; return { pack, versions, loaders };
} }
ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(QModelIndex& entry) ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(QModelIndex& entry)

View File

@ -71,7 +71,6 @@ void ModPage::setFilterWidget(unique_qobject_ptr<ModFilterWidget>& widget)
m_ui->gridLayout_3->addWidget(m_filter_widget.get(), 0, 0, 1, m_ui->gridLayout_3->columnCount()); m_ui->gridLayout_3->addWidget(m_filter_widget.get(), 0, 0, 1, m_ui->gridLayout_3->columnCount());
m_filter_widget->setInstance(&static_cast<MinecraftInstance&>(m_base_instance));
m_filter = m_filter_widget->getFilter(); m_filter = m_filter_widget->getFilter();
connect(m_filter_widget.get(), &ModFilterWidget::filterChanged, this, connect(m_filter_widget.get(), &ModFilterWidget::filterChanged, this,
@ -89,13 +88,14 @@ void ModPage::filterMods()
void ModPage::triggerSearch() void ModPage::triggerSearch()
{ {
auto changed = m_filter_widget->changed();
m_filter = m_filter_widget->getFilter(); m_filter = m_filter_widget->getFilter();
m_ui->packView->clearSelection(); m_ui->packView->clearSelection();
m_ui->packDescription->clear(); m_ui->packDescription->clear();
m_ui->versionSelectionBox->clear(); m_ui->versionSelectionBox->clear();
updateSelectionButton(); updateSelectionButton();
static_cast<ModModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt(), m_filter_widget->changed()); static_cast<ModModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt(), changed);
m_fetch_progress.watch(m_model->activeSearchJob().get()); m_fetch_progress.watch(m_model->activeSearchJob().get());
} }
@ -116,6 +116,9 @@ void ModPage::updateVersionList()
auto packProfile = (dynamic_cast<MinecraftInstance&>(m_base_instance)).getPackProfile(); auto packProfile = (dynamic_cast<MinecraftInstance&>(m_base_instance)).getPackProfile();
QString mcVersion = packProfile->getComponentVersion("net.minecraft"); QString mcVersion = packProfile->getComponentVersion("net.minecraft");
auto loaders = packProfile->getSupportedModLoaders();
if (m_filter->loaders)
loaders = m_filter->loaders;
auto current_pack = getCurrentPack(); auto current_pack = getCurrentPack();
if (!current_pack) if (!current_pack)
@ -124,7 +127,7 @@ void ModPage::updateVersionList()
auto version = current_pack->versions[i]; auto version = current_pack->versions[i];
bool valid = false; bool valid = false;
for (auto& mcVer : m_filter->versions) { for (auto& mcVer : m_filter->versions) {
if (validateVersion(version, mcVer.toString(), packProfile->getSupportedModLoaders())) { if (validateVersion(version, mcVer.toString(), loaders)) {
valid = true; valid = true;
break; break;
} }

View File

@ -31,8 +31,7 @@ class ModPage : public ResourcePage {
auto page = new T(dialog, instance); auto page = new T(dialog, instance);
auto model = static_cast<ModModel*>(page->getModel()); auto model = static_cast<ModModel*>(page->getModel());
auto filter_widget = auto filter_widget = ModFilterWidget::create(&static_cast<MinecraftInstance&>(instance), page);
ModFilterWidget::create(static_cast<MinecraftInstance&>(instance).getPackProfile()->getComponentVersion("net.minecraft"), page);
page->setFilterWidget(filter_widget); page->setFilterWidget(filter_widget);
model->setFilter(page->getFilter()); model->setFilter(page->getFilter());

View File

@ -6,6 +6,7 @@
#include "Json.h" #include "Json.h"
#include "minecraft/PackProfile.h"
#include "modplatform/flame/FlameAPI.h" #include "modplatform/flame/FlameAPI.h"
#include "modplatform/flame/FlameModIndex.h" #include "modplatform/flame/FlameModIndex.h"

View File

@ -1,13 +1,70 @@
#include "ModFilterWidget.h" #include "ModFilterWidget.h"
#include <qcheckbox.h>
#include <qcombobox.h>
#include "BaseVersionList.h"
#include "meta/Index.h"
#include "modplatform/ModIndex.h"
#include "ui_ModFilterWidget.h" #include "ui_ModFilterWidget.h"
#include "Application.h" #include "Application.h"
#include "minecraft/PackProfile.h"
unique_qobject_ptr<ModFilterWidget> ModFilterWidget::create(Version default_version, QWidget* parent) unique_qobject_ptr<ModFilterWidget> ModFilterWidget::create(MinecraftInstance* instance, QWidget* parent)
{ {
auto filter_widget = new ModFilterWidget(default_version, parent); return unique_qobject_ptr<ModFilterWidget>(new ModFilterWidget(instance, parent));
}
if (!filter_widget->versionList()->isLoaded()) { ModFilterWidget::ModFilterWidget(MinecraftInstance* instance, QWidget* parent)
: QTabWidget(parent), ui(new Ui::ModFilterWidget), m_instance(instance), m_filter(new Filter())
{
ui->setupUi(this);
m_versions_proxy = new VersionProxyModel(this);
ui->versionsCb->setModel(m_versions_proxy);
m_versions_proxy->setFilter(BaseVersionList::TypeRole, new RegexpFilter("(release)", false));
ui->versionsCb->setStyleSheet("combobox-popup: 0;");
connect(ui->snapshotsCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onIncludeSnapshotsChanged);
connect(ui->versionsCb, &QComboBox::currentIndexChanged, this, &ModFilterWidget::onVersionFilterChanged);
connect(ui->neoForgeCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onLoadersFilterChanged);
connect(ui->forgeCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onLoadersFilterChanged);
connect(ui->fabricCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onLoadersFilterChanged);
connect(ui->quiltCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onLoadersFilterChanged);
connect(ui->liteLoaderCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onLoadersFilterChanged);
connect(ui->cauldronCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onLoadersFilterChanged);
ui->liteLoaderCb->hide();
ui->cauldronCb->hide();
connect(ui->serverEnv, &QCheckBox::stateChanged, this, &ModFilterWidget::onSideFilterChanged);
connect(ui->clientEnv, &QCheckBox::stateChanged, this, &ModFilterWidget::onSideFilterChanged);
connect(ui->hide_installed, &QCheckBox::stateChanged, this, &ModFilterWidget::onHideInstalledFilterChanged);
setHidden(true);
loadVersionList();
prepareBasicFilter();
}
auto ModFilterWidget::getFilter() -> std::shared_ptr<Filter>
{
m_filter_changed = false;
emit filterUnchanged();
return m_filter;
}
ModFilterWidget::~ModFilterWidget()
{
delete ui;
}
void ModFilterWidget::loadVersionList()
{
m_version_list = APPLICATION->metadataIndex()->get("net.minecraft");
if (!m_version_list->isLoaded()) {
QEventLoop load_version_list_loop; QEventLoop load_version_list_loop;
QTimer time_limit_for_list_load; QTimer time_limit_for_list_load;
@ -16,10 +73,12 @@ unique_qobject_ptr<ModFilterWidget> ModFilterWidget::create(Version default_vers
time_limit_for_list_load.callOnTimeout(&load_version_list_loop, &QEventLoop::quit); time_limit_for_list_load.callOnTimeout(&load_version_list_loop, &QEventLoop::quit);
time_limit_for_list_load.start(4000); time_limit_for_list_load.start(4000);
auto task = filter_widget->versionList()->getLoadTask(); auto task = m_version_list->getLoadTask();
connect(task.get(), &Task::failed, connect(task.get(), &Task::failed, [this] {
[filter_widget] { filter_widget->disableVersionButton(VersionButtonID::Major, tr("failed to get version index")); }); ui->versionsCb->setEnabled(false);
ui->snapshotsCb->setEnabled(false);
});
connect(task.get(), &Task::finished, &load_version_list_loop, &QEventLoop::quit); connect(task.get(), &Task::finished, &load_version_list_loop, &QEventLoop::quit);
if (!task->isRunning()) if (!task->isRunning())
@ -29,128 +88,93 @@ unique_qobject_ptr<ModFilterWidget> ModFilterWidget::create(Version default_vers
if (time_limit_for_list_load.isActive()) if (time_limit_for_list_load.isActive())
time_limit_for_list_load.stop(); time_limit_for_list_load.stop();
} }
m_versions_proxy->setSourceModel(m_version_list.get());
return unique_qobject_ptr<ModFilterWidget>(filter_widget);
} }
ModFilterWidget::ModFilterWidget(Version def, QWidget* parent) : QTabWidget(parent), m_filter(new Filter()), ui(new Ui::ModFilterWidget) void ModFilterWidget::prepareBasicFilter()
{ {
ui->setupUi(this); m_filter->hideInstalled = false;
m_filter->side = ""; // or "both"t
m_mcVersion_buttons.addButton(ui->strictVersionButton, VersionButtonID::Strict); auto loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
ui->strictVersionButton->click(); ui->neoForgeCb->setChecked(loaders & ModPlatform::NeoForge);
m_mcVersion_buttons.addButton(ui->majorVersionButton, VersionButtonID::Major); ui->forgeCb->setChecked(loaders & ModPlatform::Forge);
m_mcVersion_buttons.addButton(ui->allVersionsButton, VersionButtonID::All); ui->fabricCb->setChecked(loaders & ModPlatform::Fabric);
// m_mcVersion_buttons.addButton(ui->betweenVersionsButton, VersionButtonID::Between); ui->quiltCb->setChecked(loaders & ModPlatform::Quilt);
ui->liteLoaderCb->setChecked(loaders & ModPlatform::LiteLoader);
connect(&m_mcVersion_buttons, SIGNAL(idClicked(int)), this, SLOT(onVersionFilterChanged(int))); ui->cauldronCb->setChecked(loaders & ModPlatform::Cauldron);
m_filter->loaders = loaders;
m_filter->versions.push_front(def); auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
m_filter->versions.push_front(Version{ def });
m_version_list = APPLICATION->metadataIndex()->get("net.minecraft"); m_versions_proxy->setCurrentVersion(def);
setHidden(true); ui->versionsCb->setCurrentIndex(m_versions_proxy->getVersion(def).row());
} }
void ModFilterWidget::setInstance(MinecraftInstance* instance) void ModFilterWidget::onIncludeSnapshotsChanged()
{ {
m_instance = instance; QString filter = "(release)";
if (ui->snapshotsCb->isChecked())
ui->strictVersionButton->setText(tr("Strict match (= %1)").arg(mcVersionStr())); filter += "|(snapshot)";
m_versions_proxy->setFilter(BaseVersionList::TypeRole, new RegexpFilter(filter, false));
// we can't do this for snapshots sadly
if (mcVersionStr().contains('.')) {
auto mcVersionSplit = mcVersionStr().split(".");
ui->majorVersionButton->setText(tr("Major version match (= %1.%2.x)").arg(mcVersionSplit[0], mcVersionSplit[1]));
} else {
ui->majorVersionButton->setText(tr("Major version match (unsupported)"));
disableVersionButton(Major);
}
ui->allVersionsButton->setText(tr("Any version"));
// ui->betweenVersionsButton->setText(
// tr("Between two versions"));
} }
auto ModFilterWidget::getFilter() -> std::shared_ptr<Filter> void ModFilterWidget::onVersionFilterChanged()
{ {
m_last_version_id = m_version_id; auto version = ui->versionsCb->currentData(BaseVersionList::VersionIdRole).toString();
emit filterUnchanged();
return m_filter;
}
void ModFilterWidget::disableVersionButton(VersionButtonID id, QString reason)
{
QAbstractButton* btn = nullptr;
switch (id) {
case (VersionButtonID::Strict):
btn = ui->strictVersionButton;
break;
case (VersionButtonID::Major):
btn = ui->majorVersionButton;
break;
case (VersionButtonID::All):
btn = ui->allVersionsButton;
break;
case (VersionButtonID::Between):
default:
break;
}
if (btn) {
btn->setEnabled(false);
if (!reason.isEmpty())
btn->setText(btn->text() + QString(" (%1)").arg(reason));
}
}
void ModFilterWidget::onVersionFilterChanged(int id)
{
// ui->lowerVersionComboBox->setEnabled(id == VersionButtonID::Between);
// ui->upperVersionComboBox->setEnabled(id == VersionButtonID::Between);
int index = 1;
auto cast_id = (VersionButtonID)id;
if (cast_id != m_version_id) {
m_version_id = cast_id;
} else {
return;
}
m_filter->versions.clear(); m_filter->versions.clear();
m_filter->versions.push_front(version);
m_filter_changed = true;
emit filterChanged();
}
switch (cast_id) { void ModFilterWidget::onLoadersFilterChanged()
case (VersionButtonID::Strict): {
m_filter->versions.push_front(mcVersion()); ModPlatform::ModLoaderTypes loaders;
break; if (ui->neoForgeCb->isChecked())
case (VersionButtonID::Major): { loaders |= ModPlatform::NeoForge;
auto versionSplit = mcVersionStr().split("."); if (ui->forgeCb->isChecked())
loaders |= ModPlatform::Forge;
auto major_version = QString("%1.%2").arg(versionSplit[0], versionSplit[1]); if (ui->fabricCb->isChecked())
QString version_str = major_version; loaders |= ModPlatform::Fabric;
if (ui->quiltCb->isChecked())
while (m_version_list->hasVersion(version_str)) { loaders |= ModPlatform::Quilt;
m_filter->versions.emplace_back(version_str); if (ui->cauldronCb->isChecked())
version_str = QString("%1.%2").arg(major_version, QString::number(index++)); loaders |= ModPlatform::Cauldron;
} if (ui->liteLoaderCb->isChecked())
loaders |= ModPlatform::LiteLoader;
break; m_filter_changed = loaders != m_filter->loaders;
} m_filter->loaders = loaders;
case (VersionButtonID::All): if (m_filter_changed)
// Empty list to avoid enumerating all versions :P
break;
case (VersionButtonID::Between):
// TODO
break;
}
if (changed())
emit filterChanged(); emit filterChanged();
else else
emit filterUnchanged(); emit filterUnchanged();
} }
ModFilterWidget::~ModFilterWidget() void ModFilterWidget::onSideFilterChanged()
{ {
delete ui; QString side;
if (ui->serverEnv->isChecked())
side = "server";
if (ui->clientEnv->isChecked()) {
if (side.isEmpty())
side = "client";
else
side = ""; // or both
}
m_filter_changed = side != m_filter->side;
m_filter->side = side;
if (m_filter_changed)
emit filterChanged();
else
emit filterUnchanged();
}
void ModFilterWidget::onHideInstalledFilterChanged()
{
auto hide = ui->hide_installed->isChecked();
m_filter_changed = hide != m_filter->hideInstalled;
m_filter->hideInstalled = hide;
if (m_filter_changed)
emit filterChanged();
else
emit filterUnchanged();
} }

View File

@ -5,11 +5,11 @@
#include "Version.h" #include "Version.h"
#include "meta/Index.h" #include "VersionProxyModel.h"
#include "meta/VersionList.h" #include "meta/VersionList.h"
#include "minecraft/MinecraftInstance.h" #include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h" #include "modplatform/ModIndex.h"
class MinecraftInstance; class MinecraftInstance;
@ -20,42 +20,37 @@ class ModFilterWidget;
class ModFilterWidget : public QTabWidget { class ModFilterWidget : public QTabWidget {
Q_OBJECT Q_OBJECT
public: public:
enum VersionButtonID { Strict = 0, Major = 1, All = 2, Between = 3 };
struct Filter { struct Filter {
std::list<Version> versions; std::list<Version> versions;
ModPlatform::ModLoaderTypes loaders;
QString side;
bool hideInstalled;
bool operator==(const Filter& other) const { return versions == other.versions; } bool operator==(const Filter& other) const
{
return hideInstalled == other.hideInstalled && side == other.side && loaders == other.loaders && versions == other.versions;
}
bool operator!=(const Filter& other) const { return !(*this == other); } bool operator!=(const Filter& other) const { return !(*this == other); }
}; };
std::shared_ptr<Filter> m_filter; static unique_qobject_ptr<ModFilterWidget> create(MinecraftInstance* instance, QWidget* parent = nullptr);
virtual ~ModFilterWidget();
public:
static unique_qobject_ptr<ModFilterWidget> create(Version default_version, QWidget* parent = nullptr);
~ModFilterWidget();
void setInstance(MinecraftInstance* instance);
/// By default all buttons are enabled
void disableVersionButton(VersionButtonID, QString reason = {});
auto getFilter() -> std::shared_ptr<Filter>; auto getFilter() -> std::shared_ptr<Filter>;
auto changed() const -> bool { return m_last_version_id != m_version_id; } auto changed() const -> bool { return m_filter_changed; }
Meta::VersionList::Ptr versionList() { return m_version_list; }
private: private:
ModFilterWidget(Version def, QWidget* parent = nullptr); ModFilterWidget(MinecraftInstance* instance, QWidget* parent = nullptr);
inline auto mcVersionStr() const -> QString void loadVersionList();
{ void prepareBasicFilter();
return m_instance ? m_instance->getPackProfile()->getComponentVersion("net.minecraft") : "";
}
inline auto mcVersion() const -> Version { return { mcVersionStr() }; }
private slots: private slots:
void onVersionFilterChanged(int id); void onVersionFilterChanged();
void onLoadersFilterChanged();
void onSideFilterChanged();
void onHideInstalledFilterChanged();
void onIncludeSnapshotsChanged();
public: public:
signals: signals:
@ -66,13 +61,9 @@ class ModFilterWidget : public QTabWidget {
Ui::ModFilterWidget* ui; Ui::ModFilterWidget* ui;
MinecraftInstance* m_instance = nullptr; MinecraftInstance* m_instance = nullptr;
std::shared_ptr<Filter> m_filter;
/* Version stuff */ bool m_filter_changed = false;
QButtonGroup m_mcVersion_buttons;
Meta::VersionList::Ptr m_version_list; Meta::VersionList::Ptr m_version_list;
VersionProxyModel* m_versions_proxy = nullptr;
/* Used to tell if the filter was changed since the last getFilter() call */
VersionButtonID m_last_version_id = VersionButtonID::Strict;
VersionButtonID m_version_id = VersionButtonID::Strict;
}; };

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>400</width>
<height>300</height> <height>127</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -16,35 +16,143 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="VersionPage"> <widget class="QWidget" name="VersionPage">
<attribute name="title"> <attribute name="title">
<string>Minecraft versions</string> <string>Minecraft versions</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="2" column="0">
<widget class="QRadioButton" name="allVersionsButton">
<property name="text">
<string notr="true">allVersions</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="strictVersionButton">
<property name="text">
<string notr="true">strictVersion</string>
</property>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QRadioButton" name="majorVersionButton"> <widget class="QComboBox" name="versionsCb">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxVisibleItems">
<number>5</number>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="snapshotsCb">
<property name="text"> <property name="text">
<string notr="true">majorVersion</string> <string>Include Snapshots</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget>
<widget class="QWidget" name="LoadersPage">
<attribute name="title">
<string>Loaders</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item row="3" column="3">
<widget class="QCheckBox" name="liteLoaderCb">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>LiteLoader</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="cauldronCb">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Cauldron</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="neoForgeCb">
<property name="text">
<string>NeoForge</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="forgeCb">
<property name="text">
<string>Forge</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="quiltCb">
<property name="text">
<string>Quilt</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="fabricCb">
<property name="text">
<string>Fabric</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="ModPage">
<attribute name="title">
<string>Others</string>
</attribute>
<layout class="QGridLayout" name="gridLayout1">
<item row="0" column="0">
<widget class="QGroupBox" name="envBox">
<property name="title">
<string>Environments</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QCheckBox" name="clientEnv">
<property name="text">
<string>Client</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="serverEnv">
<property name="text">
<string>Server</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Instaled status</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="hide_installed">
<property name="text">
<string>Hide already installed</string>
</property>
</widget>
</item>
</layout>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>