mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-15 19:47:46 -07:00
Visual deck storage v2 (#5427)
* Restore some button states (ready/sideboard locked) to sensible defaults when unloading a deck. * Update last loaded timestamp in decklist file and then restore original last modified timestamp if a user requests a deck load. * Add some todos. * Loading a deck from local file dialog should swap out scenes, enable unload button. * Lint. * Shuffle some classes and signals around. * More sort options, sort widgets directly. * Banner cards should respect providerIds. * Properly updateSortOrder on load. * Add the color identity to the Deck Preview Widget. * Properly set sort indices. * Change replace visualDeckStorageWidget with deckView to be in deckSelectFinished so that it also works on remote deck load. * Include settings for unused color identities display. * Change opacity scaling. * Overload for Qt. * Lint. * Lint. * Include QMouseEvent * Template because MacOs. * Include a quick filter for color identities. * Include a quick filter for color identities. * Save some space. * Refactor DeckPreviewWidgets to reside in their own folder. * Add Deck Loader logging category. * Introduce a tagging system. * Add some more default tags. * Even more default tags. * Lint. * Lint a comma. * Remove extra set of braces. * Lint some stuff. * Refresh banner cards when tags are added. * Lint. * Wrestle with Qt Checkboxes. * Lint. * Adjust some sizes, relayout. * Address comments. * Lint. * Reorder kindred types. * Add a search bar for tags. * Remove close button (for now) and change "Add tags ..." to "Edit tags ..." * Retranslate window title for Deck Tag Manager Dialog. * Style tag addition widget to be consistent. * Lint. * Override paintEvent. * Override sizeHint --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
9bd024d39f
commit
dd8ac14f99
46 changed files with 1899 additions and 153 deletions
|
|
@ -162,8 +162,18 @@ set(cockatrice_SOURCES
|
||||||
src/game/zones/view_zone.cpp
|
src/game/zones/view_zone.cpp
|
||||||
src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
||||||
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_widget.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
|
||||||
|
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_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_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
|
||||||
${VERSION_STRING_CPP}
|
${VERSION_STRING_CPP}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
[Rules]
|
[Rules]
|
||||||
picture_loader.debug = true
|
picture_loader.debug = true
|
||||||
|
deck_loader.debug = true
|
||||||
|
|
@ -823,7 +823,7 @@ void TabDeckEditor::updateBannerCardComboBox()
|
||||||
bannerCardComboBox->clear();
|
bannerCardComboBox->clear();
|
||||||
|
|
||||||
// Prepare the new items with deduplication
|
// Prepare the new items with deduplication
|
||||||
QSet<QString> bannerCardSet;
|
QSet<QPair<QString, QString>> bannerCardSet;
|
||||||
InnerDecklistNode *listRoot = deckModel->getDeckList()->getRoot();
|
InnerDecklistNode *listRoot = deckModel->getDeckList()->getRoot();
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
for (int i = 0; i < listRoot->size(); i++) {
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||||
|
|
@ -833,23 +833,30 @@ void TabDeckEditor::updateBannerCardComboBox()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
|
||||||
|
currentCard->getName(), currentCard->getCardProviderId());
|
||||||
if (info) {
|
if (info) {
|
||||||
bannerCardSet.insert(currentCard->getName());
|
bannerCardSet.insert(
|
||||||
|
QPair<QString, QString>(currentCard->getName(), currentCard->getCardProviderId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the QSet to a sorted QStringList
|
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
||||||
QStringList bannerCardChoices;
|
|
||||||
for (const QString &entry : bannerCardSet) {
|
|
||||||
bannerCardChoices.append(entry);
|
|
||||||
}
|
|
||||||
bannerCardChoices.sort(Qt::CaseInsensitive);
|
|
||||||
|
|
||||||
// Populate the combo box with new items
|
// Sort QList by the first() element of the QPair
|
||||||
bannerCardComboBox->addItems(bannerCardChoices);
|
std::sort(pairList.begin(), pairList.end(), [](const QPair<QString, QString> &a, const QPair<QString, QString> &b) {
|
||||||
|
return a.first.toLower() < b.first.toLower();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const auto &pair : pairList) {
|
||||||
|
QVariantMap dataMap;
|
||||||
|
dataMap["name"] = pair.first;
|
||||||
|
dataMap["uuid"] = pair.second;
|
||||||
|
|
||||||
|
bannerCardComboBox->addItem(pair.first, dataMap);
|
||||||
|
}
|
||||||
|
|
||||||
// Try to restore the previous selection by finding the currentText
|
// Try to restore the previous selection by finding the currentText
|
||||||
int restoredIndex = bannerCardComboBox->findText(currentText);
|
int restoredIndex = bannerCardComboBox->findText(currentText);
|
||||||
|
|
@ -857,7 +864,7 @@ void TabDeckEditor::updateBannerCardComboBox()
|
||||||
bannerCardComboBox->setCurrentIndex(restoredIndex);
|
bannerCardComboBox->setCurrentIndex(restoredIndex);
|
||||||
} else {
|
} else {
|
||||||
// Add a placeholder "-" and set it as the current selection
|
// Add a placeholder "-" and set it as the current selection
|
||||||
int bannerIndex = bannerCardComboBox->findText(deckModel->getDeckList()->getBannerCard());
|
int bannerIndex = bannerCardComboBox->findText(deckModel->getDeckList()->getBannerCard().first);
|
||||||
if (bannerIndex != -1) {
|
if (bannerIndex != -1) {
|
||||||
bannerCardComboBox->setCurrentIndex(bannerIndex);
|
bannerCardComboBox->setCurrentIndex(bannerIndex);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -872,8 +879,8 @@ void TabDeckEditor::updateBannerCardComboBox()
|
||||||
|
|
||||||
void TabDeckEditor::setBannerCard(int /* changedIndex */)
|
void TabDeckEditor::setBannerCard(int /* changedIndex */)
|
||||||
{
|
{
|
||||||
qDebug() << "Banner card was set to: " << bannerCardComboBox->currentText();
|
QVariantMap data = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
|
||||||
deckModel->getDeckList()->setBannerCard(bannerCardComboBox->currentText());
|
deckModel->getDeckList()->setBannerCard(QPair<QString, QString>(data["name"].toString(), data["uuid"].toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabDeckEditor::updateCardInfo(CardInfoPtr _card)
|
void TabDeckEditor::updateCardInfo(CardInfoPtr _card)
|
||||||
|
|
@ -1043,11 +1050,11 @@ void TabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLocation d
|
||||||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
||||||
|
|
||||||
auto *l = new DeckLoader;
|
auto *l = new DeckLoader;
|
||||||
if (l->loadFromFile(fileName, fmt)) {
|
if (l->loadFromFile(fileName, fmt, true)) {
|
||||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
||||||
updateBannerCardComboBox();
|
updateBannerCardComboBox();
|
||||||
if (!l->getBannerCard().isEmpty()) {
|
if (!l->getBannerCard().first.isEmpty()) {
|
||||||
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText(l->getBannerCard()));
|
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText(l->getBannerCard().first));
|
||||||
}
|
}
|
||||||
if (deckOpenLocation == NEW_TAB) {
|
if (deckOpenLocation == NEW_TAB) {
|
||||||
emit openDeckEditor(l);
|
emit openDeckEditor(l);
|
||||||
|
|
@ -1542,13 +1549,13 @@ void TabDeckEditor::actDecrement()
|
||||||
|
|
||||||
void TabDeckEditor::setDeck(DeckLoader *_deck)
|
void TabDeckEditor::setDeck(DeckLoader *_deck)
|
||||||
{
|
{
|
||||||
qDebug() << " ORIGINAL BANNER CARD " << _deck->getBannerCard();
|
qDebug() << " ORIGINAL BANNER CARD " << _deck->getBannerCard().first;
|
||||||
deckModel->setDeckList(_deck);
|
deckModel->setDeckList(_deck);
|
||||||
|
|
||||||
nameEdit->setText(deckModel->getDeckList()->getName());
|
nameEdit->setText(deckModel->getDeckList()->getName());
|
||||||
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
||||||
qDebug() << deckModel->getDeckList()->getBannerCard() << " was the banner card";
|
qDebug() << deckModel->getDeckList()->getBannerCard() << " was the banner card";
|
||||||
bannerCardComboBox->setCurrentText(deckModel->getDeckList()->getBannerCard());
|
bannerCardComboBox->setCurrentText(deckModel->getDeckList()->getBannerCard().first);
|
||||||
updateBannerCardComboBox();
|
updateBannerCardComboBox();
|
||||||
updateHash();
|
updateHash();
|
||||||
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ void TabDeckStorage::actOpenLocalDeck()
|
||||||
QString filePath = localDirModel->filePath(curLeft);
|
QString filePath = localDirModel->filePath(curLeft);
|
||||||
|
|
||||||
DeckLoader deckLoader;
|
DeckLoader deckLoader;
|
||||||
if (!deckLoader.loadFromFile(filePath, DeckLoader::CockatriceFormat))
|
if (!deckLoader.loadFromFile(filePath, DeckLoader::CockatriceFormat, true))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(filePath);
|
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(filePath);
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||||
deckView->setVisible(false);
|
deckView->setVisible(false);
|
||||||
|
|
||||||
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
||||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::imageDoubleClicked, this,
|
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckPreviewDoubleClicked, this,
|
||||||
&DeckViewContainer::replaceDeckStorageWithDeckView);
|
&DeckViewContainer::replaceDeckStorageWithDeckView);
|
||||||
|
|
||||||
deckViewLayout = new QVBoxLayout;
|
deckViewLayout = new QVBoxLayout;
|
||||||
|
|
@ -299,20 +299,12 @@ void TabGame::refreshShortcuts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::replaceDeckStorageWithDeckView(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
void DeckViewContainer::replaceDeckStorageWithDeckView(QMouseEvent *event, DeckPreviewWidget *instance)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
QString fileName = instance->filePath;
|
QString deckString = instance->deckLoader->writeToString_Native();
|
||||||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
|
||||||
QString deckString;
|
|
||||||
DeckLoader deck;
|
|
||||||
|
|
||||||
bool error = !deck.loadFromFile(fileName, fmt);
|
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||||
if (!error) {
|
|
||||||
deckString = deck.writeToString_Native();
|
|
||||||
error = deckString.length() > MAX_FILE_LENGTH;
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -335,6 +327,11 @@ void DeckViewContainer::unloadDeck()
|
||||||
visualDeckStorageWidget->setVisible(true);
|
visualDeckStorageWidget->setVisible(true);
|
||||||
deckViewLayout->update();
|
deckViewLayout->update();
|
||||||
unloadDeckButton->setEnabled(false);
|
unloadDeckButton->setEnabled(false);
|
||||||
|
readyStartButton->setEnabled(false);
|
||||||
|
readyStartButton->setState(false);
|
||||||
|
sideboardLockButton->setEnabled(false);
|
||||||
|
sideboardLockButton->setState(false);
|
||||||
|
setReadyStart(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::loadLocalDeck()
|
void DeckViewContainer::loadLocalDeck()
|
||||||
|
|
@ -352,7 +349,7 @@ void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||||
QString deckString;
|
QString deckString;
|
||||||
DeckLoader deck;
|
DeckLoader deck;
|
||||||
|
|
||||||
bool error = !deck.loadFromFile(filePath, fmt);
|
bool error = !deck.loadFromFile(filePath, fmt, true);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
deckString = deck.writeToString_Native();
|
deckString = deck.writeToString_Native();
|
||||||
error = deckString.length() > MAX_FILE_LENGTH;
|
error = deckString.length() > MAX_FILE_LENGTH;
|
||||||
|
|
@ -390,6 +387,9 @@ void DeckViewContainer::deckSelectFinished(const Response &r)
|
||||||
// TODO CHANGE THIS TO BE SELECTED BY UUID
|
// TODO CHANGE THIS TO BE SELECTED BY UUID
|
||||||
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(newDeck.getCardList()));
|
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(newDeck.getCardList()));
|
||||||
setDeck(newDeck);
|
setDeck(newDeck);
|
||||||
|
deckView->setVisible(true);
|
||||||
|
visualDeckStorageWidget->setVisible(false);
|
||||||
|
unloadDeckButton->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::readyStart()
|
void DeckViewContainer::readyStart()
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ private:
|
||||||
TabGame *parentGame;
|
TabGame *parentGame;
|
||||||
int playerId;
|
int playerId;
|
||||||
private slots:
|
private slots:
|
||||||
void replaceDeckStorageWithDeckView(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void replaceDeckStorageWithDeckView(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
void loadLocalDeck();
|
void loadLocalDeck();
|
||||||
void loadRemoteDeck();
|
void loadRemoteDeck();
|
||||||
void unloadDeck();
|
void unloadDeck();
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor, Abstra
|
||||||
leftToolBar->addAction(aDeleteLocalDeck);
|
leftToolBar->addAction(aDeleteLocalDeck);
|
||||||
|
|
||||||
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
||||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::imageDoubleClicked, this,
|
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckPreviewDoubleClicked, this,
|
||||||
&TabDeckStorageVisual::actOpenLocalDeck);
|
&TabDeckStorageVisual::actOpenLocalDeck);
|
||||||
|
|
||||||
// layout->addWidget(leftToolBar);
|
// layout->addWidget(leftToolBar);
|
||||||
|
|
@ -74,11 +74,11 @@ QString TabDeckStorageVisual::getTargetPath() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabDeckStorageVisual::actOpenLocalDeck(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
void TabDeckStorageVisual::actOpenLocalDeck(QMouseEvent *event, DeckPreviewWidget *instance)
|
||||||
{
|
{
|
||||||
(void)event;
|
(void)event;
|
||||||
DeckLoader deckLoader;
|
DeckLoader deckLoader;
|
||||||
if (!deckLoader.loadFromFile(instance->filePath, DeckLoader::CockatriceFormat))
|
if (!deckLoader.loadFromFile(instance->filePath, DeckLoader::CockatriceFormat, true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emit openDeckEditor(&deckLoader);
|
emit openDeckEditor(&deckLoader);
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ public:
|
||||||
}
|
}
|
||||||
public slots:
|
public slots:
|
||||||
void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
void closeRequest(bool forced = false) override;
|
void closeRequest(bool forced) override;
|
||||||
void actOpenLocalDeck(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void actOpenLocalDeck(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
void actDeleteLocalDeck();
|
void actDeleteLocalDeck();
|
||||||
signals:
|
signals:
|
||||||
void openDeckEditor(const DeckLoader *deckLoader);
|
void openDeckEditor(const DeckLoader *deckLoader);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "deck_preview_card_picture_widget.h"
|
#include "deck_preview_card_picture_widget.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QFontMetrics>
|
#include <QFontMetrics>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
|
|
@ -15,6 +16,7 @@
|
||||||
* @param outlineColor The color of the outline around the text.
|
* @param outlineColor The color of the outline around the text.
|
||||||
* @param fontSize The font size of the overlay text.
|
* @param fontSize The font size of the overlay text.
|
||||||
* @param alignment The alignment of the text within the overlay.
|
* @param alignment The alignment of the text within the overlay.
|
||||||
|
* @param _deckLoader The Deck Loader holding the Deck associated with this preview.
|
||||||
*
|
*
|
||||||
* Sets the widget's size policy and default border style.
|
* Sets the widget's size policy and default border style.
|
||||||
*/
|
*/
|
||||||
|
|
@ -46,8 +48,3 @@ void DeckPreviewCardPictureWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
emit imageDoubleClicked(lastMouseEvent, this);
|
emit imageDoubleClicked(lastMouseEvent, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckPreviewCardPictureWidget::setFilePath(const QString &_filePath)
|
|
||||||
{
|
|
||||||
filePath = _filePath;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -12,22 +12,17 @@ class DeckPreviewCardPictureWidget final : public CardInfoPictureWithTextOverlay
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DeckPreviewCardPictureWidget(QWidget *parent = nullptr,
|
explicit DeckPreviewCardPictureWidget(QWidget *parent,
|
||||||
bool hoverToZoomEnabled = false,
|
bool hoverToZoomEnabled = false,
|
||||||
const QColor &textColor = Qt::white,
|
const QColor &textColor = Qt::white,
|
||||||
const QColor &outlineColor = Qt::black,
|
const QColor &outlineColor = Qt::black,
|
||||||
int fontSize = 12,
|
int fontSize = 12,
|
||||||
Qt::Alignment alignment = Qt::AlignCenter);
|
Qt::Alignment alignment = Qt::AlignCenter);
|
||||||
|
|
||||||
QString filePath;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||||
void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setFilePath(const QString &filePath);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTimer *singleClickTimer;
|
QTimer *singleClickTimer;
|
||||||
QMouseEvent *lastMouseEvent = nullptr; // Store the last mouse event
|
QMouseEvent *lastMouseEvent = nullptr; // Store the last mouse event
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,11 @@ void FlowWidget::addWidget(QWidget *widget_to_add) const
|
||||||
flowLayout->addWidget(widget_to_add);
|
flowLayout->addWidget(widget_to_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlowWidget::removeWidget(QWidget *widgetToRemove) const
|
||||||
|
{
|
||||||
|
flowLayout->removeWidget(widgetToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clears all widgets from the flow layout.
|
* @brief Clears all widgets from the flow layout.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ class FlowWidget final : public QWidget
|
||||||
public:
|
public:
|
||||||
FlowWidget(QWidget *parent, Qt::ScrollBarPolicy horizontalPolicy, Qt::ScrollBarPolicy verticalPolicy);
|
FlowWidget(QWidget *parent, Qt::ScrollBarPolicy horizontalPolicy, Qt::ScrollBarPolicy verticalPolicy);
|
||||||
void addWidget(QWidget *widget_to_add) const;
|
void addWidget(QWidget *widget_to_add) const;
|
||||||
|
void removeWidget(QWidget *widgetToRemove) const;
|
||||||
void clearLayout();
|
void clearLayout();
|
||||||
[[nodiscard]] int count() const;
|
[[nodiscard]] int count() const;
|
||||||
[[nodiscard]] QLayoutItem *itemAt(int index) const;
|
[[nodiscard]] QLayoutItem *itemAt(int index) const;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
#include "deck_preview_color_identity_filter_widget.h"
|
||||||
|
|
||||||
|
#include "deck_preview_widget.h"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
DeckPreviewColorIdentityFilterCircleWidget::DeckPreviewColorIdentityFilterCircleWidget(QChar color, QWidget *parent)
|
||||||
|
: QWidget(parent), colorChar(color), isActive(false), circleDiameter(30)
|
||||||
|
{
|
||||||
|
setFixedSize(circleDiameter, circleDiameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityFilterCircleWidget::setColorActive(bool active)
|
||||||
|
{
|
||||||
|
if (isActive != active) {
|
||||||
|
isActive = active;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckPreviewColorIdentityFilterCircleWidget::isColorActive() const
|
||||||
|
{
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
QChar DeckPreviewColorIdentityFilterCircleWidget::getColorChar() const
|
||||||
|
{
|
||||||
|
return colorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityFilterCircleWidget::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
QColor circleColor;
|
||||||
|
switch (colorChar.unicode()) {
|
||||||
|
case 'W':
|
||||||
|
circleColor = Qt::white;
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
circleColor = QColor(0, 115, 230);
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
circleColor = QColor(50, 50, 50);
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
circleColor = QColor(230, 30, 30);
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
circleColor = QColor(30, 180, 30);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
circleColor = Qt::transparent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isActive) {
|
||||||
|
circleColor.setAlpha(100); // Dim inactive circles
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.setBrush(circleColor);
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
painter.drawEllipse(rect());
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
QFont font = painter.font();
|
||||||
|
font.setBold(true);
|
||||||
|
font.setPointSize(circleDiameter / 3);
|
||||||
|
painter.setFont(font);
|
||||||
|
painter.setPen(colorChar.unicode() == 'B' ? Qt::white : Qt::black);
|
||||||
|
painter.drawText(rect(), Qt::AlignCenter, colorChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityFilterCircleWidget::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
isActive = !isActive;
|
||||||
|
emit colorToggled(colorChar, isActive);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeckPreviewColorIdentityFilterWidget::DeckPreviewColorIdentityFilterWidget(VisualDeckStorageWidget *parent)
|
||||||
|
: QWidget(parent), layout(new QHBoxLayout(this))
|
||||||
|
{
|
||||||
|
setLayout(layout);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
QString fullColorIdentity = "WUBRG";
|
||||||
|
for (const QChar &color : fullColorIdentity) {
|
||||||
|
auto *circle = new DeckPreviewColorIdentityFilterCircleWidget(color, this);
|
||||||
|
|
||||||
|
layout->addWidget(circle);
|
||||||
|
|
||||||
|
// Initialize the activeColors map
|
||||||
|
activeColors[color] = false;
|
||||||
|
|
||||||
|
// Connect the color toggled signal
|
||||||
|
connect(circle, &DeckPreviewColorIdentityFilterCircleWidget::colorToggled, this,
|
||||||
|
&DeckPreviewColorIdentityFilterWidget::handleColorToggled);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleButton = new QPushButton(this);
|
||||||
|
toggleButton->setCheckable(true);
|
||||||
|
layout->addWidget(toggleButton);
|
||||||
|
|
||||||
|
// Connect the button's toggled signal
|
||||||
|
connect(toggleButton, &QPushButton::toggled, this, &DeckPreviewColorIdentityFilterWidget::updateFilterMode);
|
||||||
|
connect(this, &DeckPreviewColorIdentityFilterWidget::activeColorsChanged, parent,
|
||||||
|
&VisualDeckStorageWidget::refreshBannerCards);
|
||||||
|
connect(this, &DeckPreviewColorIdentityFilterWidget::filterModeChanged, parent,
|
||||||
|
&VisualDeckStorageWidget::refreshBannerCards);
|
||||||
|
|
||||||
|
// Call retranslateUi to set the initial text
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityFilterWidget::retranslateUi()
|
||||||
|
{
|
||||||
|
// Set the toggle button text based on the current mode
|
||||||
|
toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar color, bool active)
|
||||||
|
{
|
||||||
|
activeColors[color] = active;
|
||||||
|
emit activeColorsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityFilterWidget::updateFilterMode(bool checked)
|
||||||
|
{
|
||||||
|
exactMatchMode = checked; // Toggle between modes
|
||||||
|
retranslateUi(); // Update the button text
|
||||||
|
emit filterModeChanged(exactMatchMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DeckPreviewWidget *> 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) {
|
||||||
|
if (it.value()) {
|
||||||
|
noColorsActive = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no colors are active, return the unfiltered list of widgets
|
||||||
|
if (noColorsActive) {
|
||||||
|
return widgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &widget : widgets) {
|
||||||
|
QString colorIdentity = widget->getColorIdentity();
|
||||||
|
|
||||||
|
bool matchesFilter = true;
|
||||||
|
if (exactMatchMode) {
|
||||||
|
// Exact match mode: active colors must exactly match colorIdentity
|
||||||
|
|
||||||
|
// Create a set of active colors
|
||||||
|
QSet<QChar> activeColorSet;
|
||||||
|
for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) {
|
||||||
|
if (it.value()) {
|
||||||
|
activeColorSet.insert(it.key().toUpper()); // Use uppercase for uniformity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a set of colors from the color identity string
|
||||||
|
QSet<QChar> colorIdentitySet;
|
||||||
|
for (const QChar &color : colorIdentity) {
|
||||||
|
colorIdentitySet.insert(color.toUpper()); // Ensure case uniformity
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the sets: the sets must match exactly
|
||||||
|
if (activeColorSet != colorIdentitySet) {
|
||||||
|
matchesFilter = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Includes mode: colorIdentity must contain all active colors
|
||||||
|
for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) {
|
||||||
|
if (it.value() && !colorIdentity.contains(it.key())) {
|
||||||
|
matchesFilter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchesFilter) {
|
||||||
|
filteredWidgets << widget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredWidgets;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef DECK_PREVIEW_COLOR_IDENTITY_FILTER_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_COLOR_IDENTITY_FILTER_WIDGET_H
|
||||||
|
|
||||||
|
#include "../visual_deck_storage_widget.h"
|
||||||
|
|
||||||
|
#include <QChar>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QList>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckPreviewWidget;
|
||||||
|
class VisualDeckStorageWidget;
|
||||||
|
|
||||||
|
class DeckPreviewColorIdentityFilterCircleWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewColorIdentityFilterCircleWidget(QChar color, QWidget *parent = nullptr);
|
||||||
|
void setColorActive(bool active);
|
||||||
|
bool isColorActive() const;
|
||||||
|
QChar getColorChar() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void colorToggled(QChar color, bool active);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QChar colorChar;
|
||||||
|
bool isActive;
|
||||||
|
int circleDiameter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeckPreviewColorIdentityFilterWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewColorIdentityFilterWidget(VisualDeckStorageWidget *parent);
|
||||||
|
void retranslateUi();
|
||||||
|
QList<DeckPreviewWidget *> filterWidgets(QList<DeckPreviewWidget *> &widgets);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void filterModeChanged(bool exactMatchMode);
|
||||||
|
void activeColorsChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleColorToggled(QChar color, bool active);
|
||||||
|
void updateFilterMode(bool checked);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
QPushButton *toggleButton;
|
||||||
|
QMap<QChar, bool> activeColors;
|
||||||
|
bool exactMatchMode = false; // Default to "includes" mode
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_COLOR_IDENTITY_FILTER_WIDGET_H
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
#include "deck_preview_color_identity_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../settings/cache_settings.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
DeckPreviewColorCircleWidget::DeckPreviewColorCircleWidget(QChar color, QWidget *parent)
|
||||||
|
: QWidget(parent), colorChar(color), circleDiameter(0), isActive(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorCircleWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
|
||||||
|
// Get the parent of the DeckPreviewColorIdentityWidget
|
||||||
|
QWidget *identityParent = parentWidget() ? parentWidget()->parentWidget() : nullptr;
|
||||||
|
if (identityParent) {
|
||||||
|
// Calculate the circle diameter as 15% of the parent's height
|
||||||
|
int maxSize = identityParent->width() * 0.15;
|
||||||
|
circleDiameter = maxSize;
|
||||||
|
|
||||||
|
// Update the widget size based on the diameter
|
||||||
|
updateGeometry(); // Request a resize based on sizeHint()
|
||||||
|
}
|
||||||
|
|
||||||
|
update(); // Trigger a repaint
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize DeckPreviewColorCircleWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
// Return the size we calculated based on the parent widget
|
||||||
|
return QSize(circleDiameter, circleDiameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize DeckPreviewColorCircleWidget::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
// Return the same value as sizeHint() for minimum size
|
||||||
|
return QSize(circleDiameter, circleDiameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorCircleWidget::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
// Calculate the circle's bounding rectangle
|
||||||
|
int x = (width() - circleDiameter) / 2;
|
||||||
|
int y = (height() - circleDiameter) / 2;
|
||||||
|
QRect circleRect(x, y, circleDiameter, circleDiameter);
|
||||||
|
|
||||||
|
// Map color characters to their respective colors
|
||||||
|
QColor circleColor;
|
||||||
|
switch (colorChar.unicode()) {
|
||||||
|
case 'W':
|
||||||
|
circleColor = Qt::white;
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
circleColor = QColor(0, 115, 230);
|
||||||
|
break; // Blue
|
||||||
|
case 'B':
|
||||||
|
circleColor = QColor(50, 50, 50);
|
||||||
|
break; // Black
|
||||||
|
case 'R':
|
||||||
|
circleColor = QColor(230, 30, 30);
|
||||||
|
break; // Red
|
||||||
|
case 'G':
|
||||||
|
circleColor = QColor(30, 180, 30);
|
||||||
|
break; // Green
|
||||||
|
default:
|
||||||
|
circleColor = Qt::transparent;
|
||||||
|
break; // Fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities() || isActive) {
|
||||||
|
// Make the circle faint if it is not active
|
||||||
|
if (!isActive) {
|
||||||
|
circleColor.setAlpha(SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity() / 100.0 *
|
||||||
|
255.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the circle
|
||||||
|
painter.setBrush(circleColor);
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
painter.drawEllipse(circleRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the color character only if the circle is active
|
||||||
|
if (isActive) {
|
||||||
|
QFont font = painter.font();
|
||||||
|
font.setBold(true);
|
||||||
|
font.setPointSize(circleDiameter * 0.4); // Adjust font size relative to circle diameter
|
||||||
|
painter.setFont(font);
|
||||||
|
if (colorChar.unicode() == 'B') {
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
} else {
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Center the text within the circle
|
||||||
|
painter.drawText(circleRect, Qt::AlignCenter, colorChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorCircleWidget::setColorActive(bool active)
|
||||||
|
{
|
||||||
|
isActive = active;
|
||||||
|
update(); // Redraw the circle with the new active state
|
||||||
|
}
|
||||||
|
|
||||||
|
QChar DeckPreviewColorCircleWidget::getColorChar() const
|
||||||
|
{
|
||||||
|
return colorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeckPreviewColorIdentityWidget::DeckPreviewColorIdentityWidget(const QString &colorIdentity, QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
|
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||||
|
QString fullColorIdentity = "WUBRG";
|
||||||
|
|
||||||
|
// Create and add a DeckPreviewColorCircleWidget for each color in WUBRG
|
||||||
|
for (const QChar &color : fullColorIdentity) {
|
||||||
|
auto *circle = new DeckPreviewColorCircleWidget(color, this);
|
||||||
|
layout->addWidget(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any active colors from the input colorIdentity
|
||||||
|
for (const QChar &color : colorIdentity) {
|
||||||
|
for (DeckPreviewColorCircleWidget *circle : findChildren<DeckPreviewColorCircleWidget *>()) {
|
||||||
|
if (circle->getColorChar() == color) {
|
||||||
|
circle->setColorActive(true); // Mark the color as active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewColorIdentityWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
|
||||||
|
// Notify child widgets to update their sizes based on the new parent size
|
||||||
|
for (auto *circle : findChildren<DeckPreviewColorCircleWidget *>()) {
|
||||||
|
circle->updateGeometry(); // Request each circle to resize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef DECK_PREVIEW_COLOR_IDENTITY_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_COLOR_IDENTITY_WIDGET_H
|
||||||
|
|
||||||
|
#include <QChar>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckPreviewColorCircleWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewColorCircleWidget(QChar color, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void setColorActive(bool active);
|
||||||
|
QChar getColorChar() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QChar colorChar;
|
||||||
|
int circleDiameter;
|
||||||
|
bool isActive;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeckPreviewColorIdentityWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewColorIdentityWidget(const QString &colorIdentity, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_COLOR_IDENTITY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include "deck_preview_deck_tags_display_widget.h"
|
||||||
|
|
||||||
|
#include "../../general/layout_containers/flow_widget.h"
|
||||||
|
#include "deck_preview_tag_addition_widget.h"
|
||||||
|
#include "deck_preview_tag_display_widget.h"
|
||||||
|
#include "deck_preview_widget.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(DeckPreviewWidget *_parent, DeckLoader *_deckLoader)
|
||||||
|
: QWidget(_parent), parent(_parent), deckLoader(_deckLoader)
|
||||||
|
{
|
||||||
|
|
||||||
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
|
// Create layout
|
||||||
|
auto *layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(5, 5, 5, 5);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
|
||||||
|
setFixedHeight(100);
|
||||||
|
|
||||||
|
auto *flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
|
for (const QString &tag : this->deckLoader->getTags()) {
|
||||||
|
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
|
||||||
|
}
|
||||||
|
flowWidget->addWidget(new DeckPreviewTagAdditionWidget(this, tr("Edit tags ...")));
|
||||||
|
layout->addWidget(flowWidget);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../../../deck/deck_loader.h"
|
||||||
|
#include "deck_preview_widget.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckPreviewWidget;
|
||||||
|
class DeckPreviewDeckTagsDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewDeckTagsDisplayWidget(DeckPreviewWidget *_parent, DeckLoader *_deckLoader);
|
||||||
|
DeckPreviewWidget *parent;
|
||||||
|
DeckLoader *deckLoader;
|
||||||
|
};
|
||||||
|
#endif // DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include "deck_preview_tag_addition_widget.h"
|
||||||
|
|
||||||
|
#include "deck_preview_tag_dialog.h"
|
||||||
|
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
DeckPreviewTagAdditionWidget::DeckPreviewTagAdditionWidget(DeckPreviewDeckTagsDisplayWidget *_parent,
|
||||||
|
const QString &_tagName)
|
||||||
|
: QWidget(_parent), parent(_parent), tagName_(_tagName)
|
||||||
|
{
|
||||||
|
// Create layout
|
||||||
|
auto *layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(5, 5, 5, 5);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
|
||||||
|
// Adjust widget size
|
||||||
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize DeckPreviewTagAdditionWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
// Calculate the size based on the tag name
|
||||||
|
QFontMetrics fm(font());
|
||||||
|
int textWidth = fm.horizontalAdvance(tagName_);
|
||||||
|
int width = textWidth + 50; // Add extra padding
|
||||||
|
int height = fm.height() + 10; // Height based on font size + padding
|
||||||
|
|
||||||
|
return QSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagAdditionWidget::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
emit tagClicked();
|
||||||
|
}
|
||||||
|
QWidget::mousePressEvent(event);
|
||||||
|
QStringList knownTags = parent->parent->parent->gatherAllTagsFromFlowWidget();
|
||||||
|
QStringList activeTags = parent->deckLoader->getTags();
|
||||||
|
|
||||||
|
DeckPreviewTagDialog dialog(knownTags, activeTags);
|
||||||
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
QStringList updatedTags = dialog.getActiveTags();
|
||||||
|
parent->deckLoader->setTags(updatedTags);
|
||||||
|
parent->deckLoader->saveToFile(parent->parent->filePath, DeckLoader::CockatriceFormat);
|
||||||
|
parent->parent->parent->refreshBannerCards();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagAdditionWidget::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
// Set background color
|
||||||
|
QColor backgroundColor = Qt::lightGray;
|
||||||
|
painter.setBrush(backgroundColor);
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
painter.drawRect(rect());
|
||||||
|
|
||||||
|
// Draw border
|
||||||
|
QColor borderColor = Qt::gray;
|
||||||
|
QPen borderPen(borderColor, 1);
|
||||||
|
painter.setPen(borderPen);
|
||||||
|
painter.drawRect(rect().adjusted(0, 0, -1, -1)); // Adjust for pen width
|
||||||
|
|
||||||
|
// Calculate font size based on widget height
|
||||||
|
QFont font = painter.font();
|
||||||
|
int fontSize = std::max(10, height() / 2); // Ensure a minimum font size of 10
|
||||||
|
font.setPointSize(fontSize);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
// Calculate text rect with margin
|
||||||
|
int margin = 10; // Left and right margins
|
||||||
|
QRect textRect(margin, 0, width() - margin * 2, height());
|
||||||
|
|
||||||
|
// Draw the text with a black border for better legibility
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
|
||||||
|
// Draw text border by offsetting
|
||||||
|
for (int dx = -1; dx <= 1; ++dx) {
|
||||||
|
for (int dy = -1; dy <= 1; ++dy) {
|
||||||
|
if (dx != 0 || dy != 0) {
|
||||||
|
painter.drawText(textRect.translated(dx, dy), Qt::AlignLeft | Qt::AlignVCenter, tagName_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the actual text
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, tagName_);
|
||||||
|
|
||||||
|
QWidget::paintEvent(event);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef DECK_PREVIEW_TAG_ADDITION_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_TAG_ADDITION_WIDGET_H
|
||||||
|
|
||||||
|
#include "deck_preview_deck_tags_display_widget.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckPreviewTagAdditionWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewTagAdditionWidget(DeckPreviewDeckTagsDisplayWidget *_parent, const QString &tagName);
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void tagClicked(); // Emitted when the tag is clicked
|
||||||
|
void tagClosed(); // Emitted when the close button is clicked
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckPreviewDeckTagsDisplayWidget *parent;
|
||||||
|
QString tagName_;
|
||||||
|
QLabel *tagLabel_;
|
||||||
|
QPushButton *closeButton_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_TAG_ADDITION_WIDGET_H
|
||||||
|
|
@ -0,0 +1,223 @@
|
||||||
|
#include "deck_preview_tag_dialog.h"
|
||||||
|
|
||||||
|
#include "deck_preview_tag_item_widget.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
DeckPreviewTagDialog::DeckPreviewTagDialog(const QStringList &knownTags, const QStringList &activeTags, QWidget *parent)
|
||||||
|
: QDialog(parent), activeTags_(activeTags)
|
||||||
|
{
|
||||||
|
resize(400, 500);
|
||||||
|
|
||||||
|
QStringList defaultTags = {
|
||||||
|
// Strategies
|
||||||
|
"🏃️ Aggro",
|
||||||
|
"🧙️ Control",
|
||||||
|
"⚔️ Midrange",
|
||||||
|
"🌀 Combo",
|
||||||
|
"🪓 Mill",
|
||||||
|
"🔒 Stax",
|
||||||
|
"🗺️ Landfall",
|
||||||
|
"🛡️ Pillowfort",
|
||||||
|
"🌱 Ramp",
|
||||||
|
"⚡ Storm",
|
||||||
|
"💀 Aristocrats",
|
||||||
|
"☠️ Reanimator",
|
||||||
|
"👹 Sacrifice",
|
||||||
|
"🔥 Burn",
|
||||||
|
"🌟 Lifegain",
|
||||||
|
"🔮 Spellslinger",
|
||||||
|
"👥 Tokens",
|
||||||
|
"🎭 Blink",
|
||||||
|
"⏳ Time Manipulation",
|
||||||
|
"🌍 Domain",
|
||||||
|
"💫 Proliferate",
|
||||||
|
"📜 Saga",
|
||||||
|
"🎲 Chaos",
|
||||||
|
"🪄 Auras",
|
||||||
|
"🔫 Pingers",
|
||||||
|
|
||||||
|
// Themes
|
||||||
|
"👑 Monarch",
|
||||||
|
"🚀 Vehicles",
|
||||||
|
"💉 Infect",
|
||||||
|
"🩸 Madness",
|
||||||
|
"🌀 Morph",
|
||||||
|
|
||||||
|
// Card Types
|
||||||
|
"⚔️ Creature",
|
||||||
|
"💎 Artifact",
|
||||||
|
"🌔 Enchantment",
|
||||||
|
"📖 Sorcery",
|
||||||
|
"⚡ Instant",
|
||||||
|
"🌌 Planeswalker",
|
||||||
|
"🌏 Land",
|
||||||
|
"🪄 Aura",
|
||||||
|
|
||||||
|
// Kindred Types
|
||||||
|
"🐉 Kindred",
|
||||||
|
"🧙 Humans",
|
||||||
|
"⚔️ Soldiers",
|
||||||
|
"🛡️ Knights",
|
||||||
|
"🎻 Bards",
|
||||||
|
"🧝 Elves",
|
||||||
|
"🌲 Dryads",
|
||||||
|
"😇 Angels",
|
||||||
|
"🎩 Wizards",
|
||||||
|
"🧛 Vampires",
|
||||||
|
"🦴 Skeletons",
|
||||||
|
"💀 Zombies",
|
||||||
|
"👹 Demons",
|
||||||
|
"👾 Eldrazi",
|
||||||
|
"🐉 Dragons",
|
||||||
|
"🐠 Merfolk",
|
||||||
|
"🦁 Cats",
|
||||||
|
"🐺 Wolves",
|
||||||
|
"🐺 Werewolves",
|
||||||
|
"🦇 Bats",
|
||||||
|
"🐀 Rats",
|
||||||
|
"🦅 Birds",
|
||||||
|
"🦗 Insects",
|
||||||
|
"🍄 Fungus",
|
||||||
|
"🐚 Sea Creatures",
|
||||||
|
"🐗 Boars",
|
||||||
|
"🦊 Foxes",
|
||||||
|
"🦄 Unicorns",
|
||||||
|
"🐘 Elephants",
|
||||||
|
"🐻 Bears",
|
||||||
|
"🦏 Rhinos",
|
||||||
|
"🦂 Scorpions",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Merge knownTags with defaultTags, ensuring no duplicates
|
||||||
|
QStringList combinedTags = defaultTags + knownTags + activeTags;
|
||||||
|
combinedTags.removeDuplicates();
|
||||||
|
|
||||||
|
// Main layout
|
||||||
|
auto *mainLayout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
// Filter bar
|
||||||
|
filterInput_ = new QLineEdit(this);
|
||||||
|
mainLayout->addWidget(filterInput_);
|
||||||
|
|
||||||
|
connect(filterInput_, &QLineEdit::textChanged, this, &DeckPreviewTagDialog::filterTags);
|
||||||
|
|
||||||
|
// Instruction label
|
||||||
|
instructionLabel = new QLabel(this);
|
||||||
|
instructionLabel->setWordWrap(true);
|
||||||
|
mainLayout->addWidget(instructionLabel);
|
||||||
|
|
||||||
|
// Tag list view
|
||||||
|
tagListView_ = new QListWidget(this);
|
||||||
|
mainLayout->addWidget(tagListView_);
|
||||||
|
|
||||||
|
// Populate combined tags
|
||||||
|
for (const auto &tag : combinedTags) {
|
||||||
|
auto *item = new QListWidgetItem(tagListView_);
|
||||||
|
auto *tagWidget = new DeckPreviewTagItemWidget(tag, activeTags.contains(tag), this);
|
||||||
|
tagListView_->addItem(item);
|
||||||
|
tagListView_->setItemWidget(item, tagWidget);
|
||||||
|
|
||||||
|
connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tag input layout
|
||||||
|
auto *addTagLayout = new QHBoxLayout();
|
||||||
|
newTagInput_ = new QLineEdit(this);
|
||||||
|
addTagButton_ = new QPushButton(this);
|
||||||
|
addTagLayout->addWidget(newTagInput_);
|
||||||
|
addTagLayout->addWidget(addTagButton_);
|
||||||
|
mainLayout->addLayout(addTagLayout);
|
||||||
|
|
||||||
|
connect(addTagButton_, &QPushButton::clicked, this, &DeckPreviewTagDialog::addTag);
|
||||||
|
|
||||||
|
// OK and Cancel buttons
|
||||||
|
auto *buttonLayout = new QHBoxLayout();
|
||||||
|
okButton = new QPushButton(this);
|
||||||
|
cancelButton = new QPushButton(this);
|
||||||
|
buttonLayout->addStretch();
|
||||||
|
buttonLayout->addWidget(okButton);
|
||||||
|
buttonLayout->addWidget(cancelButton);
|
||||||
|
mainLayout->addLayout(buttonLayout);
|
||||||
|
|
||||||
|
connect(okButton, &QPushButton::clicked, this, &DeckPreviewTagDialog::accept);
|
||||||
|
connect(cancelButton, &QPushButton::clicked, this, &DeckPreviewTagDialog::reject);
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDialog::retranslateUi()
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Deck Tags Manager"));
|
||||||
|
instructionLabel->setText(tr("Manage your deck tags. Check or uncheck tags as needed, or add new ones:"));
|
||||||
|
newTagInput_->setPlaceholderText(tr("Add a new tag (e.g., Aggro️)"));
|
||||||
|
addTagButton_->setText(tr("Add Tag"));
|
||||||
|
filterInput_->setPlaceholderText(tr("Filter tags..."));
|
||||||
|
okButton->setText(tr("OK"));
|
||||||
|
cancelButton->setText(tr("Cancel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList DeckPreviewTagDialog::getActiveTags() const
|
||||||
|
{
|
||||||
|
return activeTags_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDialog::addTag()
|
||||||
|
{
|
||||||
|
QString newTag = newTagInput_->text().trimmed();
|
||||||
|
if (newTag.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, tr("Invalid Input"), tr("Tag name cannot be empty!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent duplicate tags
|
||||||
|
for (int i = 0; i < tagListView_->count(); ++i) {
|
||||||
|
auto *item = tagListView_->item(i);
|
||||||
|
auto *tagWidget = qobject_cast<DeckPreviewTagItemWidget *>(tagListView_->itemWidget(item));
|
||||||
|
if (tagWidget && tagWidget->checkBox()->text() == newTag) {
|
||||||
|
QMessageBox::warning(this, tr("Duplicate Tag"), tr("This tag already exists."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the new tag
|
||||||
|
auto *item = new QListWidgetItem(tagListView_);
|
||||||
|
auto *tagWidget = new DeckPreviewTagItemWidget(newTag, true, this);
|
||||||
|
tagListView_->addItem(item);
|
||||||
|
tagListView_->setItemWidget(item, tagWidget);
|
||||||
|
activeTags_.append(newTag);
|
||||||
|
|
||||||
|
connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged);
|
||||||
|
|
||||||
|
// Clear the input field
|
||||||
|
newTagInput_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDialog::filterTags(const QString &text)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tagListView_->count(); ++i) {
|
||||||
|
auto *item = tagListView_->item(i);
|
||||||
|
auto *tagWidget = qobject_cast<DeckPreviewTagItemWidget *>(tagListView_->itemWidget(item));
|
||||||
|
if (tagWidget) {
|
||||||
|
bool matches = tagWidget->checkBox()->text().contains(text, Qt::CaseInsensitive);
|
||||||
|
item->setHidden(!matches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDialog::onCheckboxStateChanged()
|
||||||
|
{
|
||||||
|
activeTags_.clear();
|
||||||
|
for (int i = 0; i < tagListView_->count(); ++i) {
|
||||||
|
auto *item = tagListView_->item(i);
|
||||||
|
auto *tagWidget = qobject_cast<DeckPreviewTagItemWidget *>(tagListView_->itemWidget(item));
|
||||||
|
if (tagWidget && tagWidget->checkBox()->isChecked()) {
|
||||||
|
activeTags_.append(tagWidget->checkBox()->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef DECK_PREVIEW_TAG_DIALOG_H
|
||||||
|
#define DECK_PREVIEW_TAG_DIALOG_H
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class DeckPreviewTagDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewTagDialog(const QStringList &knownTags,
|
||||||
|
const QStringList &activeTags,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
QStringList getActiveTags() const;
|
||||||
|
void filterTags(const QString &text);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void addTag();
|
||||||
|
void onCheckboxStateChanged();
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *instructionLabel;
|
||||||
|
QListWidget *tagListView_;
|
||||||
|
QLineEdit *filterInput_;
|
||||||
|
QLineEdit *newTagInput_;
|
||||||
|
QPushButton *addTagButton_;
|
||||||
|
QPushButton *okButton;
|
||||||
|
QPushButton *cancelButton;
|
||||||
|
QStringList activeTags_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_TAG_DIALOG_H
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
#include "deck_preview_tag_display_widget.h"
|
||||||
|
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
DeckPreviewTagDisplayWidget::DeckPreviewTagDisplayWidget(QWidget *parent, const QString &_tagName)
|
||||||
|
: QWidget(parent), tagName(_tagName), isSelected(false)
|
||||||
|
{
|
||||||
|
// Create layout
|
||||||
|
auto *layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(5, 5, 5, 5);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
|
||||||
|
// Add a stretch spacer for text and close button separation
|
||||||
|
// layout->addStretch(); // Ensures the close button stays at the far-right side
|
||||||
|
|
||||||
|
// Create close button
|
||||||
|
// closeButton = new QPushButton("x", this);
|
||||||
|
// closeButton->setFixedSize(16, 16); // Small square button
|
||||||
|
// closeButton->setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
|
// Set font for close button to ensure the "x" appears correctly
|
||||||
|
// QFont closeButtonFont = closeButton->font();
|
||||||
|
// closeButtonFont.setPointSize(10); // Adjust the size to make the "x" clear
|
||||||
|
// closeButton->setFont(closeButtonFont);
|
||||||
|
|
||||||
|
// layout->addWidget(closeButton);
|
||||||
|
|
||||||
|
// Adjust widget size
|
||||||
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
// Connect close button to the remove signal
|
||||||
|
// connect(closeButton, &QPushButton::clicked, this, &DeckPreviewTagDisplayWidget::tagClosed);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize DeckPreviewTagDisplayWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
// Calculate the size based on the tag name and close button
|
||||||
|
QFontMetrics fm(font());
|
||||||
|
int textWidth = fm.horizontalAdvance(tagName);
|
||||||
|
int width = textWidth + 50; // Add extra padding
|
||||||
|
int height = fm.height() + 10; // Height based on font size + padding
|
||||||
|
|
||||||
|
return QSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
setSelected(!isSelected);
|
||||||
|
emit tagClicked();
|
||||||
|
}
|
||||||
|
QWidget::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDisplayWidget::setSelected(bool selected)
|
||||||
|
{
|
||||||
|
isSelected = selected;
|
||||||
|
update(); // Trigger a repaint
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewTagDisplayWidget::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
// Set background color
|
||||||
|
QColor backgroundColor = isSelected ? QColor(173, 216, 230) : Qt::white;
|
||||||
|
painter.setBrush(backgroundColor);
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
painter.drawRect(rect());
|
||||||
|
|
||||||
|
// Draw border
|
||||||
|
QColor borderColor = isSelected ? Qt::blue : Qt::gray;
|
||||||
|
QPen borderPen(borderColor, isSelected ? 2 : 1);
|
||||||
|
painter.setPen(borderPen);
|
||||||
|
painter.drawRect(rect().adjusted(0, 0, -1, -1)); // Adjust for pen width
|
||||||
|
|
||||||
|
// Calculate font size based on widget height
|
||||||
|
QFont font = painter.font();
|
||||||
|
int fontSize = std::max(10, height() / 2); // Ensure a minimum font size of 10
|
||||||
|
font.setPointSize(fontSize);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
// Calculate text rect to avoid overlap with the close button
|
||||||
|
// int closeButtonWidth = closeButton->width();
|
||||||
|
int margin = 10; // Left and right margins
|
||||||
|
QRect textRect(margin, 0, width() - margin * 2, height());
|
||||||
|
|
||||||
|
// Draw the text with a black border for better legibility
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
|
||||||
|
// Draw text border by offsetting
|
||||||
|
for (int dx = -1; dx <= 1; ++dx) {
|
||||||
|
for (int dy = -1; dy <= 1; ++dy) {
|
||||||
|
if (dx != 0 || dy != 0) {
|
||||||
|
painter.drawText(textRect.translated(dx, dy), Qt::AlignLeft | Qt::AlignVCenter, tagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the actual text
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, tagName);
|
||||||
|
|
||||||
|
QWidget::paintEvent(event);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef DECK_PREVIEW_TAG_DISPLAY_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_TAG_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QString>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckPreviewTagDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor for DeckPreviewTagDisplayWidget.
|
||||||
|
* @param parent The parent widget.
|
||||||
|
* @param tagName The name of the tag to display.
|
||||||
|
*/
|
||||||
|
explicit DeckPreviewTagDisplayWidget(QWidget *parent = nullptr, const QString &tagName = "");
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
QString getTagName() const
|
||||||
|
{
|
||||||
|
return tagName;
|
||||||
|
}
|
||||||
|
bool getSelected() const
|
||||||
|
{
|
||||||
|
return isSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the selected state of the tag.
|
||||||
|
* @param selected True if the tag is selected, false otherwise.
|
||||||
|
*/
|
||||||
|
void setSelected(bool selected);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* @brief Emitted when the tag is clicked.
|
||||||
|
*/
|
||||||
|
void tagClicked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Emitted when the close button is clicked.
|
||||||
|
*/
|
||||||
|
void tagClosed();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Custom paint event for drawing the widget.
|
||||||
|
* @param event The paint event.
|
||||||
|
*/
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Custom mouse press event handler.
|
||||||
|
* @param event The mouse event.
|
||||||
|
*/
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *tagLabel; ///< Label for displaying the tag name.
|
||||||
|
QPushButton *closeButton; ///< Button to close/remove the tag.
|
||||||
|
QString tagName; ///< The name of the tag.
|
||||||
|
bool isSelected; ///< Indicates whether the tag is selected.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_TAG_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "deck_preview_tag_item_widget.h"
|
||||||
|
|
||||||
|
DeckPreviewTagItemWidget::DeckPreviewTagItemWidget(const QString &tagName, bool isChecked, QWidget *parent)
|
||||||
|
: QWidget(parent), checkBox_(new QCheckBox(this))
|
||||||
|
{
|
||||||
|
auto *layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
|
||||||
|
checkBox_->setText(tagName); // Set the tag name as the checkbox label
|
||||||
|
checkBox_->setChecked(isChecked); // Set the initial state of the checkbox
|
||||||
|
|
||||||
|
layout->addWidget(checkBox_); // Add the checkbox to the layout
|
||||||
|
setLayout(layout); // Set the layout of this widget
|
||||||
|
}
|
||||||
|
|
||||||
|
QCheckBox *DeckPreviewTagItemWidget::checkBox() const
|
||||||
|
{
|
||||||
|
return checkBox_; // Return the checkbox widget
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef DECK_PREVIEW_TAG_ITEM_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_TAG_ITEM_WIDGET_H
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckPreviewTagItemWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
// Constructor: Initializes the tag item widget with a tag name and initial checkbox state
|
||||||
|
DeckPreviewTagItemWidget(const QString &tagName, bool isChecked, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
// Accessor for the checkbox widget
|
||||||
|
QCheckBox *checkBox() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QCheckBox *checkBox_; // Checkbox to represent the tag's state
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_TAG_ITEM_WIDGET_H
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include "deck_preview_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../cards/deck_preview_card_picture_widget.h"
|
||||||
|
#include "deck_preview_deck_tags_display_widget.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
DeckPreviewWidget::DeckPreviewWidget(VisualDeckStorageWidget *_parent, const QString &_filePath)
|
||||||
|
: QWidget(_parent), parent(_parent), filePath(_filePath)
|
||||||
|
{
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
deckLoader = new DeckLoader();
|
||||||
|
deckLoader->loadFromFile(filePath, DeckLoader::CockatriceFormat);
|
||||||
|
|
||||||
|
auto bannerCard = deckLoader->getBannerCard().first.isEmpty()
|
||||||
|
? CardInfoPtr()
|
||||||
|
: CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
|
||||||
|
deckLoader->getBannerCard().first, deckLoader->getBannerCard().second);
|
||||||
|
|
||||||
|
bannerCardDisplayWidget = new DeckPreviewCardPictureWidget(this);
|
||||||
|
|
||||||
|
connect(bannerCardDisplayWidget, &DeckPreviewCardPictureWidget::imageClicked, this,
|
||||||
|
&DeckPreviewWidget::imageClickedEvent);
|
||||||
|
connect(bannerCardDisplayWidget, &DeckPreviewCardPictureWidget::imageDoubleClicked, this,
|
||||||
|
&DeckPreviewWidget::imageDoubleClickedEvent);
|
||||||
|
|
||||||
|
bannerCardDisplayWidget->setCard(bannerCard);
|
||||||
|
bannerCardDisplayWidget->setOverlayText(
|
||||||
|
deckLoader->getName().isEmpty() ? QFileInfo(deckLoader->getLastFileName()).fileName() : deckLoader->getName());
|
||||||
|
bannerCardDisplayWidget->setFontSize(24);
|
||||||
|
setFilePath(deckLoader->getLastFileName());
|
||||||
|
|
||||||
|
colorIdentityWidget = new DeckPreviewColorIdentityWidget(getColorIdentity());
|
||||||
|
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckLoader);
|
||||||
|
|
||||||
|
layout->addWidget(bannerCardDisplayWidget);
|
||||||
|
layout->addWidget(colorIdentityWidget);
|
||||||
|
layout->addWidget(deckTagsDisplayWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DeckPreviewWidget::getColorIdentity()
|
||||||
|
{
|
||||||
|
QStringList cardList = deckLoader->getCardList();
|
||||||
|
if (cardList.isEmpty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<QChar> colorSet; // A set to collect unique color symbols (e.g., W, U, B, R, G)
|
||||||
|
|
||||||
|
for (const QString &cardName : cardList) {
|
||||||
|
CardInfoPtr currentCard = CardDatabaseManager::getInstance()->getCard(cardName);
|
||||||
|
if (currentCard) {
|
||||||
|
QString colors = currentCard->getColors(); // Assuming this returns something like "WUB"
|
||||||
|
for (const QChar &color : colors) {
|
||||||
|
colorSet.insert(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the color identity is in WUBRG order
|
||||||
|
QString colorIdentity;
|
||||||
|
const QString wubrgOrder = "WUBRG";
|
||||||
|
for (const QChar &color : wubrgOrder) {
|
||||||
|
if (colorSet.contains(color)) {
|
||||||
|
colorIdentity.append(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return colorIdentity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewWidget::setFilePath(const QString &_filePath)
|
||||||
|
{
|
||||||
|
filePath = _filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
||||||
|
{
|
||||||
|
Q_UNUSED(instance);
|
||||||
|
emit deckPreviewClicked(event, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckPreviewWidget::imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
||||||
|
{
|
||||||
|
Q_UNUSED(instance);
|
||||||
|
emit deckPreviewDoubleClicked(event, this);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef DECK_PREVIEW_WIDGET_H
|
||||||
|
#define DECK_PREVIEW_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../../../deck/deck_loader.h"
|
||||||
|
#include "../../cards/deck_preview_card_picture_widget.h"
|
||||||
|
#include "../visual_deck_storage_widget.h"
|
||||||
|
#include "deck_preview_color_identity_widget.h"
|
||||||
|
#include "deck_preview_deck_tags_display_widget.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class VisualDeckStorageWidget;
|
||||||
|
class DeckPreviewDeckTagsDisplayWidget;
|
||||||
|
class DeckPreviewWidget final : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DeckPreviewWidget(VisualDeckStorageWidget *_parent, const QString &_filePath);
|
||||||
|
QString getColorIdentity();
|
||||||
|
|
||||||
|
VisualDeckStorageWidget *parent;
|
||||||
|
QVBoxLayout *layout;
|
||||||
|
QString filePath;
|
||||||
|
DeckLoader *deckLoader;
|
||||||
|
DeckPreviewCardPictureWidget *bannerCardDisplayWidget;
|
||||||
|
DeckPreviewColorIdentityWidget *colorIdentityWidget;
|
||||||
|
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void deckPreviewClicked(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
|
void deckPreviewDoubleClicked(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setFilePath(const QString &filePath);
|
||||||
|
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||||
|
void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_PREVIEW_WIDGET_H
|
||||||
|
|
@ -38,22 +38,23 @@ QString VisualDeckStorageSearchWidget::getSearchText()
|
||||||
return searchBar->text();
|
return searchBar->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList VisualDeckStorageSearchWidget::filterFiles(const QStringList &files, const QString &searchText)
|
QList<DeckPreviewWidget *> VisualDeckStorageSearchWidget::filterFiles(QList<DeckPreviewWidget *> &widgets,
|
||||||
|
const QString &searchText)
|
||||||
{
|
{
|
||||||
if (searchText.isEmpty() || searchText.isNull()) {
|
if (searchText.isEmpty() || searchText.isNull()) {
|
||||||
return files;
|
return widgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList filteredFiles;
|
QList<DeckPreviewWidget *> filteredWidgets;
|
||||||
|
|
||||||
for (const auto &file : files) {
|
for (const auto &file : widgets) {
|
||||||
QFileInfo fileInfo(file);
|
QFileInfo fileInfo(file->filePath);
|
||||||
QString fileName = fileInfo.fileName().toLower();
|
QString fileName = fileInfo.fileName().toLower();
|
||||||
|
|
||||||
if (fileName.contains(searchText.toLower())) {
|
if (fileName.contains(searchText.toLower())) {
|
||||||
filteredFiles << file;
|
filteredWidgets << file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredFiles;
|
return filteredWidgets;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class VisualDeckStorageSearchWidget : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit VisualDeckStorageSearchWidget(VisualDeckStorageWidget *parent);
|
explicit VisualDeckStorageSearchWidget(VisualDeckStorageWidget *parent);
|
||||||
QString getSearchText();
|
QString getSearchText();
|
||||||
QStringList filterFiles(const QStringList &files, const QString &searchText);
|
QList<DeckPreviewWidget *> filterFiles(QList<DeckPreviewWidget *> &widgets, const QString &searchText);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHBoxLayout *layout;
|
QHBoxLayout *layout;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include "visual_deck_storage_sort_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../settings/cache_settings.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a PrintingSelectorCardSortWidget for searching cards by set name or set code.
|
||||||
|
*
|
||||||
|
* This widget provides a search bar that allows users to search for cards by either their set name
|
||||||
|
* or set code. It uses a debounced timer to trigger the search action after the user stops typing.
|
||||||
|
*
|
||||||
|
* @param parent The parent PrintingSelector widget that will handle the search results.
|
||||||
|
*/
|
||||||
|
VisualDeckStorageSortWidget::VisualDeckStorageSortWidget(VisualDeckStorageWidget *parent)
|
||||||
|
: parent(parent), sortOrder(Alphabetical)
|
||||||
|
{
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
// Initialize the ComboBox
|
||||||
|
sortComboBox = new QComboBox(this);
|
||||||
|
layout->addWidget(sortComboBox);
|
||||||
|
|
||||||
|
// Set the current sort order
|
||||||
|
sortComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageSortingOrder());
|
||||||
|
|
||||||
|
// Connect sorting change signal to refresh the file list
|
||||||
|
connect(sortComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
&VisualDeckStorageSortWidget::updateSortOrder);
|
||||||
|
connect(this, &VisualDeckStorageSortWidget::sortOrderChanged, parent, &VisualDeckStorageWidget::updateSortOrder);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckStorageSortWidget::retranslateUi()
|
||||||
|
{
|
||||||
|
// Block signals to avoid triggering unnecessary updates while changing text
|
||||||
|
sortComboBox->blockSignals(true);
|
||||||
|
|
||||||
|
// Clear and repopulate the ComboBox with translated items
|
||||||
|
sortComboBox->clear();
|
||||||
|
sortComboBox->addItem(tr("Sort Alphabetically (Deck Name)"), ByName);
|
||||||
|
sortComboBox->addItem(tr("Sort Alphabetically (Filename)"), Alphabetical);
|
||||||
|
sortComboBox->addItem(tr("Sort by Last Modified"), ByLastModified);
|
||||||
|
sortComboBox->addItem(tr("Sort by Last Loaded"), ByLastLoaded);
|
||||||
|
|
||||||
|
// Restore the current index
|
||||||
|
sortComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageSortingOrder());
|
||||||
|
|
||||||
|
// Re-enable signals
|
||||||
|
sortComboBox->blockSignals(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckStorageSortWidget::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::showEvent(event);
|
||||||
|
sortComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageSortingOrder());
|
||||||
|
updateSortOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckStorageSortWidget::updateSortOrder()
|
||||||
|
{
|
||||||
|
sortOrder = static_cast<SortOrder>(sortComboBox->currentIndex());
|
||||||
|
SettingsCache::instance().setVisualDeckStorageSortingOrder(sortComboBox->currentIndex());
|
||||||
|
emit sortOrderChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (!widget1 || !widget2) {
|
||||||
|
return false; // Handle null pointers gracefully
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo info1(widget1->filePath);
|
||||||
|
QFileInfo info2(widget2->filePath);
|
||||||
|
|
||||||
|
switch (sortOrder) {
|
||||||
|
case ByName:
|
||||||
|
return widget1->deckLoader->getName() < widget2->deckLoader->getName();
|
||||||
|
case Alphabetical:
|
||||||
|
return info1.fileName().toLower() < info2.fileName().toLower();
|
||||||
|
case ByLastModified:
|
||||||
|
return info1.lastModified() > info2.lastModified();
|
||||||
|
case ByLastLoaded:
|
||||||
|
return widget1->deckLoader->getLastLoadedTimestamp() > widget2->deckLoader->getLastLoadedTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Default case, no sorting applied
|
||||||
|
});
|
||||||
|
|
||||||
|
return widgets;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef VISUAL_DECK_STORAGE_SORT_WIDGET_H
|
||||||
|
#define VISUAL_DECK_STORAGE_SORT_WIDGET_H
|
||||||
|
|
||||||
|
#include "visual_deck_storage_widget.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class VisualDeckStorageWidget;
|
||||||
|
class VisualDeckStorageSortWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VisualDeckStorageSortWidget(VisualDeckStorageWidget *parent);
|
||||||
|
void retranslateUi();
|
||||||
|
void updateSortOrder();
|
||||||
|
QString getSearchText();
|
||||||
|
QList<DeckPreviewWidget *> &filterFiles(QList<DeckPreviewWidget *> &widgets);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sortOrderChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum SortOrder
|
||||||
|
{
|
||||||
|
ByName,
|
||||||
|
Alphabetical,
|
||||||
|
ByLastModified,
|
||||||
|
ByLastLoaded,
|
||||||
|
};
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
VisualDeckStorageWidget *parent;
|
||||||
|
SortOrder sortOrder; // Current sorting option
|
||||||
|
QComboBox *sortComboBox;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VISUAL_DECK_STORAGE_SORT_WIDGET_H
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include "visual_deck_storage_tag_filter_widget.h"
|
||||||
|
|
||||||
|
#include "../general/layout_containers/flow_widget.h"
|
||||||
|
#include "deck_preview/deck_preview_tag_addition_widget.h"
|
||||||
|
#include "deck_preview/deck_preview_tag_display_widget.h"
|
||||||
|
#include "deck_preview/deck_preview_widget.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
VisualDeckStorageTagFilterWidget::VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent)
|
||||||
|
: QWidget(_parent), parent(_parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
|
// Create layout
|
||||||
|
auto *layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(5, 5, 5, 5);
|
||||||
|
layout->setSpacing(5);
|
||||||
|
|
||||||
|
setFixedHeight(100);
|
||||||
|
|
||||||
|
auto *flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
|
layout->addWidget(flowWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DeckPreviewWidget *>
|
||||||
|
VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList<DeckPreviewWidget *> &deckPreviews) const
|
||||||
|
{
|
||||||
|
// Collect selected tags from DeckPreviewTagDisplayWidget
|
||||||
|
QStringList selectedTags;
|
||||||
|
foreach (DeckPreviewTagDisplayWidget *tagWidget, findChildren<DeckPreviewTagDisplayWidget *>()) {
|
||||||
|
if (tagWidget->getSelected()) {
|
||||||
|
selectedTags.append(tagWidget->getTagName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no tags are selected, return all decks
|
||||||
|
if (selectedTags.isEmpty()) {
|
||||||
|
return deckPreviews;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter DeckPreviewWidgets that contain all of the selected tags
|
||||||
|
QList<DeckPreviewWidget *> filteredDecks;
|
||||||
|
for (DeckPreviewWidget *deckPreview : deckPreviews) {
|
||||||
|
QStringList deckTags = deckPreview->deckLoader->getTags();
|
||||||
|
|
||||||
|
// Check if all selectedTags are in deckTags
|
||||||
|
bool allTagsPresent = std::all_of(selectedTags.begin(), selectedTags.end(),
|
||||||
|
[&deckTags](const QString &tag) { return deckTags.contains(tag); });
|
||||||
|
|
||||||
|
if (allTagsPresent) {
|
||||||
|
filteredDecks.append(deckPreview);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredDecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QStringList &tags)
|
||||||
|
{
|
||||||
|
// Iterate through all DeckPreviewTagDisplayWidgets
|
||||||
|
foreach (DeckPreviewTagDisplayWidget *tagWidget, findChildren<DeckPreviewTagDisplayWidget *>()) {
|
||||||
|
// If the tag is not in the provided tags list, remove the widget
|
||||||
|
if (!tags.contains(tagWidget->getTagName())) {
|
||||||
|
auto *flowWidget = findChild<FlowWidget *>();
|
||||||
|
flowWidget->removeWidget(tagWidget);
|
||||||
|
tagWidget->deleteLater(); // Safely delete the widget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckStorageTagFilterWidget::addTagsIfNotPresent(const QStringList &tags)
|
||||||
|
{
|
||||||
|
for (const QString &tag : tags) {
|
||||||
|
addTagIfNotPresent(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckStorageTagFilterWidget::addTagIfNotPresent(const QString &tag)
|
||||||
|
{
|
||||||
|
// Check if the tag already exists in the flow widget
|
||||||
|
bool tagExists = false;
|
||||||
|
foreach (DeckPreviewTagDisplayWidget *tagWidget, findChildren<DeckPreviewTagDisplayWidget *>()) {
|
||||||
|
if (tagWidget->getTagName() == tag) {
|
||||||
|
tagExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the tag doesn't exist, add a new DeckPreviewTagDisplayWidget
|
||||||
|
if (!tagExists) {
|
||||||
|
auto *newTagWidget = new DeckPreviewTagDisplayWidget(this, tag);
|
||||||
|
connect(newTagWidget, &DeckPreviewTagDisplayWidget::tagClicked, parent,
|
||||||
|
&VisualDeckStorageWidget::refreshBannerCards);
|
||||||
|
auto *flowWidget = findChild<FlowWidget *>();
|
||||||
|
flowWidget->addWidget(newTagWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H
|
||||||
|
#define VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H
|
||||||
|
|
||||||
|
#include "visual_deck_storage_widget.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class VisualDeckStorageWidget;
|
||||||
|
class VisualDeckStorageTagFilterWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent);
|
||||||
|
void refreshTags();
|
||||||
|
QList<DeckPreviewWidget *> filterDecksBySelectedTags(const QList<DeckPreviewWidget *> &deckPreviews) const;
|
||||||
|
void removeTagsNotInList(const QStringList &tags);
|
||||||
|
void addTagsIfNotPresent(const QStringList &tags);
|
||||||
|
void addTagIfNotPresent(const QString &tag);
|
||||||
|
VisualDeckStorageWidget *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H
|
||||||
|
|
@ -3,14 +3,17 @@
|
||||||
#include "../../../../deck/deck_loader.h"
|
#include "../../../../deck/deck_loader.h"
|
||||||
#include "../../../../game/cards/card_database_manager.h"
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
#include "../../../../settings/cache_settings.h"
|
#include "../../../../settings/cache_settings.h"
|
||||||
|
#include "deck_preview/deck_preview_widget.h"
|
||||||
#include "visual_deck_storage_search_widget.h"
|
#include "visual_deck_storage_search_widget.h"
|
||||||
|
#include "visual_deck_storage_sort_widget.h"
|
||||||
|
#include "visual_deck_storage_tag_filter_widget.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), sortOrder(Alphabetical)
|
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
deckListModel = new DeckListModel(this);
|
deckListModel = new DeckListModel(this);
|
||||||
deckListModel->setObjectName("visualDeckModel");
|
deckListModel->setObjectName("visualDeckModel");
|
||||||
|
|
@ -18,27 +21,24 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
||||||
layout = new QVBoxLayout();
|
layout = new QVBoxLayout();
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
// ComboBox for sorting options
|
searchAndSortLayout = new QHBoxLayout();
|
||||||
sortComboBox = new QComboBox(this);
|
|
||||||
sortComboBox->addItem("Sort Alphabetically (Filename)", Alphabetical);
|
|
||||||
sortComboBox->addItem("Sort by Last Modified", ByLastModified);
|
|
||||||
sortComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageSortingOrder());
|
|
||||||
|
|
||||||
|
sortWidget = new VisualDeckStorageSortWidget(this);
|
||||||
searchWidget = new VisualDeckStorageSearchWidget(this);
|
searchWidget = new VisualDeckStorageSearchWidget(this);
|
||||||
|
tagFilterWidget = new VisualDeckStorageTagFilterWidget(this);
|
||||||
|
deckPreviewColorIdentityFilterWidget = new DeckPreviewColorIdentityFilterWidget(this);
|
||||||
|
|
||||||
// Add combo box to the main layout
|
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
|
||||||
layout->addWidget(sortComboBox);
|
searchAndSortLayout->addWidget(sortWidget);
|
||||||
layout->addWidget(searchWidget);
|
searchAndSortLayout->addWidget(searchWidget);
|
||||||
|
layout->addLayout(searchAndSortLayout);
|
||||||
|
layout->addWidget(tagFilterWidget);
|
||||||
|
|
||||||
flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||||
layout->addWidget(flowWidget);
|
layout->addWidget(flowWidget);
|
||||||
|
|
||||||
cardSizeWidget = new CardSizeWidget(this, flowWidget, SettingsCache::instance().getVisualDeckStorageCardSize());
|
cardSizeWidget = new CardSizeWidget(this, flowWidget, SettingsCache::instance().getVisualDeckStorageCardSize());
|
||||||
layout->addWidget(cardSizeWidget);
|
layout->addWidget(cardSizeWidget);
|
||||||
|
|
||||||
// Connect sorting change signal to refresh the file list
|
|
||||||
connect(sortComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
|
||||||
&VisualDeckStorageWidget::updateSortOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualDeckStorageWidget::showEvent(QShowEvent *event)
|
void VisualDeckStorageWidget::showEvent(QShowEvent *event)
|
||||||
|
|
@ -49,24 +49,23 @@ void VisualDeckStorageWidget::showEvent(QShowEvent *event)
|
||||||
|
|
||||||
void VisualDeckStorageWidget::updateSortOrder()
|
void VisualDeckStorageWidget::updateSortOrder()
|
||||||
{
|
{
|
||||||
sortOrder = static_cast<SortOrder>(sortComboBox->currentData().toInt());
|
|
||||||
SettingsCache::instance().setVisualDeckStorageSortingOrder(sortComboBox->currentData().toInt());
|
|
||||||
refreshBannerCards(); // Refresh the banner cards with the new sort order
|
refreshBannerCards(); // Refresh the banner cards with the new sort order
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualDeckStorageWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
void VisualDeckStorageWidget::deckPreviewClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance)
|
||||||
{
|
{
|
||||||
emit imageClicked(event, instance);
|
emit deckPreviewClicked(event, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualDeckStorageWidget::imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
void VisualDeckStorageWidget::deckPreviewDoubleClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance)
|
||||||
{
|
{
|
||||||
emit imageDoubleClicked(event, instance);
|
emit deckPreviewDoubleClicked(event, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualDeckStorageWidget::refreshBannerCards()
|
void VisualDeckStorageWidget::refreshBannerCards()
|
||||||
{
|
{
|
||||||
QStringList allFiles;
|
QStringList allFiles;
|
||||||
|
QList<DeckPreviewWidget *> allDecks;
|
||||||
|
|
||||||
// QDirIterator with QDir::Files and QDir::NoSymLinks ensures only files are listed (no directories or symlinks)
|
// 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 it(SettingsCache::instance().getDeckPath(), QDir::Files | QDir::NoSymLinks,
|
||||||
|
|
@ -76,46 +75,71 @@ void VisualDeckStorageWidget::refreshBannerCards()
|
||||||
allFiles << it.next(); // Add each file path to the list
|
allFiles << it.next(); // Add each file path to the list
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort files based on the current sort order
|
foreach (const QString &file, allFiles) {
|
||||||
std::sort(allFiles.begin(), allFiles.end(), [this](const QString &file1, const QString &file2) {
|
auto *display = new DeckPreviewWidget(this, file);
|
||||||
QFileInfo info1(file1);
|
|
||||||
QFileInfo info2(file2);
|
|
||||||
|
|
||||||
switch (sortOrder) {
|
connect(display, &DeckPreviewWidget::deckPreviewClicked, this,
|
||||||
case Alphabetical:
|
&VisualDeckStorageWidget::deckPreviewClickedEvent);
|
||||||
return info1.fileName().toLower() < info2.fileName().toLower();
|
connect(display, &DeckPreviewWidget::deckPreviewDoubleClicked, this,
|
||||||
case ByLastModified:
|
&VisualDeckStorageWidget::deckPreviewDoubleClickedEvent);
|
||||||
return info1.lastModified() > info2.lastModified();
|
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, display->bannerCardDisplayWidget,
|
||||||
}
|
&CardInfoPictureWidget::setScaleFactor);
|
||||||
|
display->bannerCardDisplayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||||
|
allDecks.append(display);
|
||||||
|
}
|
||||||
|
|
||||||
return false; // Default case
|
auto filteredByColorIdentity =
|
||||||
});
|
deckPreviewColorIdentityFilterWidget->filterWidgets(sortWidget->filterFiles(allDecks));
|
||||||
|
auto filteredByTags = tagFilterWidget->filterDecksBySelectedTags(filteredByColorIdentity);
|
||||||
|
auto filteredFiles = searchWidget->filterFiles(filteredByTags, searchWidget->getSearchText());
|
||||||
|
|
||||||
auto filteredFiles = searchWidget->filterFiles(allFiles, searchWidget->getSearchText());
|
tagFilterWidget->removeTagsNotInList(gatherAllTags(filteredFiles));
|
||||||
|
tagFilterWidget->addTagsIfNotPresent(gatherAllTags(filteredFiles));
|
||||||
|
|
||||||
flowWidget->clearLayout(); // Clear existing widgets in the flow layout
|
flowWidget->clearLayout(); // Clear existing widgets in the flow layout
|
||||||
|
|
||||||
foreach (const QString &file, filteredFiles) {
|
foreach (DeckPreviewWidget *deck, filteredFiles) {
|
||||||
auto deckLoader = new DeckLoader();
|
flowWidget->addWidget(deck);
|
||||||
deckLoader->loadFromFile(file, DeckLoader::CockatriceFormat);
|
|
||||||
deckListModel->setDeckList(new DeckLoader(*deckLoader));
|
|
||||||
|
|
||||||
auto *display = new DeckPreviewCardPictureWidget(flowWidget, false);
|
|
||||||
auto bannerCard = deckLoader->getBannerCard().isEmpty()
|
|
||||||
? CardInfoPtr()
|
|
||||||
: CardDatabaseManager::getInstance()->getCard(deckLoader->getBannerCard());
|
|
||||||
display->setCard(bannerCard);
|
|
||||||
display->setOverlayText(deckLoader->getName().isEmpty() ? QFileInfo(deckLoader->getLastFileName()).fileName()
|
|
||||||
: deckLoader->getName());
|
|
||||||
display->setFontSize(24);
|
|
||||||
display->setFilePath(deckLoader->getLastFileName());
|
|
||||||
|
|
||||||
connect(display, &DeckPreviewCardPictureWidget::imageClicked, this,
|
|
||||||
&VisualDeckStorageWidget::imageClickedEvent);
|
|
||||||
connect(display, &DeckPreviewCardPictureWidget::imageDoubleClicked, this,
|
|
||||||
&VisualDeckStorageWidget::imageDoubleClickedEvent);
|
|
||||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, display, &CardInfoPictureWidget::setScaleFactor);
|
|
||||||
display->setScaleFactor(cardSizeWidget->getSlider()->value());
|
|
||||||
flowWidget->addWidget(display);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit bannerCardsRefreshed();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList VisualDeckStorageWidget::gatherAllTagsFromFlowWidget() const
|
||||||
|
{
|
||||||
|
QStringList allTags;
|
||||||
|
|
||||||
|
if (flowWidget) {
|
||||||
|
// Iterate through all DeckPreviewWidgets
|
||||||
|
foreach (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 VisualDeckStorageWidget::gatherAllTags(const QList<DeckPreviewWidget *> &allDecks)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
allTags.removeDuplicates();
|
||||||
|
|
||||||
|
return allTags;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,20 @@
|
||||||
|
|
||||||
#include "../../../../deck/deck_list_model.h"
|
#include "../../../../deck/deck_list_model.h"
|
||||||
#include "../../../../deck/deck_view.h"
|
#include "../../../../deck/deck_view.h"
|
||||||
#include "../../../ui/widgets/cards/deck_preview_card_picture_widget.h"
|
|
||||||
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
|
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
|
||||||
#include "../cards/card_size_widget.h"
|
#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_search_widget.h"
|
#include "visual_deck_storage_search_widget.h"
|
||||||
|
#include "visual_deck_storage_sort_widget.h"
|
||||||
|
#include "visual_deck_storage_tag_filter_widget.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
|
|
||||||
class VisualDeckStorageSearchWidget;
|
class VisualDeckStorageSearchWidget;
|
||||||
|
class VisualDeckStorageSortWidget;
|
||||||
|
class VisualDeckStorageTagFilterWidget;
|
||||||
|
class DeckPreviewColorIdentityFilterWidget;
|
||||||
class VisualDeckStorageWidget final : public QWidget
|
class VisualDeckStorageWidget final : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -20,31 +25,30 @@ public:
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void deckPreviewClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void deckPreviewDoubleClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
void refreshBannerCards(); // Refresh the display of cards based on the current sorting option
|
void refreshBannerCards(); // Refresh the display of cards based on the current sorting option
|
||||||
|
QStringList gatherAllTagsFromFlowWidget() const;
|
||||||
|
QStringList gatherAllTags(const QList<DeckPreviewWidget *> &allDecks);
|
||||||
void showEvent(QShowEvent *event) override;
|
void showEvent(QShowEvent *event) override;
|
||||||
void updateSortOrder();
|
void updateSortOrder();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void bannerCardsRefreshed();
|
||||||
void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
void deckPreviewClicked(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
|
void deckPreviewDoubleClicked(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum SortOrder
|
|
||||||
{
|
|
||||||
Alphabetical,
|
|
||||||
ByLastModified
|
|
||||||
};
|
|
||||||
|
|
||||||
QVBoxLayout *layout;
|
QVBoxLayout *layout;
|
||||||
|
QHBoxLayout *searchAndSortLayout;
|
||||||
FlowWidget *flowWidget;
|
FlowWidget *flowWidget;
|
||||||
DeckListModel *deckListModel;
|
DeckListModel *deckListModel;
|
||||||
QMap<QString, DeckViewCardContainer *> cardContainers;
|
QMap<QString, DeckViewCardContainer *> cardContainers;
|
||||||
|
|
||||||
SortOrder sortOrder; // Current sorting option
|
VisualDeckStorageSortWidget *sortWidget;
|
||||||
QComboBox *sortComboBox;
|
|
||||||
VisualDeckStorageSearchWidget *searchWidget;
|
VisualDeckStorageSearchWidget *searchWidget;
|
||||||
|
VisualDeckStorageTagFilterWidget *tagFilterWidget;
|
||||||
|
DeckPreviewColorIdentityFilterWidget *deckPreviewColorIdentityFilterWidget;
|
||||||
CardSizeWidget *cardSizeWidget;
|
CardSizeWidget *cardSizeWidget;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,12 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(DeckLoaderLog, "deck_loader")
|
||||||
|
|
||||||
const QStringList DeckLoader::fileNameFilters = QStringList()
|
const QStringList DeckLoader::fileNameFilters = QStringList()
|
||||||
<< QObject::tr("Common deck formats (*.cod *.dec *.dek *.txt *.mwDeck)")
|
<< QObject::tr("Common deck formats (*.cod *.dec *.dek *.txt *.mwDeck)")
|
||||||
|
|
@ -34,7 +38,7 @@ DeckLoader::DeckLoader(const DeckLoader &other)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
|
@ -48,9 +52,9 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
||||||
break;
|
break;
|
||||||
case CockatriceFormat: {
|
case CockatriceFormat: {
|
||||||
result = loadFromFile_Native(&file);
|
result = loadFromFile_Native(&file);
|
||||||
qDebug() << "Loaded from" << fileName << "-" << result;
|
qCDebug(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
|
||||||
if (!result) {
|
if (!result) {
|
||||||
qDebug() << "Retying as plain format";
|
qCDebug(DeckLoaderLog) << "Retrying as plain format";
|
||||||
file.seek(0);
|
file.seek(0);
|
||||||
result = loadFromFile_Plain(&file);
|
result = loadFromFile_Plain(&file);
|
||||||
fmt = PlainTextFormat;
|
fmt = PlainTextFormat;
|
||||||
|
|
@ -65,11 +69,14 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
||||||
if (result) {
|
if (result) {
|
||||||
lastFileName = fileName;
|
lastFileName = fileName;
|
||||||
lastFileFormat = fmt;
|
lastFileFormat = fmt;
|
||||||
|
if (userRequest) {
|
||||||
|
updateLastLoadedTimestamp(fileName, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
emit deckLoaded();
|
emit deckLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Deck was loaded -" << result;
|
qCDebug(DeckLoaderLog) << "Deck was loaded -" << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,6 +117,59 @@ bool DeckLoader::saveToFile(const QString &fileName, FileFormat fmt)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt)
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(fileName);
|
||||||
|
if (!fileInfo.exists()) {
|
||||||
|
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime originalTimestamp = fileInfo.lastModified();
|
||||||
|
|
||||||
|
// Open the file for writing
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
qCWarning(DeckLoaderLog) << "Failed to open file for writing:" << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
// Perform file modifications
|
||||||
|
switch (fmt) {
|
||||||
|
case PlainTextFormat:
|
||||||
|
break;
|
||||||
|
case CockatriceFormat:
|
||||||
|
setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
||||||
|
result = saveToFile_Native(&file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close(); // Close the file to ensure changes are flushed
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
lastFileName = fileName;
|
||||||
|
lastFileFormat = fmt;
|
||||||
|
|
||||||
|
// Re-open the file and set the original timestamp
|
||||||
|
if (!file.open(QIODevice::ReadWrite)) {
|
||||||
|
qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.setFileTime(originalTimestamp, QFileDevice::FileModificationTime)) {
|
||||||
|
qCWarning(DeckLoaderLog) << "Failed to set modification time for file:" << fileName;
|
||||||
|
file.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// This struct is here to support the forEachCard function call, defined in decklist. It
|
// This struct is here to support the forEachCard function call, defined in decklist. It
|
||||||
// requires a function to be called for each card, and passes an inner node and a card for
|
// requires a function to be called for each card, and passes an inner node and a card for
|
||||||
// each card in the decklist.
|
// each card in the decklist.
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,10 @@ public:
|
||||||
|
|
||||||
static FileFormat getFormatFromName(const QString &fileName);
|
static FileFormat getFormatFromName(const QString &fileName);
|
||||||
|
|
||||||
bool loadFromFile(const QString &fileName, FileFormat fmt);
|
bool loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest = false);
|
||||||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
||||||
bool saveToFile(const QString &fileName, FileFormat fmt);
|
bool saveToFile(const QString &fileName, FileFormat fmt);
|
||||||
|
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
||||||
QString exportDeckToDecklist();
|
QString exportDeckToDecklist();
|
||||||
|
|
||||||
void resolveSetNameAndNumberToProviderID();
|
void resolveSetNameAndNumberToProviderID();
|
||||||
|
|
|
||||||
|
|
@ -350,9 +350,26 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
||||||
connect(&showVisualDeckStorageOnLoadCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
|
connect(&showVisualDeckStorageOnLoadCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
|
||||||
&SettingsCache::setVisualDeckStorageShowOnLoad);
|
&SettingsCache::setVisualDeckStorageShowOnLoad);
|
||||||
|
|
||||||
|
visualDeckStorageDrawUnusedColorIdentitiesCheckBox.setChecked(
|
||||||
|
settings.getVisualDeckStorageDrawUnusedColorIdentities());
|
||||||
|
connect(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
|
||||||
|
&SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
|
||||||
|
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setMinimum(0);
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setMaximum(100);
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setValue(
|
||||||
|
settings.getVisualDeckStorageUnusedColorIdentitiesOpacity());
|
||||||
|
connect(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||||
|
&settings, &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
|
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacityLabel.setBuddy(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox);
|
||||||
|
|
||||||
auto *menuGrid = new QGridLayout;
|
auto *menuGrid = new QGridLayout;
|
||||||
menuGrid->addWidget(&showShortcutsCheckBox, 0, 0);
|
menuGrid->addWidget(&showShortcutsCheckBox, 0, 0);
|
||||||
menuGrid->addWidget(&showVisualDeckStorageOnLoadCheckBox, 1, 0);
|
menuGrid->addWidget(&showVisualDeckStorageOnLoadCheckBox, 1, 0);
|
||||||
|
menuGrid->addWidget(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, 2, 0);
|
||||||
|
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacityLabel, 3, 0);
|
||||||
|
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, 3, 1);
|
||||||
|
|
||||||
menuGroupBox = new QGroupBox;
|
menuGroupBox = new QGroupBox;
|
||||||
menuGroupBox->setLayout(menuGrid);
|
menuGroupBox->setLayout(menuGrid);
|
||||||
|
|
@ -488,6 +505,10 @@ void AppearanceSettingsPage::retranslateUi()
|
||||||
menuGroupBox->setTitle(tr("Menu settings"));
|
menuGroupBox->setTitle(tr("Menu settings"));
|
||||||
showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus"));
|
showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus"));
|
||||||
showVisualDeckStorageOnLoadCheckBox.setText(tr("Show visual deck storage on database load"));
|
showVisualDeckStorageOnLoadCheckBox.setText(tr("Show visual deck storage on database load"));
|
||||||
|
visualDeckStorageDrawUnusedColorIdentitiesCheckBox.setText(
|
||||||
|
tr("Draw missing color identities in visual deck storage without color label"));
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacityLabel.setText(tr("Missing color identity opacity"));
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setSuffix("%");
|
||||||
|
|
||||||
cardsGroupBox->setTitle(tr("Card rendering"));
|
cardsGroupBox->setTitle(tr("Card rendering"));
|
||||||
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,9 @@ private:
|
||||||
QLabel maxFontSizeForCardsLabel;
|
QLabel maxFontSizeForCardsLabel;
|
||||||
QCheckBox showShortcutsCheckBox;
|
QCheckBox showShortcutsCheckBox;
|
||||||
QCheckBox showVisualDeckStorageOnLoadCheckBox;
|
QCheckBox showVisualDeckStorageOnLoadCheckBox;
|
||||||
|
QCheckBox visualDeckStorageDrawUnusedColorIdentitiesCheckBox;
|
||||||
|
QLabel visualDeckStorageUnusedColorIdentitiesOpacityLabel;
|
||||||
|
QSpinBox visualDeckStorageUnusedColorIdentitiesOpacitySpinBox;
|
||||||
QCheckBox displayCardNamesCheckBox;
|
QCheckBox displayCardNamesCheckBox;
|
||||||
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
||||||
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,10 @@ SettingsCache::SettingsCache()
|
||||||
visualDeckStorageCardSize = settings->value("cards/visualdeckstoragecardsize", 100).toInt();
|
visualDeckStorageCardSize = settings->value("cards/visualdeckstoragecardsize", 100).toInt();
|
||||||
visualDeckStorageShowOnLoad = settings->value("interface/visualdeckstorageshowonload", true).toBool();
|
visualDeckStorageShowOnLoad = settings->value("interface/visualdeckstorageshowonload", true).toBool();
|
||||||
visualDeckStorageSortingOrder = settings->value("interface/visualdeckstoragesortingorder", 0).toInt();
|
visualDeckStorageSortingOrder = settings->value("interface/visualdeckstoragesortingorder", 0).toInt();
|
||||||
|
visualDeckStorageDrawUnusedColorIdentities =
|
||||||
|
settings->value("interface/visualdeckstoragedrawunusedcoloridentities", true).toBool();
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacity =
|
||||||
|
settings->value("interface/visualdeckstorageunusedcoloridentitiesopacity", 15).toInt();
|
||||||
horizontalHand = settings->value("hand/horizontal", true).toBool();
|
horizontalHand = settings->value("hand/horizontal", true).toBool();
|
||||||
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
||||||
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
|
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
|
||||||
|
|
@ -631,6 +635,20 @@ void SettingsCache::setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T _visualDec
|
||||||
settings->setValue("interface/visualdeckstorageshowonload", visualDeckStorageShowOnLoad);
|
settings->setValue("interface/visualdeckstorageshowonload", visualDeckStorageShowOnLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities(
|
||||||
|
QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities)
|
||||||
|
{
|
||||||
|
visualDeckStorageDrawUnusedColorIdentities = _visualDeckStorageDrawUnusedColorIdentities;
|
||||||
|
settings->setValue("cards/visualdeckstoragedrawunusedcoloridentities", visualDeckStorageDrawUnusedColorIdentities);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity)
|
||||||
|
{
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacity = _visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
|
settings->setValue("cards/visualdeckstorageunusedcoloridentitiesopacity",
|
||||||
|
visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
|
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
|
||||||
{
|
{
|
||||||
horizontalHand = static_cast<bool>(_horizontalHand);
|
horizontalHand = static_cast<bool>(_horizontalHand);
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,8 @@ private:
|
||||||
bool printingSelectorNavigationButtonsVisible;
|
bool printingSelectorNavigationButtonsVisible;
|
||||||
int visualDeckStorageSortingOrder;
|
int visualDeckStorageSortingOrder;
|
||||||
int visualDeckStorageCardSize;
|
int visualDeckStorageCardSize;
|
||||||
|
bool visualDeckStorageDrawUnusedColorIdentities;
|
||||||
|
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
bool visualDeckStorageShowOnLoad;
|
bool visualDeckStorageShowOnLoad;
|
||||||
bool horizontalHand;
|
bool horizontalHand;
|
||||||
bool invertVerticalCoordinate;
|
bool invertVerticalCoordinate;
|
||||||
|
|
@ -381,6 +383,14 @@ public:
|
||||||
{
|
{
|
||||||
return visualDeckStorageCardSize;
|
return visualDeckStorageCardSize;
|
||||||
}
|
}
|
||||||
|
bool getVisualDeckStorageDrawUnusedColorIdentities() const
|
||||||
|
{
|
||||||
|
return visualDeckStorageDrawUnusedColorIdentities;
|
||||||
|
}
|
||||||
|
int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
|
||||||
|
{
|
||||||
|
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||||
|
}
|
||||||
bool getVisualDeckStorageShowOnLoad() const
|
bool getVisualDeckStorageShowOnLoad() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowOnLoad;
|
return visualDeckStorageShowOnLoad;
|
||||||
|
|
@ -695,6 +705,8 @@ public slots:
|
||||||
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
|
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
|
||||||
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
|
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
|
||||||
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
||||||
|
void setVisualDeckStorageDrawUnusedColorIdentities(QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities);
|
||||||
|
void setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||||
void setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T _visualDeckStorageShowOnLoad);
|
void setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T _visualDeckStorageShowOnLoad);
|
||||||
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
|
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
|
||||||
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
|
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
|
||||||
|
|
|
||||||
|
|
@ -368,7 +368,8 @@ DeckList::DeckList()
|
||||||
|
|
||||||
// TODO: https://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator
|
// TODO: https://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator
|
||||||
DeckList::DeckList(const DeckList &other)
|
DeckList::DeckList(const DeckList &other)
|
||||||
: QObject(), name(other.name), comments(other.comments), bannerCard(other.bannerCard), deckHash(other.deckHash)
|
: QObject(), name(other.name), comments(other.comments), bannerCard(other.bannerCard), deckHash(other.deckHash),
|
||||||
|
lastLoadedTimestamp(other.lastLoadedTimestamp)
|
||||||
{
|
{
|
||||||
root = new InnerDecklistNode(other.getRoot());
|
root = new InnerDecklistNode(other.getRoot());
|
||||||
|
|
||||||
|
|
@ -419,25 +420,37 @@ bool DeckList::readElement(QXmlStreamReader *xml)
|
||||||
{
|
{
|
||||||
const QString childName = xml->name().toString();
|
const QString childName = xml->name().toString();
|
||||||
if (xml->isStartElement()) {
|
if (xml->isStartElement()) {
|
||||||
if (childName == "deckname")
|
if (childName == "lastLoadedTimestamp") {
|
||||||
|
lastLoadedTimestamp = xml->readElementText();
|
||||||
|
} else if (childName == "deckname") {
|
||||||
name = xml->readElementText();
|
name = xml->readElementText();
|
||||||
else if (childName == "comments")
|
} else if (childName == "comments") {
|
||||||
comments = xml->readElementText();
|
comments = xml->readElementText();
|
||||||
else if (childName == "bannerCard") {
|
} else if (childName == "bannerCard") {
|
||||||
bannerCard = xml->readElementText();
|
QString providerId = xml->attributes().value("providerId").toString();
|
||||||
qDebug() << "Deckloader found the banner card " << bannerCard;
|
QString cardName = xml->readElementText();
|
||||||
|
bannerCard = QPair<QString, QString>(cardName, providerId);
|
||||||
|
} else if (childName == "tags") {
|
||||||
|
tags.clear(); // Clear existing tags
|
||||||
|
while (xml->readNextStartElement()) {
|
||||||
|
if (xml->name().toString() == "tag") {
|
||||||
|
tags.append(xml->readElementText());
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (childName == "zone") {
|
} else if (childName == "zone") {
|
||||||
InnerDecklistNode *newZone = getZoneObjFromName(xml->attributes().value("name").toString());
|
InnerDecklistNode *newZone = getZoneObjFromName(xml->attributes().value("name").toString());
|
||||||
newZone->readElement(xml);
|
newZone->readElement(xml);
|
||||||
} else if (childName == "sideboard_plan") {
|
} else if (childName == "sideboard_plan") {
|
||||||
SideboardPlan *newSideboardPlan = new SideboardPlan;
|
SideboardPlan *newSideboardPlan = new SideboardPlan;
|
||||||
if (newSideboardPlan->readElement(xml))
|
if (newSideboardPlan->readElement(xml)) {
|
||||||
sideboardPlans.insert(newSideboardPlan->getName(), newSideboardPlan);
|
sideboardPlans.insert(newSideboardPlan->getName(), newSideboardPlan);
|
||||||
else
|
} else {
|
||||||
delete newSideboardPlan;
|
delete newSideboardPlan;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (xml->isEndElement() && (childName == "cockatrice_deck"))
|
} else if (xml->isEndElement() && (childName == "cockatrice_deck")) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,17 +458,33 @@ void DeckList::write(QXmlStreamWriter *xml)
|
||||||
{
|
{
|
||||||
xml->writeStartElement("cockatrice_deck");
|
xml->writeStartElement("cockatrice_deck");
|
||||||
xml->writeAttribute("version", "1");
|
xml->writeAttribute("version", "1");
|
||||||
|
xml->writeTextElement("lastLoadedTimestamp", lastLoadedTimestamp);
|
||||||
xml->writeTextElement("deckname", name);
|
xml->writeTextElement("deckname", name);
|
||||||
xml->writeTextElement("comments", comments);
|
xml->writeStartElement("bannerCard");
|
||||||
xml->writeTextElement("bannerCard", bannerCard);
|
xml->writeAttribute("providerId", bannerCard.second);
|
||||||
|
xml->writeCharacters(bannerCard.first);
|
||||||
for (int i = 0; i < root->size(); i++)
|
|
||||||
root->at(i)->writeElement(xml);
|
|
||||||
|
|
||||||
QMapIterator<QString, SideboardPlan *> i(sideboardPlans);
|
|
||||||
while (i.hasNext())
|
|
||||||
i.next().value()->write(xml);
|
|
||||||
xml->writeEndElement();
|
xml->writeEndElement();
|
||||||
|
xml->writeTextElement("comments", comments);
|
||||||
|
|
||||||
|
// Write tags
|
||||||
|
xml->writeStartElement("tags");
|
||||||
|
for (const QString &tag : tags) {
|
||||||
|
xml->writeTextElement("tag", tag);
|
||||||
|
}
|
||||||
|
xml->writeEndElement();
|
||||||
|
|
||||||
|
// Write zones
|
||||||
|
for (int i = 0; i < root->size(); i++) {
|
||||||
|
root->at(i)->writeElement(xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write sideboard plans
|
||||||
|
QMapIterator<QString, SideboardPlan *> i(sideboardPlans);
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next().value()->write(xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
xml->writeEndElement(); // Close "cockatrice_deck"
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckList::loadFromXml(QXmlStreamReader *xml)
|
bool DeckList::loadFromXml(QXmlStreamReader *xml)
|
||||||
|
|
|
||||||
|
|
@ -250,8 +250,11 @@ class DeckList : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
QString name, comments, bannerCard;
|
QString name, comments;
|
||||||
|
QPair<QString, QString> bannerCard;
|
||||||
QString deckHash;
|
QString deckHash;
|
||||||
|
QString lastLoadedTimestamp;
|
||||||
|
QStringList tags;
|
||||||
QMap<QString, SideboardPlan *> sideboardPlans;
|
QMap<QString, SideboardPlan *> sideboardPlans;
|
||||||
InnerDecklistNode *root;
|
InnerDecklistNode *root;
|
||||||
void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
|
void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
|
||||||
|
|
@ -279,10 +282,26 @@ public slots:
|
||||||
{
|
{
|
||||||
comments = _comments;
|
comments = _comments;
|
||||||
}
|
}
|
||||||
void setBannerCard(const QString &_bannerCard = QString())
|
void setTags(const QStringList &_tags = QStringList())
|
||||||
|
{
|
||||||
|
tags = _tags;
|
||||||
|
}
|
||||||
|
void addTag(const QString &_tag)
|
||||||
|
{
|
||||||
|
tags.append(_tag);
|
||||||
|
}
|
||||||
|
void clearTags()
|
||||||
|
{
|
||||||
|
tags.clear();
|
||||||
|
}
|
||||||
|
void setBannerCard(const QPair<QString, QString> &_bannerCard = QPair<QString, QString>())
|
||||||
{
|
{
|
||||||
bannerCard = _bannerCard;
|
bannerCard = _bannerCard;
|
||||||
}
|
}
|
||||||
|
void setLastLoadedTimestamp(const QString &_lastLoadedTimestamp = QString())
|
||||||
|
{
|
||||||
|
lastLoadedTimestamp = _lastLoadedTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DeckList();
|
explicit DeckList();
|
||||||
|
|
@ -297,10 +316,18 @@ public:
|
||||||
{
|
{
|
||||||
return comments;
|
return comments;
|
||||||
}
|
}
|
||||||
QString getBannerCard() const
|
QStringList getTags() const
|
||||||
|
{
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
QPair<QString, QString> getBannerCard() const
|
||||||
{
|
{
|
||||||
return bannerCard;
|
return bannerCard;
|
||||||
}
|
}
|
||||||
|
QString getLastLoadedTimestamp() const
|
||||||
|
{
|
||||||
|
return lastLoadedTimestamp;
|
||||||
|
}
|
||||||
QList<MoveCard_ToZone> getCurrentSideboardPlan();
|
QList<MoveCard_ToZone> getCurrentSideboardPlan();
|
||||||
void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan);
|
void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan);
|
||||||
const QMap<QString, SideboardPlan *> &getSideboardPlans() const
|
const QMap<QString, SideboardPlan *> &getSideboardPlans() const
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,14 @@ void SettingsCache::setVisualDeckStorageCardSize(int /* _visualDeckStorageCardSi
|
||||||
void SettingsCache::setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T /* _visualDeckStorageShowOnLoad */)
|
void SettingsCache::setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T /* _visualDeckStorageShowOnLoad */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities(
|
||||||
|
QT_STATE_CHANGED_T /* _visualDeckStorageDrawUnusedColorIdentities */)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
|
||||||
|
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
||||||
|
{
|
||||||
|
}
|
||||||
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
|
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,14 @@ void SettingsCache::setVisualDeckStorageCardSize(int /* _visualDeckStorageCardSi
|
||||||
void SettingsCache::setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T /* _visualDeckStorageShowOnLoad */)
|
void SettingsCache::setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T /* _visualDeckStorageShowOnLoad */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities(
|
||||||
|
QT_STATE_CHANGED_T /* _visualDeckStorageDrawUnusedColorIdentities */)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
|
||||||
|
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
||||||
|
{
|
||||||
|
}
|
||||||
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
|
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue