mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
Implement folder support for VDS. (#5545)
This commit is contained in:
parent
95cea0f191
commit
a0b52ce450
18 changed files with 438 additions and 136 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue