Implement folder support for VDS. (#5545)

This commit is contained in:
BruebachL 2025-02-02 16:08:04 +01:00 committed by GitHub
parent 95cea0f191
commit a0b52ce450
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 438 additions and 136 deletions

View file

@ -188,6 +188,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp

View file

@ -14,20 +14,26 @@ BannerWidget::BannerWidget(QWidget *parent, const QString &text, Qt::Orientation
bannerLabel->setStyleSheet("font-size: 24px; font-weight: bold; color: white;");
// Layout to center the banner label
QVBoxLayout *layout = new QVBoxLayout(this);
layout = new QVBoxLayout(this);
layout->addWidget(bannerLabel);
layout->setContentsMargins(0, 20, 0, 20); // Space for the gradient
setLayout(layout);
// Set minimum height for the widget
setMinimumHeight(100);
setMinimumHeight(50);
connect(this, &BannerWidget::buddyVisibilityChanged, this, &BannerWidget::toggleBuddyVisibility);
}
void BannerWidget::mousePressEvent(QMouseEvent *event)
{
QWidget::mousePressEvent(event);
emit buddyVisibilityChanged();
if (clickable) {
emit buddyVisibilityChanged();
}
}
void BannerWidget::setText(const QString &text) const
{
bannerLabel->setText(text);
}
void BannerWidget::toggleBuddyVisibility() const

View file

@ -2,6 +2,7 @@
#define BANNER_WIDGET_H
#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>
class BannerWidget : public QWidget
@ -14,6 +15,7 @@ public:
Qt::Orientation orientation = Qt::Vertical,
int transparency = 80);
void mousePressEvent(QMouseEvent *event) override;
void setText(const QString &text) const;
void setBuddy(QWidget *_buddy)
{
buddy = _buddy;
@ -22,15 +24,21 @@ public:
{
return bannerLabel->text();
}
void setClickable(bool _clickable)
{
clickable = _clickable;
}
protected:
void paintEvent(QPaintEvent *event) override;
private:
QVBoxLayout *layout;
QLabel *bannerLabel;
Qt::Orientation gradientOrientation;
int transparency; // Transparency percentage for the gradient
QWidget *buddy;
bool clickable = true;
signals:
void buddyVisibilityChanged();
private slots:

View file

@ -112,9 +112,9 @@ DeckPreviewColorIdentityFilterWidget::DeckPreviewColorIdentityFilterWidget(Visua
// Connect the button's toggled signal
connect(toggleButton, &QPushButton::toggled, this, &DeckPreviewColorIdentityFilterWidget::updateFilterMode);
connect(this, &DeckPreviewColorIdentityFilterWidget::activeColorsChanged, parent,
&VisualDeckStorageWidget::refreshBannerCards);
&VisualDeckStorageWidget::updateColorFilter);
connect(this, &DeckPreviewColorIdentityFilterWidget::filterModeChanged, parent,
&VisualDeckStorageWidget::refreshBannerCards);
&VisualDeckStorageWidget::updateColorFilter);
// Call retranslateUi to set the initial text
retranslateUi();
@ -139,10 +139,8 @@ void DeckPreviewColorIdentityFilterWidget::updateFilterMode(bool checked)
emit filterModeChanged(exactMatchMode);
}
QList<DeckPreviewWidget *> DeckPreviewColorIdentityFilterWidget::filterWidgets(QList<DeckPreviewWidget *> &widgets)
void DeckPreviewColorIdentityFilterWidget::filterWidgets(QList<DeckPreviewWidget *> widgets)
{
QList<DeckPreviewWidget *> filteredWidgets;
// Check if no colors are active
bool noColorsActive = true;
for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) {
@ -154,7 +152,9 @@ QList<DeckPreviewWidget *> DeckPreviewColorIdentityFilterWidget::filterWidgets(Q
// If no colors are active, return the unfiltered list of widgets
if (noColorsActive) {
return widgets;
for (DeckPreviewWidget *previewWidget : widgets) {
previewWidget->filteredByColor = false;
}
}
for (const auto &widget : widgets) {
@ -192,10 +192,6 @@ QList<DeckPreviewWidget *> DeckPreviewColorIdentityFilterWidget::filterWidgets(Q
}
}
if (matchesFilter) {
filteredWidgets << widget;
}
widget->filteredByColor = !matchesFilter;
}
return filteredWidgets;
}

View file

@ -42,7 +42,7 @@ class DeckPreviewColorIdentityFilterWidget : public QWidget
public:
explicit DeckPreviewColorIdentityFilterWidget(VisualDeckStorageWidget *parent);
void retranslateUi();
QList<DeckPreviewWidget *> filterWidgets(QList<DeckPreviewWidget *> &widgets);
void filterWidgets(QList<DeckPreviewWidget *> widgets);
signals:
void filterModeChanged(bool exactMatchMode);

View file

@ -39,7 +39,7 @@ void DeckPreviewTagAdditionWidget::mousePressEvent(QMouseEvent *event)
emit tagClicked();
}
QWidget::mousePressEvent(event);
QStringList knownTags = parent->parent->parent->gatherAllTagsFromFlowWidget();
QStringList knownTags = parent->parent->visualDeckStorageWidget->tagFilterWidget->getAllKnownTags();
QStringList activeTags = parent->deckLoader->getTags();
bool canAddTags = true;

View file

@ -9,14 +9,18 @@
#include <QSet>
#include <QVBoxLayout>
DeckPreviewWidget::DeckPreviewWidget(VisualDeckStorageWidget *_parent, const QString &_filePath)
: QWidget(_parent), parent(_parent), filePath(_filePath)
DeckPreviewWidget::DeckPreviewWidget(QWidget *_parent,
VisualDeckStorageWidget *_visualDeckStorageWidget,
const QString &_filePath)
: QWidget(_parent), visualDeckStorageWidget(_visualDeckStorageWidget), filePath(_filePath)
{
layout = new QVBoxLayout(this);
setLayout(layout);
deckLoader = new DeckLoader();
connect(deckLoader, &DeckLoader::loadFinished, this, &DeckPreviewWidget::initializeUi);
connect(deckLoader, &DeckLoader::loadFinished, visualDeckStorageWidget->tagFilterWidget,
&VisualDeckStorageTagFilterWidget::refreshTags);
deckLoader->loadFromFileAsync(filePath, DeckLoader::getFormatFromName(filePath), false);
bannerCardDisplayWidget = new DeckPreviewCardPictureWidget(this);
@ -52,6 +56,22 @@ void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess)
layout->addWidget(deckTagsDisplayWidget);
}
void DeckPreviewWidget::updateVisibility()
{
if (isVisible() != checkVisibility()) {
setHidden(!checkVisibility());
emit visibilityUpdated();
}
}
bool DeckPreviewWidget::checkVisibility() const
{
if (filteredBySearch || filteredByColor || filteredByTags) {
return false;
}
return true;
}
QString DeckPreviewWidget::getColorIdentity()
{
QStringList cardList = deckLoader->getCardList();

View file

@ -16,20 +16,27 @@ class DeckPreviewWidget final : public QWidget
{
Q_OBJECT
public:
explicit DeckPreviewWidget(VisualDeckStorageWidget *_parent, const QString &_filePath);
explicit DeckPreviewWidget(QWidget *_parent,
VisualDeckStorageWidget *_visualDeckStorageWidget,
const QString &_filePath);
QString getColorIdentity();
VisualDeckStorageWidget *parent;
VisualDeckStorageWidget *visualDeckStorageWidget;
QVBoxLayout *layout;
QString filePath;
DeckLoader *deckLoader;
DeckPreviewCardPictureWidget *bannerCardDisplayWidget;
DeckPreviewColorIdentityWidget *colorIdentityWidget;
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
bool filteredBySearch = false;
bool filteredByColor = false;
bool filteredByTags = false;
bool checkVisibility() const;
signals:
void deckPreviewClicked(QMouseEvent *event, DeckPreviewWidget *instance);
void deckPreviewDoubleClicked(QMouseEvent *event, DeckPreviewWidget *instance);
void visibilityUpdated();
public slots:
void setFilePath(const QString &filePath);
@ -37,6 +44,7 @@ public slots:
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
void initializeUi(bool deckLoadSuccess);
void updateVisibility();
};
#endif // DECK_PREVIEW_WIDGET_H

View file

@ -0,0 +1,179 @@
#include "visual_deck_storage_folder_display_widget.h"
#include "../../../../settings/cache_settings.h"
#include "deck_preview/deck_preview_widget.h"
#include <QDirIterator>
#include <QMouseEvent>
VisualDeckStorageFolderDisplayWidget::VisualDeckStorageFolderDisplayWidget(
QWidget *parent,
VisualDeckStorageWidget *_visualDeckStorageWidget,
QString _filePath,
bool canBeHidden)
: QWidget(parent), visualDeckStorageWidget(_visualDeckStorageWidget), filePath(_filePath)
{
layout = new QVBoxLayout(this);
setLayout(layout);
header = new BannerWidget(this, "");
header->setClickable(canBeHidden);
layout->addWidget(header);
container = new QWidget(this);
containerLayout = new QVBoxLayout(container);
container->setLayout(containerLayout);
header->setBuddy(container);
layout->addWidget(container);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
containerLayout->addWidget(flowWidget);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::tagFilterUpdated, this,
&VisualDeckStorageFolderDisplayWidget::updateVisibility);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::colorFilterUpdated, this,
&VisualDeckStorageFolderDisplayWidget::updateVisibility);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::searchFilterUpdated, this,
&VisualDeckStorageFolderDisplayWidget::updateVisibility);
createWidgetsForFiles();
createWidgetsForFolders();
refreshUi();
}
void VisualDeckStorageFolderDisplayWidget::refreshUi()
{
QString bannerText = tr("Deck Storage");
QString deckPath = SettingsCache::instance().getDeckPath();
if (filePath != deckPath) {
QString relativePath = filePath;
if (filePath.startsWith(deckPath)) {
relativePath = filePath.mid(deckPath.length()); // Remove the deckPath prefix
if (relativePath.startsWith('/')) {
relativePath.remove(0, 1); // Remove leading '/' if it exists
}
}
bannerText = relativePath;
}
header->setText(bannerText);
}
void VisualDeckStorageFolderDisplayWidget::createWidgetsForFiles()
{
QList<DeckPreviewWidget *> allDecks;
for (const QString &file : getAllFiles()) {
auto *display = new DeckPreviewWidget(flowWidget, visualDeckStorageWidget, file);
connect(display, &DeckPreviewWidget::deckPreviewClicked, visualDeckStorageWidget,
&VisualDeckStorageWidget::deckPreviewClickedEvent);
connect(display, &DeckPreviewWidget::deckPreviewDoubleClicked, visualDeckStorageWidget,
&VisualDeckStorageWidget::deckPreviewDoubleClickedEvent);
connect(visualDeckStorageWidget->cardSizeWidget->getSlider(), &QSlider::valueChanged,
display->bannerCardDisplayWidget, &CardInfoPictureWidget::setScaleFactor);
display->bannerCardDisplayWidget->setScaleFactor(visualDeckStorageWidget->cardSizeWidget->getSlider()->value());
allDecks.append(display);
}
flowWidget->clearLayout(); // Clear existing widgets in the flow layout
for (DeckPreviewWidget *deck : allDecks) {
flowWidget->addWidget(deck);
}
}
void VisualDeckStorageFolderDisplayWidget::updateVisibility()
{
bool atLeastOneWidgetVisible = checkVisibility();
if (atLeastOneWidgetVisible) {
setVisible(true);
for (DeckPreviewWidget *display : flowWidget->findChildren<DeckPreviewWidget *>()) {
display->updateVisibility();
}
for (VisualDeckStorageFolderDisplayWidget *subFolder : findChildren<VisualDeckStorageFolderDisplayWidget *>()) {
subFolder->updateVisibility();
}
} else {
setVisible(false);
}
}
bool VisualDeckStorageFolderDisplayWidget::checkVisibility()
{
bool atLeastOneWidgetVisible = false;
if (flowWidget) {
// Iterate through all DeckPreviewWidgets
for (DeckPreviewWidget *display : flowWidget->findChildren<DeckPreviewWidget *>()) {
if (display->checkVisibility()) {
atLeastOneWidgetVisible = true;
}
}
}
for (VisualDeckStorageFolderDisplayWidget *subFolder : findChildren<VisualDeckStorageFolderDisplayWidget *>()) {
if (subFolder->checkVisibility()) {
atLeastOneWidgetVisible = true;
}
}
return atLeastOneWidgetVisible;
}
void VisualDeckStorageFolderDisplayWidget::createWidgetsForFolders()
{
for (const QString &dir : getAllSubFolders()) {
auto *display = new VisualDeckStorageFolderDisplayWidget(this, visualDeckStorageWidget, dir, true);
containerLayout->addWidget(display);
}
}
QStringList VisualDeckStorageFolderDisplayWidget::gatherAllTagsFromFlowWidget() const
{
QStringList allTags;
if (flowWidget) {
// Iterate through all DeckPreviewWidgets
for (DeckPreviewWidget *display : flowWidget->findChildren<DeckPreviewWidget *>()) {
// Get tags from each DeckPreviewWidget
QStringList tags = display->deckLoader->getTags();
// Add tags to the list while avoiding duplicates
allTags.append(tags);
}
}
// Remove duplicates by calling 'removeDuplicates'
allTags.removeDuplicates();
return allTags;
}
QStringList VisualDeckStorageFolderDisplayWidget::getAllFiles() const
{
QStringList allFiles;
// QDirIterator with QDir::Files ensures only files are listed (no directories)
QDirIterator it(filePath, QDir::Files);
while (it.hasNext()) {
allFiles << it.next(); // Add each file path to the list
}
return allFiles;
}
QStringList VisualDeckStorageFolderDisplayWidget::getAllSubFolders() const
{
QStringList allFolders;
// QDirIterator with QDir::Files ensures only files are listed (no directories)
QDirIterator it(filePath, QDir::Dirs | QDir::NoDotAndDotDot);
while (it.hasNext()) {
allFolders << it.next(); // Add each file path to the list
}
return allFolders;
}

