mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-03-21 17:55:21 -05:00
Visual deck storage v2 (#5427)
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Debian, DEB, 12) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Debian, DEB, skip, 11) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Fedora, RPM, 41) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Fedora, RPM, skip, 40) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Ubuntu, DEB, 24.04) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Ubuntu, DEB, skip, 20.04) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Ubuntu, DEB, skip, 22.04) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (yes, Arch, skip) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (3, 1, macos-14, Apple, 14, Release, 15.4) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (3, 1, macos-15, Apple, 15, Release, 16.2) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (3, macos-15, Apple, 15, Debug, 16.2) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (4, 1, macos-13, Intel, 13, Release, 14.3.1) (push) Blocked by required conditions
Build Desktop / Windows ${{matrix.target}} (msvc2019_64, 5.15.*, 7) (push) Blocked by required conditions
Build Desktop / Windows ${{matrix.target}} (msvc2019_64, qtimageformats qtmultimedia qtwebsockets, 6.6.*, 10) (push) Blocked by required conditions
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Debian, DEB, 12) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Debian, DEB, skip, 11) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Fedora, RPM, 41) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Fedora, RPM, skip, 40) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Ubuntu, DEB, 24.04) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Ubuntu, DEB, skip, 20.04) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (Ubuntu, DEB, skip, 22.04) (push) Blocked by required conditions
Build Desktop / ${{matrix.distro}} ${{matrix.version}} (yes, Arch, skip) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (3, 1, macos-14, Apple, 14, Release, 15.4) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (3, 1, macos-15, Apple, 15, Release, 16.2) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (3, macos-15, Apple, 15, Debug, 16.2) (push) Blocked by required conditions
Build Desktop / macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }} (4, 1, macos-13, Intel, 13, Release, 14.3.1) (push) Blocked by required conditions
Build Desktop / Windows ${{matrix.target}} (msvc2019_64, 5.15.*, 7) (push) Blocked by required conditions
Build Desktop / Windows ${{matrix.target}} (msvc2019_64, qtimageformats qtmultimedia qtwebsockets, 6.6.*, 10) (push) Blocked by required conditions
* 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
|
|
@ -162,8 +162,18 @@ set(cockatrice_SOURCES
|
|||
src/game/zones/view_zone.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/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_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}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
[Rules]
|
||||
picture_loader.debug = true
|
||||
picture_loader.debug = true
|
||||
deck_loader.debug = true
|
||||
|
|
@ -823,7 +823,7 @@ void TabDeckEditor::updateBannerCardComboBox()
|
|||
bannerCardComboBox->clear();
|
||||
|
||||
// Prepare the new items with deduplication
|
||||
QSet<QString> bannerCardSet;
|
||||
QSet<QPair<QString, QString>> bannerCardSet;
|
||||
InnerDecklistNode *listRoot = deckModel->getDeckList()->getRoot();
|
||||
for (int i = 0; i < listRoot->size(); i++) {
|
||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||
|
|
@ -833,23 +833,30 @@ void TabDeckEditor::updateBannerCardComboBox()
|
|||
continue;
|
||||
|
||||
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) {
|
||||
bannerCardSet.insert(currentCard->getName());
|
||||
bannerCardSet.insert(
|
||||
QPair<QString, QString>(currentCard->getName(), currentCard->getCardProviderId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the QSet to a sorted QStringList
|
||||
QStringList bannerCardChoices;
|
||||
for (const QString &entry : bannerCardSet) {
|
||||
bannerCardChoices.append(entry);
|
||||
}
|
||||
bannerCardChoices.sort(Qt::CaseInsensitive);
|
||||
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
||||
|
||||
// Populate the combo box with new items
|
||||
bannerCardComboBox->addItems(bannerCardChoices);
|
||||
// Sort QList by the first() element of the QPair
|
||||
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
|
||||
int restoredIndex = bannerCardComboBox->findText(currentText);
|
||||
|
|
@ -857,7 +864,7 @@ void TabDeckEditor::updateBannerCardComboBox()
|
|||
bannerCardComboBox->setCurrentIndex(restoredIndex);
|
||||
} else {
|
||||
// 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) {
|
||||
bannerCardComboBox->setCurrentIndex(bannerIndex);
|
||||
} else {
|
||||
|
|
@ -872,8 +879,8 @@ void TabDeckEditor::updateBannerCardComboBox()
|
|||
|
||||
void TabDeckEditor::setBannerCard(int /* changedIndex */)
|
||||
{
|
||||
qDebug() << "Banner card was set to: " << bannerCardComboBox->currentText();
|
||||
deckModel->getDeckList()->setBannerCard(bannerCardComboBox->currentText());
|
||||
QVariantMap data = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
|
||||
deckModel->getDeckList()->setBannerCard(QPair<QString, QString>(data["name"].toString(), data["uuid"].toString()));
|
||||
}
|
||||
|
||||
void TabDeckEditor::updateCardInfo(CardInfoPtr _card)
|
||||
|
|
@ -1043,11 +1050,11 @@ void TabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLocation d
|
|||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
||||
|
||||
auto *l = new DeckLoader;
|
||||
if (l->loadFromFile(fileName, fmt)) {
|
||||
if (l->loadFromFile(fileName, fmt, true)) {
|
||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
||||
updateBannerCardComboBox();
|
||||
if (!l->getBannerCard().isEmpty()) {
|
||||
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText(l->getBannerCard()));
|
||||
if (!l->getBannerCard().first.isEmpty()) {
|
||||
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText(l->getBannerCard().first));
|
||||
}
|
||||
if (deckOpenLocation == NEW_TAB) {
|
||||
emit openDeckEditor(l);
|
||||
|
|
@ -1542,13 +1549,13 @@ void TabDeckEditor::actDecrement()
|
|||
|
||||
void TabDeckEditor::setDeck(DeckLoader *_deck)
|
||||
{
|
||||
qDebug() << " ORIGINAL BANNER CARD " << _deck->getBannerCard();
|
||||
qDebug() << " ORIGINAL BANNER CARD " << _deck->getBannerCard().first;
|
||||
deckModel->setDeckList(_deck);
|
||||
|
||||
nameEdit->setText(deckModel->getDeckList()->getName());
|
||||
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
||||
qDebug() << deckModel->getDeckList()->getBannerCard() << " was the banner card";
|
||||
bannerCardComboBox->setCurrentText(deckModel->getDeckList()->getBannerCard());
|
||||
bannerCardComboBox->setCurrentText(deckModel->getDeckList()->getBannerCard().first);
|
||||
updateBannerCardComboBox();
|
||||
updateHash();
|
||||
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ void TabDeckStorage::actOpenLocalDeck()
|
|||
QString filePath = localDirModel->filePath(curLeft);
|
||||
|
||||
DeckLoader deckLoader;
|
||||
if (!deckLoader.loadFromFile(filePath, DeckLoader::CockatriceFormat))
|
||||
if (!deckLoader.loadFromFile(filePath, DeckLoader::CockatriceFormat, true))
|
||||
continue;
|
||||
|
||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(filePath);
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
|||
deckView->setVisible(false);
|
||||
|
||||
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::imageDoubleClicked, this,
|
||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckPreviewDoubleClicked, this,
|
||||
&DeckViewContainer::replaceDeckStorageWithDeckView);
|
||||
|
||||
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);
|
||||
QString fileName = instance->filePath;
|
||||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
||||
QString deckString;
|
||||
DeckLoader deck;
|
||||
QString deckString = instance->deckLoader->writeToString_Native();
|
||||
|
||||
bool error = !deck.loadFromFile(fileName, fmt);
|
||||
if (!error) {
|
||||
deckString = deck.writeToString_Native();
|
||||
error = deckString.length() > MAX_FILE_LENGTH;
|
||||
}
|
||||
if (error) {
|
||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
||||
return;
|
||||
}
|
||||
|
|
@ -335,6 +327,11 @@ void DeckViewContainer::unloadDeck()
|
|||
visualDeckStorageWidget->setVisible(true);
|
||||
deckViewLayout->update();
|
||||
unloadDeckButton->setEnabled(false);
|
||||
readyStartButton->setEnabled(false);
|
||||
readyStartButton->setState(false);
|
||||
sideboardLockButton->setEnabled(false);
|
||||
sideboardLockButton->setState(false);
|
||||
setReadyStart(false);
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadLocalDeck()
|
||||
|
|
@ -352,7 +349,7 @@ void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
|||
QString deckString;
|
||||
DeckLoader deck;
|
||||
|
||||
bool error = !deck.loadFromFile(filePath, fmt);
|
||||
bool error = !deck.loadFromFile(filePath, fmt, true);
|
||||
if (!error) {
|
||||
deckString = deck.writeToString_Native();
|
||||
error = deckString.length() > MAX_FILE_LENGTH;
|
||||
|
|
@ -390,6 +387,9 @@ void DeckViewContainer::deckSelectFinished(const Response &r)
|
|||
// TODO CHANGE THIS TO BE SELECTED BY UUID
|
||||
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(newDeck.getCardList()));
|
||||
setDeck(newDeck);
|
||||
deckView->setVisible(true);
|
||||
visualDeckStorageWidget->setVisible(false);
|
||||
unloadDeckButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void DeckViewContainer::readyStart()
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ private:
|
|||
TabGame *parentGame;
|
||||
int playerId;
|
||||
private slots:
|
||||
void replaceDeckStorageWithDeckView(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void replaceDeckStorageWithDeckView(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||
void loadLocalDeck();
|
||||
void loadRemoteDeck();
|
||||
void unloadDeck();
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor, Abstra
|
|||
leftToolBar->addAction(aDeleteLocalDeck);
|
||||
|
||||
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::imageDoubleClicked, this,
|
||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckPreviewDoubleClicked, this,
|
||||
&TabDeckStorageVisual::actOpenLocalDeck);
|
||||
|
||||
// layout->addWidget(leftToolBar);
|
||||
|
|
@ -74,11 +74,11 @@ QString TabDeckStorageVisual::getTargetPath() const
|
|||
return {};
|
||||
}
|
||||
|
||||
void TabDeckStorageVisual::actOpenLocalDeck(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
|
||||
void TabDeckStorageVisual::actOpenLocalDeck(QMouseEvent *event, DeckPreviewWidget *instance)
|
||||
{
|
||||
(void)event;
|
||||
DeckLoader deckLoader;
|
||||
if (!deckLoader.loadFromFile(instance->filePath, DeckLoader::CockatriceFormat))
|
||||
if (!deckLoader.loadFromFile(instance->filePath, DeckLoader::CockatriceFormat, true))
|
||||
return;
|
||||
|
||||
emit openDeckEditor(&deckLoader);
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ public:
|
|||
}
|
||||
public slots:
|
||||
void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void closeRequest(bool forced = false) override;
|
||||
void actOpenLocalDeck(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void closeRequest(bool forced) override;
|
||||
void actOpenLocalDeck(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||
void actDeleteLocalDeck();
|
||||
signals:
|
||||
void openDeckEditor(const DeckLoader *deckLoader);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "deck_preview_card_picture_widget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QFontMetrics>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainterPath>
|
||||
|
|
@ -15,6 +16,7 @@
|
|||
* @param outlineColor The color of the outline around the text.
|
||||
* @param fontSize The font size of the overlay text.
|
||||
* @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.
|
||||
*/
|
||||
|
|
@ -46,8 +48,3 @@ void DeckPreviewCardPictureWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
|||
emit imageDoubleClicked(lastMouseEvent, this);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckPreviewCardPictureWidget::setFilePath(const QString &_filePath)
|
||||
{
|
||||
filePath = _filePath;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,22 +12,17 @@ class DeckPreviewCardPictureWidget final : public CardInfoPictureWithTextOverlay
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DeckPreviewCardPictureWidget(QWidget *parent = nullptr,
|
||||
explicit DeckPreviewCardPictureWidget(QWidget *parent,
|
||||
bool hoverToZoomEnabled = false,
|
||||
const QColor &textColor = Qt::white,
|
||||
const QColor &outlineColor = Qt::black,
|
||||
int fontSize = 12,
|
||||
Qt::Alignment alignment = Qt::AlignCenter);
|
||||
|
||||
QString filePath;
|
||||
|
||||
signals:
|
||||
void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
|
||||
public slots:
|
||||
void setFilePath(const QString &filePath);
|
||||
|
||||
private:
|
||||
QTimer *singleClickTimer;
|
||||
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);
|
||||
}
|
||||
|
||||
void FlowWidget::removeWidget(QWidget *widgetToRemove) const
|
||||
{
|
||||
flowLayout->removeWidget(widgetToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears all widgets from the flow layout.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class FlowWidget final : public QWidget
|
|||
public:
|
||||
FlowWidget(QWidget *parent, Qt::ScrollBarPolicy horizontalPolicy, Qt::ScrollBarPolicy verticalPolicy);
|
||||
void addWidget(QWidget *widget_to_add) const;
|
||||
void removeWidget(QWidget *widgetToRemove) const;
|
||||
void clearLayout();
|
||||
[[nodiscard]] int count() 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();
|
||||
}
|
||||
|
||||
QStringList VisualDeckStorageSearchWidget::filterFiles(const QStringList &files, const QString &searchText)
|
||||
QList<DeckPreviewWidget *> VisualDeckStorageSearchWidget::filterFiles(QList<DeckPreviewWidget *> &widgets,
|
||||
const QString &searchText)
|
||||
{
|
||||
if (searchText.isEmpty() || searchText.isNull()) {
|
||||
return files;
|
||||
return widgets;
|
||||
}
|
||||
|
||||
QStringList filteredFiles;
|
||||
QList<DeckPreviewWidget *> filteredWidgets;
|
||||
|
||||
for (const auto &file : files) {
|
||||
QFileInfo fileInfo(file);
|
||||
for (const auto &file : widgets) {
|
||||
QFileInfo fileInfo(file->filePath);
|
||||
QString fileName = fileInfo.fileName().toLower();
|
||||
|
||||
if (fileName.contains(searchText.toLower())) {
|
||||
filteredFiles << file;
|
||||
filteredWidgets << file;
|
||||
}
|
||||
}
|
||||
|
||||
return filteredFiles;
|
||||
return filteredWidgets;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class VisualDeckStorageSearchWidget : public QWidget
|
|||
public:
|
||||
explicit VisualDeckStorageSearchWidget(VisualDeckStorageWidget *parent);
|
||||
QString getSearchText();
|
||||
QStringList filterFiles(const QStringList &files, const QString &searchText);
|
||||
QList<DeckPreviewWidget *> filterFiles(QList<DeckPreviewWidget *> &widgets, const QString &searchText);
|
||||
|
||||
private:
|
||||
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 "../../../../game/cards/card_database_manager.h"
|
||||
#include "../../../../settings/cache_settings.h"
|
||||
#include "deck_preview/deck_preview_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 <QDirIterator>
|
||||
#include <QMouseEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), sortOrder(Alphabetical)
|
||||
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
deckListModel = new DeckListModel(this);
|
||||
deckListModel->setObjectName("visualDeckModel");
|
||||
|
|
@ -18,27 +21,24 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
|
|||
layout = new QVBoxLayout();
|
||||
setLayout(layout);
|
||||
|
||||
// ComboBox for sorting options
|
||||
sortComboBox = new QComboBox(this);
|
||||
sortComboBox->addItem("Sort Alphabetically (Filename)", Alphabetical);
|
||||
sortComboBox->addItem("Sort by Last Modified", ByLastModified);
|
||||
sortComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageSortingOrder());
|
||||
searchAndSortLayout = new QHBoxLayout();
|
||||
|
||||
sortWidget = new VisualDeckStorageSortWidget(this);
|
||||
searchWidget = new VisualDeckStorageSearchWidget(this);
|
||||
tagFilterWidget = new VisualDeckStorageTagFilterWidget(this);
|
||||
deckPreviewColorIdentityFilterWidget = new DeckPreviewColorIdentityFilterWidget(this);
|
||||
|
||||
// Add combo box to the main layout
|
||||
layout->addWidget(sortComboBox);
|
||||
layout->addWidget(searchWidget);
|
||||
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
|
||||
searchAndSortLayout->addWidget(sortWidget);
|
||||
searchAndSortLayout->addWidget(searchWidget);
|
||||
layout->addLayout(searchAndSortLayout);
|
||||
layout->addWidget(tagFilterWidget);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
cardSizeWidget = new CardSizeWidget(this, flowWidget, SettingsCache::instance().getVisualDeckStorageCardSize());
|
||||
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)
|
||||
|
|
@ -49,24 +49,23 @@ void VisualDeckStorageWidget::showEvent(QShowEvent *event)
|
|||
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QStringList allFiles;
|
||||
QList<DeckPreviewWidget *> allDecks;
|
||||
|
||||
// QDirIterator with QDir::Files and QDir::NoSymLinks ensures only files are listed (no directories or symlinks)
|
||||
QDirIterator it(SettingsCache::instance().getDeckPath(), QDir::Files | QDir::NoSymLinks,
|
||||
|
|
@ -76,46 +75,71 @@ void VisualDeckStorageWidget::refreshBannerCards()
|
|||
allFiles << it.next(); // Add each file path to the list
|
||||
}
|
||||
|
||||
// Sort files based on the current sort order
|
||||
std::sort(allFiles.begin(), allFiles.end(), [this](const QString &file1, const QString &file2) {
|
||||
QFileInfo info1(file1);
|
||||
QFileInfo info2(file2);
|
||||
foreach (const QString &file, allFiles) {
|
||||
auto *display = new DeckPreviewWidget(this, file);
|
||||
|
||||
switch (sortOrder) {
|
||||
case Alphabetical:
|
||||
return info1.fileName().toLower() < info2.fileName().toLower();
|
||||
case ByLastModified:
|
||||
return info1.lastModified() > info2.lastModified();
|
||||
}
|
||||
connect(display, &DeckPreviewWidget::deckPreviewClicked, this,
|
||||
&VisualDeckStorageWidget::deckPreviewClickedEvent);
|
||||
connect(display, &DeckPreviewWidget::deckPreviewDoubleClicked, this,
|
||||
&VisualDeckStorageWidget::deckPreviewDoubleClickedEvent);
|
||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, display->bannerCardDisplayWidget,
|
||||
&CardInfoPictureWidget::setScaleFactor);
|
||||
display->bannerCardDisplayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||
allDecks.append(display);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
foreach (const QString &file, filteredFiles) {
|
||||
auto deckLoader = new DeckLoader();
|
||||
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);
|
||||
foreach (DeckPreviewWidget *deck, filteredFiles) {
|
||||
flowWidget->addWidget(deck);
|
||||
}
|
||||
|
||||
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_view.h"
|
||||
#include "../../../ui/widgets/cards/deck_preview_card_picture_widget.h"
|
||||
#include "../../../ui/widgets/general/layout_containers/flow_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_sort_widget.h"
|
||||
#include "visual_deck_storage_tag_filter_widget.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QFileSystemModel>
|
||||
|
||||
class VisualDeckStorageSearchWidget;
|
||||
class VisualDeckStorageSortWidget;
|
||||
class VisualDeckStorageTagFilterWidget;
|
||||
class DeckPreviewColorIdentityFilterWidget;
|
||||
class VisualDeckStorageWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -20,31 +25,30 @@ public:
|
|||
void retranslateUi();
|
||||
|
||||
public slots:
|
||||
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void deckPreviewClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||
void deckPreviewDoubleClickedEvent(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||
void refreshBannerCards(); // Refresh the display of cards based on the current sorting option
|
||||
QStringList gatherAllTagsFromFlowWidget() const;
|
||||
QStringList gatherAllTags(const QList<DeckPreviewWidget *> &allDecks);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void updateSortOrder();
|
||||
|
||||
signals:
|
||||
void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void bannerCardsRefreshed();
|
||||
void deckPreviewClicked(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||
void deckPreviewDoubleClicked(QMouseEvent *event, DeckPreviewWidget *instance);
|
||||
|
||||
private:
|
||||
enum SortOrder
|
||||
{
|
||||
Alphabetical,
|
||||
ByLastModified
|
||||
};
|
||||
|
||||
QVBoxLayout *layout;
|
||||
QHBoxLayout *searchAndSortLayout;
|
||||
FlowWidget *flowWidget;
|
||||
DeckListModel *deckListModel;
|
||||
QMap<QString, DeckViewCardContainer *> cardContainers;
|
||||
|
||||
SortOrder sortOrder; // Current sorting option
|
||||
QComboBox *sortComboBox;
|
||||
VisualDeckStorageSortWidget *sortWidget;
|
||||
VisualDeckStorageSearchWidget *searchWidget;
|
||||
VisualDeckStorageTagFilterWidget *tagFilterWidget;
|
||||
DeckPreviewColorIdentityFilterWidget *deckPreviewColorIdentityFilterWidget;
|
||||
CardSizeWidget *cardSizeWidget;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@
|
|||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <qloggingcategory.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(DeckLoaderLog, "deck_loader")
|
||||
|
||||
const QStringList DeckLoader::fileNameFilters = QStringList()
|
||||
<< 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);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
|
|
@ -48,9 +52,9 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
|||
break;
|
||||
case CockatriceFormat: {
|
||||
result = loadFromFile_Native(&file);
|
||||
qDebug() << "Loaded from" << fileName << "-" << result;
|
||||
qCDebug(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
|
||||
if (!result) {
|
||||
qDebug() << "Retying as plain format";
|
||||
qCDebug(DeckLoaderLog) << "Retrying as plain format";
|
||||
file.seek(0);
|
||||
result = loadFromFile_Plain(&file);
|
||||
fmt = PlainTextFormat;
|
||||
|
|
@ -65,11 +69,14 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
|||
if (result) {
|
||||
lastFileName = fileName;
|
||||
lastFileFormat = fmt;
|
||||
if (userRequest) {
|
||||
updateLastLoadedTimestamp(fileName, fmt);
|
||||
}
|
||||
|
||||
emit deckLoaded();
|
||||
}
|
||||
|
||||
qDebug() << "Deck was loaded -" << result;
|
||||
qCDebug(DeckLoaderLog) << "Deck was loaded -" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +117,59 @@ bool DeckLoader::saveToFile(const QString &fileName, FileFormat fmt)
|
|||
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
|
||||
// requires a function to be called for each card, and passes an inner node and a card for
|
||||
// each card in the decklist.
|
||||
|
|
|
|||
|
|
@ -42,9 +42,10 @@ public:
|
|||
|
||||
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 saveToFile(const QString &fileName, FileFormat fmt);
|
||||
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
||||
QString exportDeckToDecklist();
|
||||
|
||||
void resolveSetNameAndNumberToProviderID();
|
||||
|
|
|
|||
|
|
@ -350,9 +350,26 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
connect(&showVisualDeckStorageOnLoadCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
|
||||
&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;
|
||||
menuGrid->addWidget(&showShortcutsCheckBox, 0, 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->setLayout(menuGrid);
|
||||
|
|
@ -488,6 +505,10 @@ void AppearanceSettingsPage::retranslateUi()
|
|||
menuGroupBox->setTitle(tr("Menu settings"));
|
||||
showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus"));
|
||||
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"));
|
||||
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@ private:
|
|||
QLabel maxFontSizeForCardsLabel;
|
||||
QCheckBox showShortcutsCheckBox;
|
||||
QCheckBox showVisualDeckStorageOnLoadCheckBox;
|
||||
QCheckBox visualDeckStorageDrawUnusedColorIdentitiesCheckBox;
|
||||
QLabel visualDeckStorageUnusedColorIdentitiesOpacityLabel;
|
||||
QSpinBox visualDeckStorageUnusedColorIdentitiesOpacitySpinBox;
|
||||
QCheckBox displayCardNamesCheckBox;
|
||||
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
||||
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
||||
|
|
|
|||
|
|
@ -262,6 +262,10 @@ SettingsCache::SettingsCache()
|
|||
visualDeckStorageCardSize = settings->value("cards/visualdeckstoragecardsize", 100).toInt();
|
||||
visualDeckStorageShowOnLoad = settings->value("interface/visualdeckstorageshowonload", true).toBool();
|
||||
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();
|
||||
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
horizontalHand = static_cast<bool>(_horizontalHand);
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ private:
|
|||
bool printingSelectorNavigationButtonsVisible;
|
||||
int visualDeckStorageSortingOrder;
|
||||
int visualDeckStorageCardSize;
|
||||
bool visualDeckStorageDrawUnusedColorIdentities;
|
||||
int visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||
bool visualDeckStorageShowOnLoad;
|
||||
bool horizontalHand;
|
||||
bool invertVerticalCoordinate;
|
||||
|
|
@ -381,6 +383,14 @@ public:
|
|||
{
|
||||
return visualDeckStorageCardSize;
|
||||
}
|
||||
bool getVisualDeckStorageDrawUnusedColorIdentities() const
|
||||
{
|
||||
return visualDeckStorageDrawUnusedColorIdentities;
|
||||
}
|
||||
int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
|
||||
{
|
||||
return visualDeckStorageUnusedColorIdentitiesOpacity;
|
||||
}
|
||||
bool getVisualDeckStorageShowOnLoad() const
|
||||
{
|
||||
return visualDeckStorageShowOnLoad;
|
||||
|
|
@ -695,6 +705,8 @@ public slots:
|
|||
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
|
||||
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
|
||||
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
||||
void setVisualDeckStorageDrawUnusedColorIdentities(QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities);
|
||||
void setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity);
|
||||
void setVisualDeckStorageShowOnLoad(QT_STATE_CHANGED_T _visualDeckStorageShowOnLoad);
|
||||
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
|
||||
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
|
||||
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());
|
||||
|
||||
|
|
@ -419,25 +420,37 @@ bool DeckList::readElement(QXmlStreamReader *xml)
|
|||
{
|
||||
const QString childName = xml->name().toString();
|
||||
if (xml->isStartElement()) {
|
||||
if (childName == "deckname")
|
||||
if (childName == "lastLoadedTimestamp") {
|
||||
lastLoadedTimestamp = xml->readElementText();
|
||||
} else if (childName == "deckname") {
|
||||
name = xml->readElementText();
|
||||
else if (childName == "comments")
|
||||
} else if (childName == "comments") {
|
||||
comments = xml->readElementText();
|
||||
else if (childName == "bannerCard") {
|
||||
bannerCard = xml->readElementText();
|
||||
qDebug() << "Deckloader found the banner card " << bannerCard;
|
||||
} else if (childName == "bannerCard") {
|
||||
QString providerId = xml->attributes().value("providerId").toString();
|
||||
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") {
|
||||
InnerDecklistNode *newZone = getZoneObjFromName(xml->attributes().value("name").toString());
|
||||
newZone->readElement(xml);
|
||||
} else if (childName == "sideboard_plan") {
|
||||
SideboardPlan *newSideboardPlan = new SideboardPlan;
|
||||
if (newSideboardPlan->readElement(xml))
|
||||
if (newSideboardPlan->readElement(xml)) {
|
||||
sideboardPlans.insert(newSideboardPlan->getName(), newSideboardPlan);
|
||||
else
|
||||
} else {
|
||||
delete newSideboardPlan;
|
||||
}
|
||||
}
|
||||
} else if (xml->isEndElement() && (childName == "cockatrice_deck"))
|
||||
} else if (xml->isEndElement() && (childName == "cockatrice_deck")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -445,17 +458,33 @@ void DeckList::write(QXmlStreamWriter *xml)
|
|||
{
|
||||
xml->writeStartElement("cockatrice_deck");
|
||||
xml->writeAttribute("version", "1");
|
||||
xml->writeTextElement("lastLoadedTimestamp", lastLoadedTimestamp);
|
||||
xml->writeTextElement("deckname", name);
|
||||
xml->writeTextElement("comments", comments);
|
||||
xml->writeTextElement("bannerCard", bannerCard);
|
||||
|
||||
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->writeStartElement("bannerCard");
|
||||
xml->writeAttribute("providerId", bannerCard.second);
|
||||
xml->writeCharacters(bannerCard.first);
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -250,8 +250,11 @@ class DeckList : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QString name, comments, bannerCard;
|
||||
QString name, comments;
|
||||
QPair<QString, QString> bannerCard;
|
||||
QString deckHash;
|
||||
QString lastLoadedTimestamp;
|
||||
QStringList tags;
|
||||
QMap<QString, SideboardPlan *> sideboardPlans;
|
||||
InnerDecklistNode *root;
|
||||
void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
|
||||
|
|
@ -279,10 +282,26 @@ public slots:
|
|||
{
|
||||
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;
|
||||
}
|
||||
void setLastLoadedTimestamp(const QString &_lastLoadedTimestamp = QString())
|
||||
{
|
||||
lastLoadedTimestamp = _lastLoadedTimestamp;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit DeckList();
|
||||
|
|
@ -297,10 +316,18 @@ public:
|
|||
{
|
||||
return comments;
|
||||
}
|
||||
QString getBannerCard() const
|
||||
QStringList getTags() const
|
||||
{
|
||||
return tags;
|
||||
}
|
||||
QPair<QString, QString> getBannerCard() const
|
||||
{
|
||||
return bannerCard;
|
||||
}
|
||||
QString getLastLoadedTimestamp() const
|
||||
{
|
||||
return lastLoadedTimestamp;
|
||||
}
|
||||
QList<MoveCard_ToZone> getCurrentSideboardPlan();
|
||||
void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan);
|
||||
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::setVisualDeckStorageDrawUnusedColorIdentities(
|
||||
QT_STATE_CHANGED_T /* _visualDeckStorageDrawUnusedColorIdentities */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
|
||||
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
||||
{
|
||||
}
|
||||
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::setVisualDeckStorageDrawUnusedColorIdentities(
|
||||
QT_STATE_CHANGED_T /* _visualDeckStorageDrawUnusedColorIdentities */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
|
||||
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user