View file

@ -0,0 +1,44 @@
#ifndef VISUAL_DECK_STORAGE_FOLDER_DISPLAY_WIDGET_H
#define VISUAL_DECK_STORAGE_FOLDER_DISPLAY_WIDGET_H
#include "../general/display/banner_widget.h"
#include "../general/layout_containers/flow_widget.h"
#include "visual_deck_storage_widget.h"
#include <QVBoxLayout>
#include <QWidget>
class VisualDeckStorageFolderDisplayWidget : public QWidget
{
Q_OBJECT
public:
VisualDeckStorageFolderDisplayWidget(QWidget *parent,
VisualDeckStorageWidget *_visualDeckStorageWidget,
QString _filePath,
bool canBeHidden);
void refreshUi();
void createWidgetsForFiles();
void createWidgetsForFolders();
QStringList gatherAllTagsFromFlowWidget() const;
[[nodiscard]] QStringList getAllFiles() const;
[[nodiscard]] QStringList getAllSubFolders() const;
FlowWidget *getFlowWidget() const
{
return flowWidget;
};
public slots:
void updateVisibility();
bool checkVisibility();
private:
QVBoxLayout *layout;
VisualDeckStorageWidget *visualDeckStorageWidget;
QString filePath;
BannerWidget *header;
QWidget *container;
QVBoxLayout *containerLayout;
FlowWidget *flowWidget;
};
#endif // VISUAL_DECK_STORAGE_FOLDER_DISPLAY_WIDGET_H

View file

@ -25,7 +25,7 @@ VisualDeckStorageSearchWidget::VisualDeckStorageSearchWidget(VisualDeckStorageWi
searchDebounceTimer->start(300); // 300ms debounce
});
connect(searchDebounceTimer, &QTimer::timeout, parent, &VisualDeckStorageWidget::refreshBannerCards);
connect(searchDebounceTimer, &QTimer::timeout, parent, &VisualDeckStorageWidget::updateSearchFilter);
}
/**
@ -38,23 +38,18 @@ QString VisualDeckStorageSearchWidget::getSearchText()
return searchBar->text();
}
QList<DeckPreviewWidget *> VisualDeckStorageSearchWidget::filterFiles(QList<DeckPreviewWidget *> &widgets,
const QString &searchText)
void VisualDeckStorageSearchWidget::filterWidgets(QList<DeckPreviewWidget *> widgets, const QString &searchText)
{
if (searchText.isEmpty() || searchText.isNull()) {
return widgets;
}
QList<DeckPreviewWidget *> filteredWidgets;
for (const auto &file : widgets) {
QFileInfo fileInfo(file->filePath);
QString fileName = fileInfo.fileName().toLower();
if (fileName.contains(searchText.toLower())) {
filteredWidgets << file;
for (auto widget : widgets) {
widget->filteredBySearch = false;
}
}
return filteredWidgets;
for (auto file : widgets) {
QFileInfo fileInfo(file->filePath);
QString fileName = fileInfo.fileName().toLower();
file->filteredBySearch = !fileName.contains(searchText.toLower());
}
}

View file

@ -16,7 +16,7 @@ class VisualDeckStorageSearchWidget : public QWidget
public:
explicit VisualDeckStorageSearchWidget(VisualDeckStorageWidget *parent);
QString getSearchText();
QList<DeckPreviewWidget *> filterFiles(QList<DeckPreviewWidget *> &widgets, const QString &searchText);
void filterWidgets(QList<DeckPreviewWidget *> widgets, const QString &searchText);
private:
QHBoxLayout *layout;

View file

@ -63,7 +63,24 @@ void VisualDeckStorageSortWidget::updateSortOrder()
emit sortOrderChanged();
}
QList<DeckPreviewWidget *> &VisualDeckStorageSortWidget::filterFiles(QList<DeckPreviewWidget *> &widgets)
void VisualDeckStorageSortWidget::sortFolder(VisualDeckStorageFolderDisplayWidget *folderWidget)
{
auto children =
folderWidget->getFlowWidget()->findChildren<QWidget *>(QString(), Qt::FindChildOption::FindDirectChildrenOnly);
for (auto widget : children) {
auto deckPreviewWidgets =
widget->findChildren<DeckPreviewWidget *>(QString(), Qt::FindChildOption::FindDirectChildrenOnly);
auto newOrder = filterFiles(deckPreviewWidgets);
for (DeckPreviewWidget *previewWidget : newOrder) {
folderWidget->getFlowWidget()->removeWidget(previewWidget);
}
for (DeckPreviewWidget *previewWidget : newOrder) {
folderWidget->getFlowWidget()->addWidget(previewWidget);
}
}
}
QList<DeckPreviewWidget *> VisualDeckStorageSortWidget::filterFiles(QList<DeckPreviewWidget *> widgets)
{
// Sort the widgets list based on the current sort order
std::sort(widgets.begin(), widgets.end(), [this](DeckPreviewWidget *widget1, DeckPreviewWidget *widget2) {

View file

@ -8,6 +8,7 @@
#include <QWidget>
class VisualDeckStorageWidget;
class VisualDeckStorageFolderDisplayWidget;
class VisualDeckStorageSortWidget : public QWidget
{
Q_OBJECT
@ -16,8 +17,9 @@ public:
explicit VisualDeckStorageSortWidget(VisualDeckStorageWidget *parent);
void retranslateUi();
void updateSortOrder();
void sortFolder(VisualDeckStorageFolderDisplayWidget *folderWidget);
QString getSearchText();
QList<DeckPreviewWidget *> &filterFiles(QList<DeckPreviewWidget *> &widgets);
QList<DeckPreviewWidget *> filterFiles(QList<DeckPreviewWidget *> widgets);
signals:
void sortOrderChanged();

View file

@ -25,8 +25,13 @@ VisualDeckStorageTagFilterWidget::VisualDeckStorageTagFilterWidget(VisualDeckSto
layout->addWidget(flowWidget);
}
QList<DeckPreviewWidget *>
VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList<DeckPreviewWidget *> &deckPreviews) const
void VisualDeckStorageTagFilterWidget::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
refreshTags();
}
void VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList<DeckPreviewWidget *> &deckPreviews) const
{
// Collect selected tags from DeckPreviewTagDisplayWidget
QStringList selectedTags;
@ -36,9 +41,12 @@ VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList<DeckPrev
}
}
// If no tags are selected, return all decks
// If no tags are selected, set all decks as visible
if (selectedTags.isEmpty()) {
return deckPreviews;
for (DeckPreviewWidget *deckPreview : deckPreviews) {
deckPreview->filteredByTags = false;
}
return;
}
// Filter DeckPreviewWidgets that contain all of the selected tags
@ -50,12 +58,15 @@ VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList<DeckPrev
bool allTagsPresent = std::all_of(selectedTags.begin(), selectedTags.end(),
[&deckTags](const QString &tag) { return deckTags.contains(tag); });
if (allTagsPresent) {
filteredDecks.append(deckPreview);
}
deckPreview->filteredByTags = !allTagsPresent;
}
}
return filteredDecks;
void VisualDeckStorageTagFilterWidget::refreshTags()
{
QStringList allTags = gatherAllTags();
removeTagsNotInList(gatherAllTags());
addTagsIfNotPresent(gatherAllTags());
}
void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QStringList &tags)
@ -93,8 +104,37 @@ void VisualDeckStorageTagFilterWidget::addTagIfNotPresent(const QString &tag)
if (!tagExists) {
auto *newTagWidget = new DeckPreviewTagDisplayWidget(this, tag);
connect(newTagWidget, &DeckPreviewTagDisplayWidget::tagClicked, parent,
&VisualDeckStorageWidget::refreshBannerCards);
&VisualDeckStorageWidget::updateTagFilter);
connect(newTagWidget, &DeckPreviewTagDisplayWidget::tagClicked, this,
&VisualDeckStorageTagFilterWidget::refreshTags);
auto *flowWidget = findChild<FlowWidget *>();
flowWidget->addWidget(newTagWidget);
}
}
QStringList VisualDeckStorageTagFilterWidget::gatherAllTags()
{
QStringList allTags;
QList<DeckPreviewWidget *> deckWidgets = parent->findChildren<DeckPreviewWidget *>();
for (DeckPreviewWidget *widget : deckWidgets) {
if (widget->checkVisibility()) {
allTags << widget->deckLoader->getTags();
}
}
return allTags;
}
QStringList VisualDeckStorageTagFilterWidget::getAllKnownTags()
{
QStringList allTags;
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren<DeckPreviewTagDisplayWidget *>()) {
allTags.append(tagWidget->getTagName());
}
// Remove duplicates by calling 'removeDuplicates'
allTags.removeDuplicates();
return allTags;
}

View file

@ -12,12 +12,17 @@ class VisualDeckStorageTagFilterWidget : public QWidget
public:
explicit VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent);
void refreshTags();
QList<DeckPreviewWidget *> filterDecksBySelectedTags(const QList<DeckPreviewWidget *> &deckPreviews) const;
QStringList gatherAllTags();
void filterDecksBySelectedTags(const QList<DeckPreviewWidget *> &deckPreviews) const;
void removeTagsNotInList(const QStringList &tags);
void addTagsIfNotPresent(const QStringList &tags);
void addTagIfNotPresent(const QString &tag);
QStringList getAllKnownTags();
VisualDeckStorageWidget *parent;
public slots:
void refreshTags();
void showEvent(QShowEvent *event) override;
};
#endif // VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H

View file

@ -3,6 +3,7 @@
#include "../../../../game/cards/card_database_manager.h"
#include "../../../../settings/cache_settings.h"
#include "deck_preview/deck_preview_widget.h"
#include "visual_deck_storage_folder_display_widget.h"
#include "visual_deck_storage_search_widget.h"
#include "visual_deck_storage_sort_widget.h"
#include "visual_deck_storage_tag_filter_widget.h"
@ -17,12 +18,12 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
deckListModel = new DeckListModel(this);
deckListModel->setObjectName("visualDeckModel");
layout = new QVBoxLayout();
layout = new QVBoxLayout(this);
layout->setSpacing(0);
layout->setContentsMargins(9, 0, 9, 5);
setLayout(layout);
searchAndSortLayout = new QHBoxLayout();
searchAndSortLayout = new QHBoxLayout(this);
searchAndSortLayout->setSpacing(3);
searchAndSortLayout->setContentsMargins(9, 0, 9, 0);
@ -36,11 +37,19 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
searchAndSortLayout->addWidget(searchWidget);
layout->addLayout(searchAndSortLayout);
layout->addWidget(tagFilterWidget);
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
layout->addWidget(flowWidget);
scrollArea = new QScrollArea(this);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
folderWidget = new VisualDeckStorageFolderDisplayWidget(this, this, SettingsCache::instance().getDeckPath(), false);
scrollArea->setWidget(folderWidget);
scrollArea->setWidgetResizable(true);
layout->addWidget(scrollArea);
cardSizeWidget = new CardSizeWidget(this, flowWidget, SettingsCache::instance().getVisualDeckStorageCardSize());
layout->addWidget(cardSizeWidget);
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
@ -56,20 +65,22 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
refreshBannerCards();
databaseLoadIndicator->setVisible(false);
} else {
flowWidget->addWidget(databaseLoadIndicator);
scrollArea->setWidget(databaseLoadIndicator);
}
}
void VisualDeckStorageWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width());
scrollArea->widget()->adjustSize();
}
void VisualDeckStorageWidget::retranslateUi()
{
databaseLoadIndicator->setText(tr("Loading database ..."));
}
void VisualDeckStorageWidget::updateSortOrder()
{
refreshBannerCards(); // Refresh the banner cards with the new sort order
}
void VisualDeckStorageWidget::deckPreviewClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance)
{
emit deckPreviewClicked(event, instance);
@ -83,82 +94,44 @@ void VisualDeckStorageWidget::deckPreviewDoubleClickedEvent(QMouseEvent *event,
void VisualDeckStorageWidget::refreshBannerCards()
{
QStringList allFiles;
QList<DeckPreviewWidget *> allDecks;
// QDirIterator with QDir::Files and QDir::NoSymLinks ensures only files are listed (no directories or symlinks)
QDirIterator it(SettingsCache::instance().getDeckPath(), QDir::Files | QDir::NoSymLinks,
QDirIterator::Subdirectories);
while (it.hasNext()) {
allFiles << it.next(); // Add each file path to the list
}
for (const QString &file : allFiles) {
auto *display = new DeckPreviewWidget(this, file);
connect(display, &DeckPreviewWidget::deckPreviewClicked, this,
&VisualDeckStorageWidget::deckPreviewClickedEvent);
connect(display, &DeckPreviewWidget::deckPreviewDoubleClicked, this,
&VisualDeckStorageWidget::deckPreviewDoubleClickedEvent);
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, display->bannerCardDisplayWidget,
&CardInfoPictureWidget::setScaleFactor);
display->bannerCardDisplayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
allDecks.append(display);
}
auto filteredByColorIdentity =
deckPreviewColorIdentityFilterWidget->filterWidgets(sortWidget->filterFiles(allDecks));
auto filteredByTags = tagFilterWidget->filterDecksBySelectedTags(filteredByColorIdentity);
auto filteredFiles = searchWidget->filterFiles(filteredByTags, searchWidget->getSearchText());
tagFilterWidget->removeTagsNotInList(gatherAllTags(filteredFiles));
tagFilterWidget->addTagsIfNotPresent(gatherAllTags(filteredFiles));
flowWidget->clearLayout(); // Clear existing widgets in the flow layout
for (DeckPreviewWidget *deck : filteredFiles) {
flowWidget->addWidget(deck);
}
emit bannerCardsRefreshed();
folderWidget = new VisualDeckStorageFolderDisplayWidget(this, this, SettingsCache::instance().getDeckPath(), false);
scrollArea->setWidget(folderWidget);
scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width());
scrollArea->widget()->adjustSize();
}
QStringList VisualDeckStorageWidget::gatherAllTagsFromFlowWidget() const
void VisualDeckStorageWidget::updateSortOrder()
{
QStringList allTags;
if (flowWidget) {
// Iterate through all DeckPreviewWidgets
for (DeckPreviewWidget *display : flowWidget->findChildren<DeckPreviewWidget *>()) {
// Get tags from each DeckPreviewWidget
QStringList tags = display->deckLoader->getTags();
// Add tags to the list while avoiding duplicates
allTags.append(tags);
if (folderWidget) {
qDebug() << "Updating sort order";
sortWidget->sortFolder(folderWidget);
for (VisualDeckStorageFolderDisplayWidget *subFolderWidget :
folderWidget->findChildren<VisualDeckStorageFolderDisplayWidget *>()) {
sortWidget->sortFolder(subFolderWidget);
}
}
// Remove duplicates by calling 'removeDuplicates'
allTags.removeDuplicates();
return allTags;
}
QStringList VisualDeckStorageWidget::gatherAllTags(const QList<DeckPreviewWidget *> &allDecks)
void VisualDeckStorageWidget::updateTagFilter()
{
QStringList allTags;
// Iterate through all decks provided as input
for (DeckPreviewWidget *deck : allDecks) {
QStringList tags = deck->deckLoader->getTags();
// Add tags to the list while avoiding duplicates
allTags.append(tags);
if (folderWidget) {
tagFilterWidget->filterDecksBySelectedTags(folderWidget->findChildren<DeckPreviewWidget *>());
}
// Remove duplicates
allTags.removeDuplicates();
return allTags;
emit tagFilterUpdated();
}
void VisualDeckStorageWidget::updateColorFilter()
{
if (folderWidget) {
deckPreviewColorIdentityFilterWidget->filterWidgets(folderWidget->findChildren<DeckPreviewWidget *>());
}
emit colorFilterUpdated();
}
void VisualDeckStorageWidget::updateSearchFilter()
{
if (folderWidget) {
searchWidget->filterWidgets(folderWidget->findChildren<DeckPreviewWidget *>(), searchWidget->getSearchText());
}
emit searchFilterUpdated();
}

View file

@ -6,6 +6,7 @@
#include "../cards/card_size_widget.h"
#include "deck_preview/deck_preview_color_identity_filter_widget.h"
#include "deck_preview/deck_preview_widget.h"
#include "visual_deck_storage_folder_display_widget.h"
#include "visual_deck_storage_search_widget.h"
#include "visual_deck_storage_sort_widget.h"
#include "visual_deck_storage_tag_filter_widget.h"
@ -15,40 +16,47 @@
class VisualDeckStorageSearchWidget;
class VisualDeckStorageSortWidget;
class VisualDeckStorageTagFilterWidget;
class VisualDeckStorageFolderDisplayWidget;
class DeckPreviewColorIdentityFilterWidget;
class VisualDeckStorageWidget final : public QWidget
{
Q_OBJECT
public:
explicit VisualDeckStorageWidget(QWidget *parent);
void retranslateUi();
CardSizeWidget *cardSizeWidget;
VisualDeckStorageTagFilterWidget *tagFilterWidget;
public slots:
void deckPreviewClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance);
void deckPreviewDoubleClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance);
void refreshBannerCards(); // Refresh the display of cards based on the current sorting option
QStringList gatherAllTagsFromFlowWidget() const;
QStringList gatherAllTags(const QList<DeckPreviewWidget *> &allDecks);
void updateTagFilter();
void updateColorFilter();
void updateSearchFilter();
void updateSortOrder();
void resizeEvent(QResizeEvent *event) override;
signals:
void bannerCardsRefreshed();
void deckPreviewClicked(QMouseEvent *event, DeckPreviewWidget *instance);
void deckPreviewDoubleClicked(QMouseEvent *event, DeckPreviewWidget *instance);
void deckLoadRequested(QString &filePath);
void tagFilterUpdated();
void colorFilterUpdated();
void searchFilterUpdated();
private:
QVBoxLayout *layout;
QHBoxLayout *searchAndSortLayout;
FlowWidget *flowWidget;
DeckListModel *deckListModel;
QLabel *databaseLoadIndicator;
VisualDeckStorageSortWidget *sortWidget;
VisualDeckStorageSearchWidget *searchWidget;
VisualDeckStorageTagFilterWidget *tagFilterWidget;
DeckPreviewColorIdentityFilterWidget *deckPreviewColorIdentityFilterWidget;
CardSizeWidget *cardSizeWidget;
QScrollArea *scrollArea;
VisualDeckStorageFolderDisplayWidget *folderWidget;
};
#endif // VISUAL_DECK_STORAGE_WIDGET_H