New printing selector (#5182)

* Squashed Commits

Lint things.

Set focus back to deckView after selecting a card to enable keyboard navigation.

Bump scrollbar to top when selecting a new card.

Update card info on hover.

Layout cleanups

Add +- to buttons.

Merge buttons into card picture.

Cleanup size, min 2 cards by default in rows

Support layout settings config and set min to 525 so two cols are visible by default for printings, when opened

Move Printing Selector to before Deck, and visible true

Null safety for setCard.

Turn down the dropshadow a little.

Make PrintingSelector dockable, don't duplicate sets when bumping them to the front of the list.

When swapping cards between mainboard and sideboard, use preferred printing if no uuid is available (i.e. null).

Reorder includes...

Unwonk an include.

Give the card widget a snazzy drop shadow, appease the linter gods.

Handle jumping between segments

Remember scale factor when initializing new widgets.

Cleanup

Select Card works (Not M->SB tho)

Resize word-wrapped label properly.

Fix the layouting, mostly.

remove tx

Build Fix

Squashed Commits

Load and store redirects properly.

Layouting is fun :)

* Group PrintingSelectorCardDisplayWidgets into distinct containers for alignment purposes.

Override resizeEvent() properly.

Word wrap properly.

Keep widget sizes uniform for aesthetic reasons (grid pattern).

Label stuff, center card picture widget, allow cardSizeSlider to scale down.

Replace cards which have no uuid in the decklist when first selecting a printing.

Add buttons for previous and next card in DeckList.

Add a card size slider.

Move sort options initialization to implementation file.

Explicitly nullptr the parent for the PrintingSelector.

Address PR comments (minor cleanups).

Hook up to the rows removed signal to update card counts properly.

Include QDebug.

Add labels to the mainboard/sideboard button boxes.

Implement a search bar.

Expand node recursively when we add a new card.

Only create image widgets for the printing selector if it is visible in order to not slow down image loading.

Minor Tweaks

Invert decklist export logic to write out setName, collectorNumber, providerId value if it is NOT empty.

Linting.

Update CardCounts properly, update PrintingSelector on Database selection.

Initialize sideboard card count label properly.

Split mainboard/sideboard display and increment/decrement buttons.

Add button to sort all sortOptions by ascending or descending order.

Add option to sort by release date in ascending or descending order.

Add PrintingSelector to database view.

Display placeholder image before loading.

Fix deckEditor crash on mainboard/sideboard swap by correcting column index to providerId instead of shortName.

Include currentZoneName, fix the column when updating from DeckView indexChanged to be UUID and not setShortName so cards are properly fetched again.

The most minor linter change you've ever seen.

Null checks are important.

Linter again.

Linter and refactor to providerId.

Sort properly, (We don't need a map, we need a list, a map won't be ordered right [i.e. 1, 10, 11, 2, 3, 4, ..., 9])

Sort alphabetically or by preference.

Hook printingSelector up to the CardInfoFrameWidget.

Allow info from CardFrame to be retrieved, properly initialize PrintingSelector again.

Refactors to reflect CardInfoPicture becoming CardInfoPictureWidget.

Make PrintingSelector re-usable by introducing setCard().

Make PrintingSelector use the CardFrame, not the database index.

Add a new selector widget for printings.

* Support multiple <set> tags per card within the database

This will allow us to show off all different printings for cards that might appear multiple times in a set (alt arts, Secret Lairs, etc.)

* Support Flip Cards with related art

* Minor Cleanup

* Minor Cleanup

* Release Date DESC default

* Load widgets in batches.

* Refactor local batch variables to be class variables/defines.

* Clear timer on updateDisplay.

* Fix Timer & Builds on Qt5

* Not Override

* Yes Override

* Yes Override

* Lint

* Can't override in function definition.

* Resize setName to picture width on initialization.

Also add a new signal to card_info_picture_widget to emit when the scale factor changes.

Hook this up to the setName resizing method to ensure card size updates trigger it appropriately after initialization.

Clean up unused enter and resize methods that just delegated to base-class.

* Add ability to force preferred set art to be loaded for every card.

* Show related cards from printing selector by right-clicking card image.

* fix build

* Fix UST cards

* Inc QDebug

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix cards being able to jump between side and mainboard

* Don't hide PrintingSelector button widgets if the deck contains a card from the set.

* Update PrintingSelector properly on DeckListModel::dataChanged

* Add option to disable bumping sets to the front of the list if the deck contains cards from the set.

* Linter behave.

* Linter behave.

* Fix mocks.

* Fix cards without providerIds being counted for all cards.

* Flip preference sort so descending means "Most to least preferred".

* Set the index correctly when removing a non-providerId printing for a providerId printing to avoid jumping to the next card.

* Move the "Next/Previous" card buttons to their own widget.

* Move the card size slider to its own widget.

* Lint the makelist.

* Linter

* Crash fix

* Move the sorting options to their own widget.

* Move the search bar to its own widget.

* Minor cleanup

* Minor cleanup

* Minor cleanup

* Only overwrite card in deck if UUID _and_ Number missing

* Adjust font size when adjusting card size.

* Clean up some imports.

* Pivot to a view options toolbar.

* Persist sort options and change default to 'preference'.

* Lint.

* Remember how many cards were originally in deck when replacing with uuid version.

* Relabel buttons for clarity.

* Fix tests.

* Fix tests properly.

* Fix dbconverter mock.

* Try to wrangle font sizes.

* Update mainboard/sideboard labels correctly.

* Initialize button sizes correctly.

* Label texts are supposed to be white.

* Adjust another deckModel->findCard call to include number parameter.

* Style buttons again.

* Negative currentSize means we don't render the widget yet, return a default value.

* Clean up debug statements.

* Boop the mainboard/sideboard label and the cardCount after a little bit of delay to make sure they initialize at the right size.

* Persist card size slider selection in SettingsCache.

* Good Lint Inc.

* updateCardCount to get white color in initializer

* Make the view display options functional.

* Comment ALL the things.

* Lint the things.

* Brief accidentally nuked some constants.

* Proper Qt slot for checkboxes.

* Don't use timers, Qt provides ShowEvent for anything necessary before the widget is shown.

* Cleanup from Reading

* Cleanup Lints

* Minor

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: Zach Halpern <zahalpern+github@gmail.com>
This commit is contained in:
BruebachL 2024-12-19 03:40:34 +01:00 committed by GitHub
parent e588917f6c
commit 245d51caea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
71 changed files with 3197 additions and 251 deletions

View file

@ -24,6 +24,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/cards/card_info_picture_widget.cpp
src/client/ui/widgets/cards/card_info_text_widget.cpp
src/client/ui/widgets/cards/card_info_display_widget.cpp
src/client/ui/widgets/cards/card_size_widget.cpp
src/game/cards/card_item.cpp
src/game/cards/card_list.cpp
src/game/zones/card_zone.cpp
@ -80,6 +81,9 @@ set(cockatrice_SOURCES
src/client/ui/widgets/cards/card_info_picture_enlarged_widget.cpp
src/client/ui/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
src/client/ui/widgets/general/display/labeled_input.cpp
src/client/ui/widgets/general/display/dynamic_font_size_label.cpp
src/client/ui/widgets/general/display/dynamic_font_size_push_button.cpp
src/client/ui/widgets/general/display/shadow_background_label.cpp
src/main.cpp
src/server/message_log_widget.cpp
src/client/ui/layouts/overlap_layout.cpp
@ -94,6 +98,17 @@ set(cockatrice_SOURCES
src/game/player/player.cpp
src/game/player/player_list_widget.cpp
src/game/player/player_target.cpp
src/client/ui/widgets/printing_selector/all_zones_card_amount_widget.cpp
src/client/ui/widgets/printing_selector/card_amount_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector.cpp
src/client/ui/widgets/printing_selector/printing_selector_card_display_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector_card_search_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector_card_selection_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector_card_sorting_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector_view_options_toolbar_widget.cpp
src/client/ui/widgets/printing_selector/printing_selector_view_options_widget.cpp
src/client/ui/widgets/printing_selector/set_name_and_collectors_number_display_widget.cpp
src/client/network/release_channel.cpp
src/server/remote/remote_client.cpp
src/server/remote/remote_decklist_tree_widget.cpp

View file

@ -15,6 +15,7 @@
#include "../../settings/cache_settings.h"
#include "../ui/picture_loader.h"
#include "../ui/pixel_map_generator.h"
#include "../ui/widgets/printing_selector/printing_selector.h"
#include "pb/command_deck_upload.pb.h"
#include "pb/response.pb.h"
#include "tab_supervisor.h"
@ -78,9 +79,13 @@ void TabDeckEditor::createDeckDock()
deckView->sortByColumn(1, Qt::AscendingOrder);
deckView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
deckView->installEventFilter(&deckViewKeySignals);
deckView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &)));
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
SLOT(updatePrintingSelectorDeckView(const QModelIndex &, const QModelIndex &)));
connect(deckView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actSwapCard()));
connect(deckView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(decklistCustomMenu(QPoint)));
connect(&deckViewKeySignals, SIGNAL(onShiftS()), this, SLOT(actSwapCard()));
connect(&deckViewKeySignals, SIGNAL(onEnter()), this, SLOT(actIncrement()));
connect(&deckViewKeySignals, SIGNAL(onCtrlAltEqual()), this, SLOT(actIncrement()));
@ -172,7 +177,6 @@ void TabDeckEditor::createDeckDock()
deckDock = new QDockWidget(this);
deckDock->setObjectName("deckDock");
deckDock->setMinimumSize(QSize(200, 41));
deckDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
deckDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
QDockWidget::DockWidgetMovable);
@ -196,7 +200,6 @@ void TabDeckEditor::createCardInfoDock()
cardInfoDock = new QDockWidget(this);
cardInfoDock->setObjectName("cardInfoDock");
cardInfoDock->setMinimumSize(QSize(200, 41));
cardInfoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
cardInfoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
QDockWidget::DockWidgetMovable);
@ -271,6 +274,32 @@ void TabDeckEditor::createFiltersDock()
connect(filterDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
}
void TabDeckEditor::createPrintingSelectorDock()
{
printingSelector = new PrintingSelector(this, this, deckModel, deckView);
printingSelector->setObjectName("printingSelector");
auto *printingSelectorFrame = new QVBoxLayout;
printingSelectorFrame->setObjectName("printingSelectorFrame");
printingSelectorFrame->addWidget(printingSelector);
printingSelectorDock = new QDockWidget(this);
printingSelectorDock->setObjectName("printingSelectorDock");
printingSelectorDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
printingSelectorDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
QDockWidget::DockWidgetMovable);
auto *printingSelectorDockContents = new QWidget();
printingSelectorDockContents->setObjectName("printingSelectorDockContents");
printingSelectorDockContents->setLayout(printingSelectorFrame);
printingSelectorDock->setWidget(printingSelectorDockContents);
printingSelectorDock->installEventFilter(this);
connect(printingSelectorDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
addDockWidget(Qt::RightDockWidgetArea, printingSelectorDock);
printingSelectorDock->setFloating(false);
}
void TabDeckEditor::createMenus()
{
aNewDeck = new QAction(QString(), this);
@ -349,6 +378,7 @@ void TabDeckEditor::createMenus()
cardInfoDockMenu = viewMenu->addMenu(QString());
deckDockMenu = viewMenu->addMenu(QString());
filterDockMenu = viewMenu->addMenu(QString());
printingSelectorDockMenu = viewMenu->addMenu(QString());
aCardInfoDockVisible = cardInfoDockMenu->addAction(QString());
aCardInfoDockVisible->setCheckable(true);
@ -371,6 +401,13 @@ void TabDeckEditor::createMenus()
aFilterDockFloating->setCheckable(true);
connect(aFilterDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
aPrintingSelectorDockVisible = printingSelectorDockMenu->addAction(QString());
aPrintingSelectorDockVisible->setCheckable(true);
connect(aPrintingSelectorDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
aPrintingSelectorDockFloating = printingSelectorDockMenu->addAction(QString());
aPrintingSelectorDockFloating->setCheckable(true);
connect(aPrintingSelectorDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
viewMenu->addSeparator();
aResetLayout = viewMenu->addAction(QString());
@ -426,6 +463,8 @@ void TabDeckEditor::createCentralFrame()
connect(databaseView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(databaseCustomMenu(QPoint)));
connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
SLOT(updateCardInfoLeft(const QModelIndex &, const QModelIndex &)));
connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
SLOT(updatePrintingSelectorDatabase(const QModelIndex &, const QModelIndex &)));
connect(databaseView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actAddCard()));
QByteArray dbHeaderState = SettingsCache::instance().layouts().getDeckEditorDbHeaderState();
@ -465,6 +504,7 @@ void TabDeckEditor::createCentralFrame()
centralWidget = new QWidget(this);
centralWidget->setObjectName("centralWidget");
centralWidget->setLayout(centralFrame);
centralWidget->setMaximumSize(900, 5000);
setCentralWidget(centralWidget);
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
}
@ -475,11 +515,14 @@ void TabDeckEditor::databaseCustomMenu(QPoint point)
const CardInfoPtr info = currentCardInfo();
// add to deck and sideboard options
QAction *addToDeck, *addToSideboard;
QAction *addToDeck, *addToSideboard, *selectPrinting;
addToDeck = menu.addAction(tr("Add to Deck"));
addToSideboard = menu.addAction(tr("Add to Sideboard"));
selectPrinting = menu.addAction(tr("Select Printing"));
connect(addToDeck, SIGNAL(triggered()), this, SLOT(actAddCard()));
connect(addToSideboard, SIGNAL(triggered()), this, SLOT(actAddCardToSideboard()));
connect(selectPrinting, &QAction::triggered, this, [this, info] { this->showPrintingSelector(); });
// filling out the related cards submenu
auto *relatedMenu = new QMenu(tr("Show Related cards"));
@ -498,36 +541,58 @@ void TabDeckEditor::databaseCustomMenu(QPoint point)
menu.exec(databaseView->mapToGlobal(point));
}
void TabDeckEditor::decklistCustomMenu(QPoint point)
{
QMenu menu;
const CardInfoPtr info = cardInfo->getInfo();
QAction *selectPrinting = menu.addAction(tr("Select Printing"));
connect(selectPrinting, &QAction::triggered, this, &TabDeckEditor::showPrintingSelector);
menu.exec(deckView->mapToGlobal(point));
}
void TabDeckEditor::showPrintingSelector()
{
printingSelector->setCard(cardInfo->getInfo(), DECK_ZONE_MAIN);
printingSelector->updateDisplay();
aPrintingSelectorDockVisible->setChecked(true);
printingSelectorDock->setVisible(true);
}
void TabDeckEditor::restartLayout()
{
deckDock->setVisible(true);
cardInfoDock->setVisible(true);
filterDock->setVisible(true);
printingSelectorDock->setVisible(false);
deckDock->setFloating(false);
cardInfoDock->setFloating(false);
filterDock->setFloating(false);
printingSelectorDock->setFloating(false);
aCardInfoDockVisible->setChecked(true);
aDeckDockVisible->setChecked(true);
aFilterDockVisible->setChecked(true);
aPrintingSelectorDockVisible->setChecked(false);
aCardInfoDockFloating->setChecked(false);
aDeckDockFloating->setChecked(false);
aFilterDockFloating->setChecked(false);
aPrintingSelectorDockFloating->setChecked(false);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), deckDock);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), cardInfoDock);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), filterDock);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), printingSelectorDock);
splitDockWidget(cardInfoDock, deckDock, Qt::Horizontal);
splitDockWidget(cardInfoDock, printingSelectorDock, Qt::Horizontal);
splitDockWidget(printingSelectorDock, deckDock, Qt::Horizontal);
splitDockWidget(cardInfoDock, printingSelectorDock, Qt::Horizontal);
splitDockWidget(cardInfoDock, filterDock, Qt::Vertical);
deckDock->setMinimumWidth(360);
deckDock->setMaximumWidth(360);
cardInfoDock->setMinimumSize(250, 360);
cardInfoDock->setMaximumSize(250, 360);
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
}
@ -541,6 +606,11 @@ void TabDeckEditor::freeDocksSize()
filterDock->setMinimumSize(100, 100);
filterDock->setMaximumSize(5000, 5000);
printingSelectorDock->setMinimumSize(525, 100);
printingSelectorDock->setMaximumSize(5000, 5000);
centralWidget->setMaximumSize(900, 5000);
}
void TabDeckEditor::refreshShortcuts()
@ -583,14 +653,17 @@ void TabDeckEditor::loadLayout()
aCardInfoDockVisible->setChecked(cardInfoDock->isVisible());
aFilterDockVisible->setChecked(filterDock->isVisible());
aDeckDockVisible->setChecked(deckDock->isVisible());
aPrintingSelectorDockVisible->setChecked(printingSelectorDock->isVisible());
aCardInfoDockFloating->setEnabled(aCardInfoDockVisible->isChecked());
aDeckDockFloating->setEnabled(aDeckDockVisible->isChecked());
aFilterDockFloating->setEnabled(aFilterDockVisible->isChecked());
aPrintingSelectorDockFloating->setEnabled(aPrintingSelectorDockVisible->isChecked());
aCardInfoDockFloating->setChecked(cardInfoDock->isFloating());
aFilterDockFloating->setChecked(filterDock->isFloating());
aDeckDockFloating->setChecked(deckDock->isFloating());
aPrintingSelectorDockFloating->setChecked(printingSelectorDock->isFloating());
cardInfoDock->setMinimumSize(layouts.getDeckEditorCardSize());
cardInfoDock->setMaximumSize(layouts.getDeckEditorCardSize());
@ -601,6 +674,9 @@ void TabDeckEditor::loadLayout()
deckDock->setMinimumSize(layouts.getDeckEditorDeckSize());
deckDock->setMaximumSize(layouts.getDeckEditorDeckSize());
printingSelectorDock->setMinimumSize(layouts.getDeckEditorPrintingSelectorSize());
printingSelectorDock->setMaximumSize(layouts.getDeckEditorPrintingSelectorSize());
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
}
@ -616,6 +692,7 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
createDeckDock();
createCardInfoDock();
createFiltersDock();
createPrintingSelectorDock();
this->installEventFilter(this);
@ -675,11 +752,13 @@ void TabDeckEditor::retranslateUi()
cardInfoDock->setWindowTitle(tr("Card Info"));
deckDock->setWindowTitle(tr("Deck"));
filterDock->setWindowTitle(tr("Filters"));
printingSelectorDock->setWindowTitle(tr("Printing Selector"));
viewMenu->setTitle(tr("&View"));
cardInfoDockMenu->setTitle(tr("Card Info"));
deckDockMenu->setTitle(tr("Deck"));
filterDockMenu->setTitle(tr("Filters"));
printingSelectorDockMenu->setTitle(tr("Printing"));
aCardInfoDockVisible->setText(tr("Visible"));
aCardInfoDockFloating->setText(tr("Floating"));
@ -690,6 +769,9 @@ void TabDeckEditor::retranslateUi()
aFilterDockVisible->setText(tr("Visible"));
aFilterDockFloating->setText(tr("Floating"));
aPrintingSelectorDockVisible->setText(tr("Visible"));
aPrintingSelectorDockFloating->setText(tr("Floating"));
aResetLayout->setText(tr("Reset layout"));
}
@ -715,6 +797,11 @@ void TabDeckEditor::updateComments()
setSaveStatus(true);
}
void TabDeckEditor::updateCardInfo(CardInfoPtr _card)
{
cardInfo->setCard(_card);
}
void TabDeckEditor::updateCardInfoLeft(const QModelIndex &current, const QModelIndex & /*previous*/)
{
cardInfo->setCard(current.sibling(current.row(), 0).data().toString());
@ -730,6 +817,43 @@ void TabDeckEditor::updateCardInfoRight(const QModelIndex &current, const QModel
}
}
void TabDeckEditor::updatePrintingSelectorDatabase(const QModelIndex &current, const QModelIndex & /*previous*/)
{
const QString cardName = current.sibling(current.row(), 0).data().toString();
const QString cardProviderID = CardDatabaseManager::getInstance()->getPreferredPrintingProviderIdForCard(cardName);
if (!current.isValid()) {
return;
}
if (!current.model()->hasChildren(current.sibling(current.row(), 0))) {
printingSelector->setCard(
CardDatabaseManager::getInstance()->getCardByNameAndProviderId(cardName, cardProviderID), DECK_ZONE_MAIN);
}
}
void TabDeckEditor::updatePrintingSelectorDeckView(const QModelIndex &current, const QModelIndex & /*previous*/)
{
const QString cardName = current.sibling(current.row(), 1).data().toString();
const QString cardProviderID = current.sibling(current.row(), 4).data().toString();
const QModelIndex gparent = current.parent().parent();
if (!gparent.isValid()) {
return;
}
const QString zoneName = gparent.sibling(gparent.row(), 1).data(Qt::EditRole).toString();
if (!current.isValid()) {
return;
}
if (!current.model()->hasChildren(current.sibling(current.row(), 0))) {
printingSelector->setCard(
CardDatabaseManager::getInstance()->getCardByNameAndProviderId(cardName, cardProviderID), zoneName);
}
}
void TabDeckEditor::updateSearch(const QString &search)
{
databaseDisplayModel->setStringFilter(search);
@ -1096,7 +1220,7 @@ void TabDeckEditor::actSwapCard()
if (!currentIndex.isValid())
return;
const QString cardName = currentIndex.sibling(currentIndex.row(), 1).data().toString();
const QString cardProviderID = currentIndex.sibling(currentIndex.row(), 2).data().toString();
const QString cardProviderID = currentIndex.sibling(currentIndex.row(), 4).data().toString();
const QModelIndex gparent = currentIndex.parent().parent();
if (!gparent.isValid())
@ -1270,6 +1394,9 @@ bool TabDeckEditor::eventFilter(QObject *o, QEvent *e)
} else if (o == filterDock) {
aFilterDockVisible->setChecked(false);
aFilterDockFloating->setEnabled(false);
} else if (o == printingSelectorDock) {
aPrintingSelectorDockVisible->setChecked(false);
aPrintingSelectorDockFloating->setEnabled(false);
}
}
if (o == this && e->type() == QEvent::Hide) {
@ -1279,6 +1406,7 @@ bool TabDeckEditor::eventFilter(QObject *o, QEvent *e)
layouts.setDeckEditorCardSize(cardInfoDock->size());
layouts.setDeckEditorFilterSize(filterDock->size());
layouts.setDeckEditorDeckSize(deckDock->size());
layouts.setDeckEditorPrintingSelectorSize(printingSelectorDock->size());
}
return false;
}
@ -1303,6 +1431,12 @@ void TabDeckEditor::dockVisibleTriggered()
aFilterDockFloating->setEnabled(aFilterDockVisible->isChecked());
return;
}
if (o == aPrintingSelectorDockVisible) {
printingSelectorDock->setVisible(aPrintingSelectorDockVisible->isChecked());
aPrintingSelectorDockFloating->setEnabled(aPrintingSelectorDockVisible->isChecked());
return;
}
}
void TabDeckEditor::dockFloatingTriggered()
@ -1322,6 +1456,11 @@ void TabDeckEditor::dockFloatingTriggered()
filterDock->setFloating(aFilterDockFloating->isChecked());
return;
}
if (o == aPrintingSelectorDockFloating) {
printingSelectorDock->setFloating(aPrintingSelectorDockFloating->isChecked());
return;
}
}
void TabDeckEditor::dockTopLevelChanged(bool topLevel)
@ -1341,6 +1480,11 @@ void TabDeckEditor::dockTopLevelChanged(bool topLevel)
aFilterDockFloating->setChecked(topLevel);
return;
}
if (o == printingSelectorDock) {
aPrintingSelectorDockFloating->setChecked(topLevel);
return;
}
}
void TabDeckEditor::saveDbHeaderState()

View file

@ -4,6 +4,7 @@
#include "../../deck/custom_line_edit.h"
#include "../../game/cards/card_database.h"
#include "../game_logic/key_signals.h"
#include "../ui/widgets/printing_selector/printing_selector.h"
#include "tab.h"
#include <QAbstractItemModel>
@ -55,8 +56,11 @@ private slots:
void updateHash();
void updateCardInfoLeft(const QModelIndex &current, const QModelIndex &previous);
void updateCardInfoRight(const QModelIndex &current, const QModelIndex &previous);
void updatePrintingSelectorDatabase(const QModelIndex &current, const QModelIndex &previous);
void updatePrintingSelectorDeckView(const QModelIndex &current, const QModelIndex &previous);
void updateSearch(const QString &search);
void databaseCustomMenu(QPoint point);
void decklistCustomMenu(QPoint point);
void actNewDeck();
void actLoadDeck();
@ -129,6 +133,7 @@ private:
QTreeView *deckView;
KeySignals deckViewKeySignals;
CardInfoFrameWidget *cardInfo;
PrintingSelector *printingSelector;
SearchLineEdit *searchEdit;
KeySignals searchKeySignals;
@ -143,8 +148,8 @@ private:
KeySignals filterViewKeySignals;
QWidget *filterBox;
QMenu *deckMenu, *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu, *analyzeDeckMenu,
*saveDeckToClipboardMenu;
QMenu *deckMenu, *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu, *printingSelectorDockMenu,
*analyzeDeckMenu, *saveDeckToClipboardMenu;
QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, *aSaveDeckToClipboard,
*aSaveDeckToClipboardRaw, *aPrintDeck, *aExportDeckDecklist, *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout,
*aClose;
@ -152,7 +157,7 @@ private:
QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement;
QAction *aResetLayout;
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating, *aFilterDockVisible,
*aFilterDockFloating;
*aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
bool modified;
QVBoxLayout *centralFrame;
@ -160,6 +165,7 @@ private:
QDockWidget *cardInfoDock;
QDockWidget *deckDock;
QDockWidget *filterDock;
QDockWidget *printingSelectorDock;
QWidget *centralWidget;
public:
@ -173,11 +179,14 @@ public:
void createDeckDock();
void createCardInfoDock();
void createFiltersDock();
void createPrintingSelectorDock();
void createMenus();
void createCentralFrame();
void updateCardInfo(CardInfoPtr _card);
public slots:
void closeRequest() override;
void showPrintingSelector();
signals:
void openDeckEditor(const DeckLoader *deckLoader);
void deckEditorClosing(TabDeckEditor *tab);

View file

@ -1807,9 +1807,9 @@ void TabGame::createDeckViewContainerWidget(bool bReplay)
deckViewContainerWidget->setLayout(deckViewContainerLayout);
}
void TabGame::viewCardInfo(const QString &cardName)
void TabGame::viewCardInfo(const QString &cardName, const QString &providerId) const
{
cardInfoFrameWidget->setCard(cardName);
cardInfoFrameWidget->setCard(cardName, providerId);
}
void TabGame::createCardInfoDock(bool bReplay)

View file

@ -313,7 +313,7 @@ public:
public slots:
void sendGameCommand(PendingCommand *pend, int playerId = -1);
void sendGameCommand(const ::google::protobuf::Message &command, int playerId = -1);
void viewCardInfo(const QString &cardName);
void viewCardInfo(const QString &cardName, const QString &providerId = "") const;
};
#endif

View file

@ -32,20 +32,28 @@ PictureToLoad::PictureToLoad(CardInfoPtr _card)
: card(std::move(_card)), urlTemplates(SettingsCache::instance().downloads().getAllURLs())
{
if (card) {
for (const auto &set : card->getSets()) {
sortedSets << set.getPtr();
for (const auto &cardInfoPerSetList : card->getSets()) {
for (const auto &set : cardInfoPerSetList) {
sortedSets << set.getPtr();
}
}
if (sortedSets.empty()) {
sortedSets << CardSet::newInstance("", "", "", QDate());
}
std::sort(sortedSets.begin(), sortedSets.end(), SetDownloadPriorityComparator());
// If the pixmapCacheKey corresponds to a specific set, we have to try to load it first.
for (const auto &set : card->getSets()) {
if (QLatin1String("card_") + card->getName() + QString("_") + QString(set.getProperty("uuid")) ==
card->getPixmapCacheKey()) {
long long setIndex = sortedSets.indexOf(set.getPtr());
CardSetPtr setForCardProviderID = sortedSets.takeAt(setIndex);
sortedSets.prepend(setForCardProviderID);
// If the user hasn't disabled arts other than their personal preference...
if (!SettingsCache::instance().getOverrideAllCardArtWithPersonalPreference()) {
// If the pixmapCacheKey corresponds to a specific set, we have to try to load it first.
for (const auto &cardInfoPerSetList : card->getSets()) {
for (const auto &set : cardInfoPerSetList) {
if (QLatin1String("card_") + card->getName() + QString("_") + QString(set.getProperty("uuid")) ==
card->getPixmapCacheKey()) {
long long setIndex = sortedSets.indexOf(set.getPtr());
CardSetPtr setForCardProviderID = sortedSets.takeAt(setIndex);
sortedSets.prepend(setForCardProviderID);
}
}
}
}
// The first time called, nextSet will also populate the Urls for the first set.
@ -717,6 +725,26 @@ void PictureLoader::getCardBackPixmap(QPixmap &pixmap, QSize size)
}
}
void PictureLoader::getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSize size)
{
QString backCacheKey = "_trice_card_back_" + QString::number(size.width()) + QString::number(size.height());
if (!QPixmapCache::find(backCacheKey, &pixmap)) {
qDebug() << "PictureLoader: cache fail for" << backCacheKey;
pixmap = QPixmap("theme:cardback").scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert(backCacheKey, pixmap);
}
}
void PictureLoader::getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize size)
{
QString backCacheKey = "_trice_card_back_" + QString::number(size.width()) + QString::number(size.height());
if (!QPixmapCache::find(backCacheKey, &pixmap)) {
qDebug() << "PictureLoader: cache fail for" << backCacheKey;
pixmap = QPixmap("theme:cardback").scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert(backCacheKey, pixmap);
}
}
void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
{
if (card == nullptr) {

View file

@ -142,6 +142,8 @@ private:
public:
static void getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size);
static void getCardBackPixmap(QPixmap &pixmap, QSize size);
static void getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSize size);
static void getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize size);
static void clearPixmapCache(CardInfoPtr card);
static void clearPixmapCache();
static void cacheCardPixmaps(QList<CardInfoPtr> cards);

View file

@ -30,7 +30,12 @@ public:
TextOnlyView,
ImageAndTextView
};
explicit CardInfoFrameWidget(const QString &cardName = QString(), QWidget *parent = nullptr);
CardInfoPtr getInfo()
{
return info;
}
void retranslateUi();
public slots:

View file

@ -92,13 +92,15 @@ void CardInfoPictureWidget::resizeEvent(QResizeEvent *event)
*/
void CardInfoPictureWidget::setScaleFactor(const int scale)
{
const int newWidth = baseWidth + scale * 20;
const int newWidth = baseWidth * scale / 100;
const int newHeight = static_cast<int>(newWidth * aspectRatio);
scaleFactor = scale;
setFixedSize(newWidth, newHeight);
updatePixmap();
emit cardScaleFactorChanged(scale);
}
/**
@ -119,10 +121,11 @@ void CardInfoPictureWidget::updatePixmap()
*/
void CardInfoPictureWidget::loadPixmap()
{
PictureLoader::getCardBackLoadingInProgressPixmap(resizedPixmap, size());
if (info) {
PictureLoader::getPixmap(resizedPixmap, info, size());
} else {
PictureLoader::getCardBackPixmap(resizedPixmap, size());
PictureLoader::getCardBackLoadingFailedPixmap(resizedPixmap, size());
}
pixmapDirty = false;

View file

@ -29,6 +29,7 @@ public slots:
signals:
void hoveredOnCard(CardInfoPtr hoveredCard);
void cardScaleFactorChanged(int _scale);
protected:
void resizeEvent(QResizeEvent *event) override;

View file

@ -0,0 +1,53 @@
#include "card_size_widget.h"
#include "../../../../settings/cache_settings.h"
/**
* @class CardSizeWidget
* @brief A widget for adjusting card sizes using a slider.
*
* This widget allows users to dynamically change the card size in a linked FlowWidget
* and updates the application's settings accordingly.
*/
CardSizeWidget::CardSizeWidget(QWidget *parent, FlowWidget *flowWidget, int defaultValue)
: parent(parent), flowWidget(flowWidget)
{
cardSizeLayout = new QHBoxLayout(this);
setLayout(cardSizeLayout);
cardSizeLabel = new QLabel(tr("Card Size"), this);
cardSizeLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
cardSizeSlider = new QSlider(Qt::Horizontal, this);
cardSizeSlider->setRange(50, 250); ///< Slider range for card size adjustment.
cardSizeSlider->setValue(defaultValue); ///< Initial slider value.
cardSizeLayout->addWidget(cardSizeLabel);
cardSizeLayout->addWidget(cardSizeSlider);
if (flowWidget != nullptr) {
connect(cardSizeSlider, &QSlider::valueChanged, flowWidget, &FlowWidget::setMinimumSizeToMaxSizeHint);
}
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardSizeWidget::updateCardSizeSetting);
}
/**
* @brief Updates the card size setting in the application's cache.
*
* @param newValue The new card size value set by the slider.
*/
void CardSizeWidget::updateCardSizeSetting(int newValue)
{
SettingsCache::instance().setPrintingSelectorCardSize(newValue);
}
/**
* @brief Gets the slider widget used for adjusting the card size.
*
* @return A pointer to the QSlider object.
*/
QSlider *CardSizeWidget::getSlider() const
{
return cardSizeSlider;
}

View file

@ -0,0 +1,29 @@
#ifndef CARD_SIZE_WIDGET_H
#define CARD_SIZE_WIDGET_H
#include "../general/layout_containers/flow_widget.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QSlider>
#include <QWidget>
class CardSizeWidget : public QWidget
{
Q_OBJECT
public:
explicit CardSizeWidget(QWidget *parent, FlowWidget *flowWidget = nullptr, int defaultValue = 100);
[[nodiscard]] QSlider *getSlider() const;
public slots:
static void updateCardSizeSetting(int newValue);
private:
QWidget *parent;
FlowWidget *flowWidget;
QHBoxLayout *cardSizeLayout;
QLabel *cardSizeLabel;
QSlider *cardSizeSlider;
};
#endif // CARD_SIZE_WIDGET_H

View file

@ -0,0 +1,137 @@
#include "dynamic_font_size_label.h"
#define FONT_PRECISION (0.5)
#include <QDebug>
#include <QElapsedTimer>
DynamicFontSizeLabel::DynamicFontSizeLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f)
{
setIndent(0);
}
void DynamicFontSizeLabel::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event)
emit clicked();
}
void DynamicFontSizeLabel::paintEvent(QPaintEvent *event)
{
// QElapsedTimer timer;
// timer.start();
QFont newFont = font();
float fontSize = getWidgetMaximumFontSize(this, this->text());
newFont.setPointSizeF(fontSize);
setFont(newFont);
// qDebug() << "Font size set to" << fontSize;
QLabel::paintEvent(event);
// LOG(true, "Paint delay" << ((float)timer.nsecsElapsed())/1000000.0 << " mS");
}
float DynamicFontSizeLabel::getWidgetMaximumFontSize(QWidget *widget, const QString &text)
{
QFont font = widget->font();
const QRect widgetRect = widget->contentsRect();
const float widgetWidth = widgetRect.width();
const float widgetHeight = widgetRect.height();
QRectF newFontSizeRect;
float currentSize = font.pointSizeF();
float step = currentSize / 2.0;
/* If too small, increase step */
if (step <= FONT_PRECISION) {
step = FONT_PRECISION * 4.0;
}
float lastTestedSize = currentSize;
float currentHeight = 0;
float currentWidth = 0;
if (text == "") {
return currentSize;
}
if (currentSize < 0) {
return 1;
}
/* Only stop when step is small enough and new size is smaller than QWidget */
while (step > FONT_PRECISION || (currentHeight > widgetHeight) || (currentWidth > widgetWidth)) {
/* Keep last tested value */
lastTestedSize = currentSize;
/* Test label with its font */
font.setPointSizeF(currentSize);
/* Use font metrics to test */
QFontMetricsF fm(font);
/* Check if widget is QLabel */
QLabel *label = qobject_cast<QLabel *>(widget);
if (label) {
newFontSizeRect =
fm.boundingRect(widgetRect, (label->wordWrap() ? Qt::TextWordWrap : 0) | label->alignment(), text);
} else {
newFontSizeRect = fm.boundingRect(widgetRect, 0, text);
}
currentHeight = newFontSizeRect.height();
currentWidth = newFontSizeRect.width();
/* If new font size is too big, decrease it */
if ((currentHeight > widgetHeight) || (currentWidth > widgetWidth)) {
// qDebug() << "-- contentsRect()" << label->contentsRect() << "rect"<< label->rect() << " newFontSizeRect"
// << newFontSizeRect << "Tight" << text << currentSize;
currentSize -= step;
/* if step is small enough, keep it constant, so it converge to biggest font size */
if (step > FONT_PRECISION) {
step /= 2.0;
}
/* Do not allow negative size */
if (currentSize <= 0) {
break;
}
}
/* If new font size is smaller than maximum possible size, increase it */
else {
// qDebug() << "++ contentsRect()" << label->contentsRect() << "rect"<< label->rect() << " newFontSizeRect"
// << newFontSizeRect << "Tight" << text << currentSize;
currentSize += step;
}
}
return lastTestedSize;
}
void DynamicFontSizeLabel::setTextColor(QColor color)
{
if (color.isValid() && color != textColor) {
textColor = color;
setStyleSheet("color : " + color.name() + ";");
}
}
QColor DynamicFontSizeLabel::getTextColor()
{
return textColor;
}
void DynamicFontSizeLabel::setTextAndColor(const QString &text, QColor color)
{
setTextColor(color);
setText(text);
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizeLabel::minimumSizeHint() const
{
return QWidget::minimumSizeHint();
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizeLabel::sizeHint() const
{
return QWidget::sizeHint();
}

View file

@ -0,0 +1,41 @@
#ifndef DYNAMICFONTSIZELABEL_H
#define DYNAMICFONTSIZELABEL_H
#include <QColor>
#include <QLabel>
class DynamicFontSizeLabel : public QLabel
{
Q_OBJECT
public:
explicit DynamicFontSizeLabel(QWidget *parent = NULL, Qt::WindowFlags f = Qt::WindowFlags());
~DynamicFontSizeLabel()
{
}
static float getWidgetMaximumFontSize(QWidget *widget, const QString &text);
/* This method overwrite stylesheet */
void setTextColor(QColor color);
QColor getTextColor();
void setTextAndColor(const QString &text, QColor color = QColor::Invalid);
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *event);
QColor textColor;
// QWidget interface
protected:
void paintEvent(QPaintEvent *event);
// QWidget interface
public:
QSize minimumSizeHint() const;
QSize sizeHint() const;
};
#endif // DYNAMICFONTSIZELABEL_H

View file

@ -0,0 +1,80 @@
#include "dynamic_font_size_push_button.h"
#include "dynamic_font_size_label.h"
#include <QDebug>
#include <QPainter>
DynamicFontSizePushButton::DynamicFontSizePushButton(QWidget *parent) : QPushButton(parent)
{
}
void DynamicFontSizePushButton::paintEvent(QPaintEvent *event)
{
// Call the base class paintEvent to preserve any other painting behavior
QPushButton::paintEvent(event);
// Adjust the font size dynamically based on the text
QFont newFont = font();
float fontSize = DynamicFontSizeLabel::getWidgetMaximumFontSize(this, this->text());
newFont.setPointSizeF(fontSize);
setFont(newFont);
// Get painter for custom painting
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// Paint the background with a linear gradient (normal state)
QLinearGradient gradient(0, 0, 0, height());
if (isDown()) {
// Pressed state
gradient.setColorAt(0, QColor(128, 128, 128));
gradient.setColorAt(1, QColor(64, 64, 64));
} else if (underMouse()) {
// Hover state
gradient.setColorAt(0, QColor(96, 96, 96));
gradient.setColorAt(1, QColor(48, 48, 48));
} else {
// Normal state
gradient.setColorAt(0, QColor(64, 64, 64)); // start color
gradient.setColorAt(1, QColor(32, 32, 32)); // end color
}
painter.setBrush(gradient);
painter.setPen(Qt::NoPen); // No border
painter.drawRect(rect());
// Paint the button text
painter.setPen(QPen(textColor.isValid() ? textColor : QColor(255, 255, 255))); // Set text color
painter.drawText(rect(), Qt::AlignCenter, text());
}
void DynamicFontSizePushButton::setTextColor(QColor color)
{
if (color.isValid() && color != textColor) {
textColor = color;
update(); // Request a repaint to update the text color
}
}
void DynamicFontSizePushButton::setTextAndColor(const QString &text, QColor color)
{
setTextColor(color);
setText(text);
}
QColor DynamicFontSizePushButton::getTextColor()
{
return textColor;
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizePushButton::minimumSizeHint() const
{
return QWidget::minimumSizeHint();
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizePushButton::sizeHint() const
{
return QWidget::sizeHint();
}

View file

@ -0,0 +1,29 @@
#ifndef DYNAMICFONTSIZEPUSHBUTTON_H
#define DYNAMICFONTSIZEPUSHBUTTON_H
#include <QObject>
#include <QPushButton>
#include <QWidget>
class DynamicFontSizePushButton : public QPushButton
{
public:
explicit DynamicFontSizePushButton(QWidget *parent = NULL);
/* This method overwrite stylesheet */
void setTextColor(QColor color);
QColor getTextColor();
void setTextAndColor(const QString &text, QColor color = QColor::Invalid);
// QWidget interface
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent *event);
private:
QColor textColor;
};
#endif // DYNAMICFONTSIZEPUSHBUTTON_H

View file

@ -0,0 +1,63 @@
#include "shadow_background_label.h"
#include <QPaintEvent>
#include <QPainter>
/**
* @class ShadowBackgroundLabel
* @brief A QLabel with a semi-transparent black shadowed background and rounded corners.
*
* This label provides a styled appearance with centered white text and a translucent
* rounded background, making it suitable for overlay or emphasis in a UI.
*/
ShadowBackgroundLabel::ShadowBackgroundLabel(QWidget *parent, const QString &text) : QLabel(parent)
{
setAttribute(Qt::WA_TranslucentBackground); // Allows transparency.
setText("<font color='white'>" + text + "</font>"); ///< Ensures the text is rendered in white.
setAlignment(Qt::AlignCenter); ///< Centers the text within the label.
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ///< Ensures minimum size constraints.
}
/**
* @brief Handles resizing of the label.
*
* Ensures the label updates its appearance when resized by triggering a repaint.
*
* @param event The resize event containing new size information.
*/
void ShadowBackgroundLabel::resizeEvent(QResizeEvent *event)
{
QLabel::resizeEvent(event);
update(); // Repaint borders explicitly.
}
/**
* @brief Custom paint event for drawing the label's background.
*
* Renders a semi-transparent black rounded rectangle as the background
* and then delegates text rendering to QLabel.
*
* @param event The paint event for the widget.
*/
void ShadowBackgroundLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// Enable antialiasing for smoother edges.
painter.setRenderHint(QPainter::Antialiasing, true);
// Set semi-transparent black brush and disable border pen.
painter.setBrush(QColor(0, 0, 0, 128)); // Semi-transparent black.
painter.setPen(Qt::NoPen); // No border.
// Adjust the rectangle to account for margins.
QRect adjustedRect = this->rect();
int margin = contentsMargins().left(); // Assuming equal margins.
adjustedRect.adjust(margin, margin, -margin, -margin);
// Draw a rounded rectangle with a corner radius of 5.
painter.drawRoundedRect(adjustedRect, 5, 5);
// Delegate text rendering to QLabel.
QLabel::paintEvent(event);
}

View file

@ -0,0 +1,18 @@
#ifndef STYLEDLABEL_H
#define STYLEDLABEL_H
#include <QLabel>
class ShadowBackgroundLabel : public QLabel
{
Q_OBJECT
public:
explicit ShadowBackgroundLabel(QWidget *parent, const QString &text);
protected:
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override; // Custom painting logic
};
#endif // STYLEDLABEL_H

View file

@ -5,7 +5,6 @@
#include "flow_widget.h"
#include "../../../layouts/flow_layout.h"
#include "../../../layouts/horizontal_flow_layout.h"
#include "../../../layouts/vertical_flow_layout.h"
@ -29,21 +28,21 @@ FlowWidget::FlowWidget(QWidget *parent,
// Main Widget and Layout
this->setMinimumSize(0, 0);
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
main_layout = new QHBoxLayout();
this->setLayout(main_layout);
mainLayout = new QHBoxLayout();
this->setLayout(mainLayout);
// Flow Layout inside the scroll area
container = new QWidget();
if (horizontalPolicy != Qt::ScrollBarAlwaysOff && verticalPolicy == Qt::ScrollBarAlwaysOff) {
flow_layout = new HorizontalFlowLayout(container);
flowLayout = new HorizontalFlowLayout(container);
} else if (horizontalPolicy == Qt::ScrollBarAlwaysOff && verticalPolicy != Qt::ScrollBarAlwaysOff) {
flow_layout = new VerticalFlowLayout(container);
flowLayout = new VerticalFlowLayout(container);
} else {
flow_layout = new FlowLayout(container, 0, 0, 0);
flowLayout = new FlowLayout(container, 0, 0, 0);
}
container->setLayout(flow_layout);
container->setLayout(flowLayout);
// The container should expand as much as possible, trusting the scrollArea to constrain it.
container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
container->setMinimumSize(0, 0);
@ -60,10 +59,10 @@ FlowWidget::FlowWidget(QWidget *parent,
// Use the FlowLayout container directly if we disable the ScrollArea
if (horizontalPolicy == Qt::ScrollBarAlwaysOff && verticalPolicy == Qt::ScrollBarAlwaysOff) {
main_layout->addWidget(container);
mainLayout->addWidget(container);
} else {
scrollArea->setWidget(container);
main_layout->addWidget(scrollArea);
mainLayout->addWidget(scrollArea);
}
}
@ -85,7 +84,7 @@ void FlowWidget::addWidget(QWidget *widget_to_add) const
}
// Add the widget to the flow layout
this->flow_layout->addWidget(widget_to_add);
flowLayout->addWidget(widget_to_add);
}
/**
@ -95,23 +94,23 @@ void FlowWidget::addWidget(QWidget *widget_to_add) const
*/
void FlowWidget::clearLayout()
{
if (flow_layout != nullptr) {
if (flowLayout != nullptr) {
QLayoutItem *item;
while ((item = flow_layout->takeAt(0)) != nullptr) {
while ((item = flowLayout->takeAt(0)) != nullptr) {
item->widget()->deleteLater(); // Delete the widget
delete item; // Delete the layout item
}
} else {
if (scrollArea->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff &&
scrollArea->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
flow_layout = new HorizontalFlowLayout(container);
flowLayout = new HorizontalFlowLayout(container);
} else if (scrollArea->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff &&
scrollArea->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
flow_layout = new VerticalFlowLayout(container);
flowLayout = new VerticalFlowLayout(container);
} else {
flow_layout = new FlowLayout(container, 0, 0, 0);
flowLayout = new FlowLayout(container, 0, 0, 0);
}
this->container->setLayout(flow_layout);
container->setLayout(flowLayout);
}
}
@ -127,15 +126,52 @@ void FlowWidget::resizeEvent(QResizeEvent *event)
QWidget::resizeEvent(event);
// Trigger the layout to recalculate
if (flow_layout != nullptr) {
flow_layout->invalidate(); // Marks the layout as dirty and requires recalculation
flow_layout->activate(); // Recalculate the layout based on the new size
if (flowLayout != nullptr) {
flowLayout->invalidate(); // Marks the layout as dirty and requires recalculation
flowLayout->activate(); // Recalculate the layout based on the new size
}
// Ensure the scroll area and its content adjust correctly
if (scrollArea != nullptr) {
if (scrollArea->widget() != nullptr) {
scrollArea->widget()->adjustSize();
if (scrollArea != nullptr && scrollArea->widget() != nullptr) {
scrollArea->widget()->adjustSize();
}
}
/**
* @brief Sets the minimum size for all widgets inside the FlowWidget to the maximum sizeHint of all of them.
*/
void FlowWidget::setMinimumSizeToMaxSizeHint()
{
QSize maxSize(0, 0); // Initialize to a zero size
// Iterate over all widgets in the flow layout to find the maximum sizeHint
for (int i = 0; i < flowLayout->count(); ++i) {
if (QLayoutItem *item = flowLayout->itemAt(i)) {
if (QWidget *widget = item->widget()) {
// Update the max size based on the sizeHint of each widget
QSize widgetSizeHint = widget->sizeHint();
maxSize.setWidth(qMax(maxSize.width(), widgetSizeHint.width()));
maxSize.setHeight(qMax(maxSize.height(), widgetSizeHint.height()));
}
}
}
// Set the minimum size for all widgets to the max sizeHint
for (int i = 0; i < flowLayout->count(); ++i) {
if (QLayoutItem *item = flowLayout->itemAt(i)) {
if (QWidget *widget = item->widget()) {
widget->setMinimumSize(maxSize);
}
}
}
}
QLayoutItem *FlowWidget::itemAt(int index) const
{
return flowLayout->itemAt(index);
}
int FlowWidget::count() const
{
return flowLayout->count();
}

View file

@ -14,15 +14,20 @@ public:
FlowWidget(QWidget *parent, Qt::ScrollBarPolicy horizontalPolicy, Qt::ScrollBarPolicy verticalPolicy);
void addWidget(QWidget *widget_to_add) const;
void clearLayout();
[[nodiscard]] int count() const;
[[nodiscard]] QLayoutItem *itemAt(int index) const;
QScrollArea *scrollArea;
public slots:
void setMinimumSizeToMaxSizeHint();
protected:
void resizeEvent(QResizeEvent *event) override;
private:
QHBoxLayout *main_layout;
FlowLayout *flow_layout;
QHBoxLayout *mainLayout;
FlowLayout *flowLayout;
QWidget *container;
};

View file

@ -0,0 +1,120 @@
#include "all_zones_card_amount_widget.h"
#include "../general/display/shadow_background_label.h"
#include <QTimer>
/**
* @brief Constructor for the AllZonesCardAmountWidget class.
*
* Initializes the widget with its layout and sets up the connections and necessary
* UI elements for managing card counts in both the mainboard and sideboard zones.
*
* @param parent The parent widget.
* @param deckEditor Pointer to the TabDeckEditor.
* @param deckModel Pointer to the DeckListModel.
* @param deckView Pointer to the QTreeView for the deck display.
* @param cardSizeSlider Pointer to the QSlider used for dynamic font resizing.
* @param rootCard The root card for the widget.
* @param setInfoForCard The set information for the card.
*/
AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
TabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
CardInfoPtr rootCard,
CardInfoPerSet setInfoForCard)
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
rootCard(rootCard), setInfoForCard(setInfoForCard)
{
layout = new QVBoxLayout(this);
layout->setAlignment(Qt::AlignHCenter);
setLayout(layout);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setContentsMargins(5, 5, 5, 5); // Padding around the text
zoneLabelMainboard = new ShadowBackgroundLabel(this, tr("Mainboard"));
buttonBoxMainboard = new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard,
setInfoForCard, DECK_ZONE_MAIN);
zoneLabelSideboard = new ShadowBackgroundLabel(this, tr("Sideboard"));
buttonBoxSideboard = new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard,
setInfoForCard, DECK_ZONE_SIDE);
layout->addWidget(zoneLabelMainboard, 0, Qt::AlignHCenter | Qt::AlignBottom);
layout->addWidget(buttonBoxMainboard, 0, Qt::AlignHCenter | Qt::AlignTop);
layout->addSpacing(25);
layout->addWidget(zoneLabelSideboard, 0, Qt::AlignHCenter | Qt::AlignBottom);
layout->addWidget(buttonBoxSideboard, 0, Qt::AlignHCenter | Qt::AlignTop);
connect(cardSizeSlider, &QSlider::valueChanged, this, &AllZonesCardAmountWidget::adjustFontSize);
QTimer::singleShot(10, this, [this]() { adjustFontSize(this->cardSizeSlider->value()); });
setMouseTracking(true);
}
/**
* @brief Adjusts the font size of the zone labels based on the slider value.
*
* This method calculates the new font size as a percentage of the original font size
* based on the slider value and applies it to the zone label text.
*
* @param scalePercentage The scale percentage from the slider.
*/
void AllZonesCardAmountWidget::adjustFontSize(int scalePercentage)
{
const int minFontSize = 8; // Minimum font size
const int maxFontSize = 32; // Maximum font size
const int basePercentage = 100; // Scale at 100%
int newFontSize = minFontSize + (scalePercentage - basePercentage) * (maxFontSize - minFontSize) / 225;
newFontSize = std::clamp(newFontSize, minFontSize, maxFontSize);
// Update the font labels
QFont zoneLabelFont = zoneLabelMainboard->font();
zoneLabelFont.setPointSize(newFontSize);
zoneLabelMainboard->setFont(zoneLabelFont);
zoneLabelSideboard->setFont(zoneLabelFont);
// Repaint the widget (if necessary)
repaint();
}
/**
* @brief Gets the card count in the mainboard zone.
*
* @return The number of cards in the mainboard.
*/
int AllZonesCardAmountWidget::getMainboardAmount()
{
return buttonBoxMainboard->countCardsInZone(DECK_ZONE_MAIN);
}
/**
* @brief Gets the card count in the sideboard zone.
*
* @return The number of cards in the sideboard.
*/
int AllZonesCardAmountWidget::getSideboardAmount()
{
return buttonBoxSideboard->countCardsInZone(DECK_ZONE_SIDE);
}
/**
* @brief Handles the event when the mouse enters the widget.
*
* This method is triggered when the mouse enters the widget's area, allowing for updates
* or interactions such as UI feedback or layout changes.
*
* @param event The event information for the mouse entry.
*/
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
void AllZonesCardAmountWidget::enterEvent(QEnterEvent *event)
#else
void AllZonesCardAmountWidget::enterEvent(QEvent *event)
#endif
{
QWidget::enterEvent(event);
update();
}

View file

@ -0,0 +1,47 @@
#ifndef ALL_ZONES_CARD_AMOUNT_WIDGET_H
#define ALL_ZONES_CARD_AMOUNT_WIDGET_H
#include "../../../../deck/deck_list_model.h"
#include "../../../../deck/deck_loader.h"
#include "../../../../deck/deck_view.h"
#include "card_amount_widget.h"
#include <QVBoxLayout>
#include <QWidget>
class AllZonesCardAmountWidget : public QWidget
{
Q_OBJECT
public:
explicit AllZonesCardAmountWidget(QWidget *parent,
TabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
CardInfoPtr rootCard,
CardInfoPerSet setInfoForCard);
int getMainboardAmount();
int getSideboardAmount();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
void enterEvent(QEnterEvent *event) override;
#else
void enterEvent(QEvent *event) override;
#endif
public slots:
void adjustFontSize(int scalePercentage);
private:
QVBoxLayout *layout;
TabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
CardInfoPtr rootCard;
CardInfoPerSet setInfoForCard;
QLabel *zoneLabelMainboard;
CardAmountWidget *buttonBoxMainboard;
QLabel *zoneLabelSideboard;
CardAmountWidget *buttonBoxSideboard;
};
#endif // ALL_ZONES_CARD_AMOUNT_WIDGET_H

View file

@ -0,0 +1,293 @@
#include "card_amount_widget.h"
#include <QTimer>
/**
* @brief Constructs a widget for displaying and controlling the card count in a specific zone.
*
* @param parent The parent widget.
* @param deckEditor Pointer to the TabDeckEditor instance.
* @param deckModel Pointer to the DeckListModel instance.
* @param deckView Pointer to the QTreeView displaying the deck.
* @param cardSizeSlider Pointer to the QSlider for adjusting font size.
* @param rootCard The root card to manage within the widget.
* @param setInfoForCard Card set information for the root card.
* @param zoneName The zone name (e.g., DECK_ZONE_MAIN or DECK_ZONE_SIDE).
*/
CardAmountWidget::CardAmountWidget(QWidget *parent,
TabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
CardInfoPtr &rootCard,
CardInfoPerSet &setInfoForCard,
const QString &zoneName)
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
rootCard(rootCard), setInfoForCard(setInfoForCard), zoneName(zoneName), hovered(false)
{
layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(10);
this->setLayout(layout);
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
layout->setAlignment(Qt::AlignHCenter);
incrementButton = new DynamicFontSizePushButton(this);
incrementButton->setTextAndColor("+", Qt::white);
decrementButton = new DynamicFontSizePushButton(this);
decrementButton->setTextAndColor("-", Qt::white);
incrementButton->setFixedSize(parentWidget()->size().width() / 3, parentWidget()->size().height() / 9);
decrementButton->setFixedSize(parentWidget()->size().width() / 3, parentWidget()->size().height() / 9);
// Set up connections based on the zone (Mainboard or Sideboard)
if (zoneName == DECK_ZONE_MAIN) {
connect(incrementButton, &QPushButton::clicked, this, &CardAmountWidget::addPrintingMainboard);
connect(decrementButton, &QPushButton::clicked, this, &CardAmountWidget::removePrintingMainboard);
} else if (zoneName == DECK_ZONE_SIDE) {
connect(incrementButton, &QPushButton::clicked, this, &CardAmountWidget::addPrintingSideboard);
connect(decrementButton, &QPushButton::clicked, this, &CardAmountWidget::removePrintingSideboard);
}
cardCountInZone = new QLabel(QString::number(countCardsInZone(zoneName)), this);
cardCountInZone->setAlignment(Qt::AlignCenter);
layout->addWidget(decrementButton);
layout->addWidget(cardCountInZone);
layout->addWidget(incrementButton);
// React to model changes
connect(deckModel, &DeckListModel::dataChanged, this, &CardAmountWidget::updateCardCount);
connect(deckModel, &QAbstractItemModel::rowsRemoved, this, &CardAmountWidget::updateCardCount);
// Connect slider for dynamic font size adjustment
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardAmountWidget::adjustFontSize);
}
/**
* @brief Handles the painting of the widget, drawing a semi-transparent background.
*
* @param event The paint event.
*/
void CardAmountWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// Draw semi-transparent black background
painter.setBrush(QBrush(QColor(0, 0, 0, 128)));
painter.setPen(Qt::NoPen);
painter.drawRect(rect());
QWidget::paintEvent(event);
}
void CardAmountWidget::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
adjustFontSize(this->cardSizeSlider->value());
updateCardCount();
if (parentWidget()) {
int width = parentWidget()->size().width();
int height = parentWidget()->size().height();
incrementButton->setFixedSize(width / 3, height / 9);
decrementButton->setFixedSize(width / 3, height / 9);
}
}
/**
* @brief Adjusts the font size of the card count label based on the slider value.
*
* @param scalePercentage The percentage value from the slider for scaling the font size.
*/
void CardAmountWidget::adjustFontSize(int scalePercentage)
{
const int minFontSize = 8; ///< Minimum font size
const int maxFontSize = 32; ///< Maximum font size
const int basePercentage = 100; ///< Scale at 100%
int newFontSize = minFontSize + (scalePercentage - basePercentage) * (maxFontSize - minFontSize) / 225;
newFontSize = std::clamp(newFontSize, minFontSize, maxFontSize);
// Update the font for card count label
QFont cardCountFont = cardCountInZone->font();
cardCountFont.setPointSize(newFontSize);
cardCountInZone->setFont(cardCountFont);
incrementButton->setFixedSize(parentWidget()->size().width() / 3, parentWidget()->size().height() / 9);
decrementButton->setFixedSize(parentWidget()->size().width() / 3, parentWidget()->size().height() / 9);
// Repaint the widget
repaint();
}
/**
* @brief Updates the card count display in the widget.
*/
void CardAmountWidget::updateCardCount()
{
cardCountInZone->setText("<font color='white'>" + QString::number(countCardsInZone(zoneName)) + "</font>");
layout->invalidate();
layout->activate();
}
/**
* @brief Adds a printing of the card to the specified zone (Mainboard or Sideboard).
*
* @param zone The zone to add the card to (DECK_ZONE_MAIN or DECK_ZONE_SIDE).
*/
void CardAmountWidget::addPrinting(const QString &zone)
{
auto newCardIndex = deckModel->addCard(rootCard->getName(), setInfoForCard, zone);
recursiveExpand(newCardIndex);
QModelIndex find_card = deckModel->findCard(rootCard->getName(), zone);
if (find_card.isValid() && find_card != newCardIndex) {
auto amount = deckModel->data(find_card, Qt::DisplayRole);
for (int i = 0; i < amount.toInt() - 1; i++) {
deckModel->addCard(rootCard->getName(), setInfoForCard, zone);
}
deckModel->removeRow(find_card.row(), find_card.parent());
}
newCardIndex = deckModel->findCard(rootCard->getName(), zone, setInfoForCard.getProperty("uuid"),
setInfoForCard.getProperty("num"));
deckView->setCurrentIndex(newCardIndex);
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
}
/**
* @brief Adds a printing to the mainboard zone.
*/
void CardAmountWidget::addPrintingMainboard()
{
addPrinting(DECK_ZONE_MAIN);
}
/**
* @brief Adds a printing to the sideboard zone.
*/
void CardAmountWidget::addPrintingSideboard()
{
addPrinting(DECK_ZONE_SIDE);
}
/**
* @brief Removes a printing from the mainboard zone.
*/
void CardAmountWidget::removePrintingMainboard()
{
decrementCardHelper(DECK_ZONE_MAIN);
}
/**
* @brief Removes a printing from the sideboard zone.
*/
void CardAmountWidget::removePrintingSideboard()
{
decrementCardHelper(DECK_ZONE_SIDE);
}
/**
* @brief Recursively expands the card in the deck view starting from the given index.
*
* @param index The model index of the card to expand.
*/
void CardAmountWidget::recursiveExpand(const QModelIndex &index)
{
if (index.parent().isValid()) {
recursiveExpand(index.parent());
}
deckView->expand(index);
}
/**
* @brief Offsets the card count at the specified index by the given amount.
*
* @param idx The model index of the card.
* @param offset The amount to add or subtract from the card count.
*/
void CardAmountWidget::offsetCountAtIndex(const QModelIndex &idx, int offset)
{
if (!idx.isValid() || offset == 0) {
return;
}
const QModelIndex numberIndex = idx.sibling(idx.row(), 0);
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
const int new_count = count + offset;
deckView->setCurrentIndex(numberIndex);
if (new_count <= 0) {
deckModel->removeRow(idx.row(), idx.parent());
} else {
deckModel->setData(numberIndex, new_count, Qt::EditRole);
}
deckEditor->setModified(true);
}
/**
* @brief Helper function to decrement the card count for a given zone.
*
* @param zone The zone from which to remove the card (DECK_ZONE_MAIN or DECK_ZONE_SIDE).
*/
void CardAmountWidget::decrementCardHelper(const QString &zone)
{
QModelIndex idx = deckModel->findCard(rootCard->getName(), zone, setInfoForCard.getProperty("uuid"),
setInfoForCard.getProperty("num"));
offsetCountAtIndex(idx, -1);
}
/**
* @brief Counts the number of cards in a specific zone (mainboard or sideboard).
*
* @param deckZone The name of the zone (e.g., DECK_ZONE_MAIN or DECK_ZONE_SIDE).
* @return The number of cards in the zone.
*/
int CardAmountWidget::countCardsInZone(const QString &deckZone)
{
if (setInfoForCard.getProperty("uuid").isEmpty()) {
return 0; // Cards without uuids/providerIds CANNOT match another card, they are undefined for us.
}
if (!deckModel) {
return -1;
}
DeckList *decklist = deckModel->getDeckList();
if (!decklist) {
return -1;
}
InnerDecklistNode *listRoot = decklist->getRoot();
if (!listRoot) {
return -1;
}
int count = 0;
for (auto *i : *listRoot) {
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
if (!countCurrentZone) {
continue;
}
if (countCurrentZone->getName() != deckZone) {
continue;
}
for (auto *cardNode : *countCurrentZone) {
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
if (!currentCard) {
continue;
}
for (int k = 0; k < currentCard->getNumber(); ++k) {
if (currentCard->getCardProviderId() == setInfoForCard.getProperty("uuid")) {
count++;
}
}
}
}
return count;
}

View file

@ -0,0 +1,67 @@
#ifndef CARD_AMOUNT_WIDGET_H
#define CARD_AMOUNT_WIDGET_H
#include "../../../../deck/deck_list_model.h"
#include "../../../../deck/deck_loader.h"
#include "../../../../deck/deck_view.h"
#include "../../../../game/cards/card_database.h"
#include "../../../tabs/tab_deck_editor.h"
#include "../general/display/dynamic_font_size_push_button.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPropertyAnimation>
#include <QPushButton>
#include <QTreeView>
#include <QWidget>
class CardAmountWidget : public QWidget
{
Q_OBJECT
public:
explicit CardAmountWidget(QWidget *parent,
TabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
CardInfoPtr &rootCard,
CardInfoPerSet &setInfoForCard,
const QString &zoneName);
int countCardsInZone(const QString &deckZone);
public slots:
void updateCardCount();
void addPrinting(const QString &zone);
protected:
void paintEvent(QPaintEvent *event) override;
void showEvent(QShowEvent *event) override;
private:
TabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
CardInfoPtr rootCard;
CardInfoPerSet setInfoForCard;
QString zoneName;
QHBoxLayout *layout;
DynamicFontSizePushButton *incrementButton;
DynamicFontSizePushButton *decrementButton;
QLabel *cardCountInZone;
bool hovered;
void offsetCountAtIndex(const QModelIndex &idx, int offset);
void decrementCardHelper(const QString &zoneName);
void recursiveExpand(const QModelIndex &index);
private slots:
void addPrintingMainboard();
void addPrintingSideboard();
void removePrintingMainboard();
void removePrintingSideboard();
void adjustFontSize(int scalePercentage);
};
#endif // CARD_AMOUNT_WIDGET_H

View file

@ -0,0 +1,234 @@
#include "printing_selector.h"
#include "../../../../settings/cache_settings.h"
#include "printing_selector_card_display_widget.h"
#include "printing_selector_card_search_widget.h"
#include "printing_selector_card_selection_widget.h"
#include "printing_selector_card_sorting_widget.h"
#include "printing_selector_view_options_toolbar_widget.h"
#include <QScrollBar>
/**
* @brief Constructs a PrintingSelector widget to display and manage card printings.
*
* This constructor initializes the PrintingSelector widget, setting up various child widgets
* such as sorting tools, search bar, card size options, and navigation controls. It also connects
* signals and slots to update the display when the deck model changes, and loads available printings
* for the selected card.
*
* @param parent The parent widget for the PrintingSelector.
* @param deckEditor The TabDeckEditor instance used for managing the deck.
* @param deckModel The DeckListModel instance that provides data for the deck's contents.
* @param deckView The QTreeView instance used to display the deck and its contents.
*/
PrintingSelector::PrintingSelector(QWidget *parent,
TabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView)
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout = new QVBoxLayout();
setLayout(layout);
widgetLoadingBufferTimer = new QTimer(this);
// Initialize toolbar and widgets
viewOptionsToolbar = new PrintingSelectorViewOptionsToolbarWidget(this, this);
layout->addWidget(viewOptionsToolbar);
sortToolBar = new PrintingSelectorCardSortingWidget(this);
sortToolBar->setVisible(SettingsCache::instance().getPrintingSelectorSortOptionsVisible());
layout->addWidget(sortToolBar);
searchBar = new PrintingSelectorCardSearchWidget(this);
searchBar->setVisible(SettingsCache::instance().getPrintingSelectorSearchBarVisible());
layout->addWidget(searchBar);
flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
layout->addWidget(flowWidget);
cardSizeWidget = new CardSizeWidget(this, flowWidget, SettingsCache::instance().getPrintingSelectorCardSize());
cardSizeWidget->setVisible(SettingsCache::instance().getPrintingSelectorCardSizeSliderVisible());
layout->addWidget(cardSizeWidget);
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this);
cardSelectionBar->setVisible(SettingsCache::instance().getPrintingSelectorNavigationButtonsVisible());
layout->addWidget(cardSelectionBar);
// Connect deck model data change signal to update display
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
// Delay the update to avoid race conditions
QTimer::singleShot(100, this, &PrintingSelector::updateDisplay);
});
}
/**
* @brief Updates the display by clearing the layout and loading new sets for the current card.
*/
void PrintingSelector::updateDisplay()
{
widgetLoadingBufferTimer->stop();
widgetLoadingBufferTimer->deleteLater();
widgetLoadingBufferTimer = new QTimer(this);
flowWidget->clearLayout();
if (selectedCard != nullptr) {
setWindowTitle(selectedCard->getName());
}
getAllSetsForCurrentCard();
}
/**
* @brief Sets the current card for the selector and updates the display.
*
* @param newCard The new card to set.
* @param _currentZone The current zone the card is in.
*/
void PrintingSelector::setCard(const CardInfoPtr &newCard, const QString &_currentZone)
{
if (newCard.isNull()) {
return;
}
selectedCard = newCard;
currentZone = _currentZone;
if (isVisible()) {
updateDisplay();
}
flowWidget->setMinimumSizeToMaxSizeHint();
flowWidget->scrollArea->verticalScrollBar()->setValue(0);
flowWidget->repaint();
}
/**
* @brief Selects the previous card in the list.
*/
void PrintingSelector::selectPreviousCard()
{
selectCard(-1);
}
/**
* @brief Selects the next card in the list.
*/
void PrintingSelector::selectNextCard()
{
selectCard(1);
}
/**
* @brief Selects a card based on the change direction.
*
* @param changeBy The direction to change, -1 for previous, 1 for next.
*/
void PrintingSelector::selectCard(const int changeBy)
{
if (changeBy == 0) {
return;
}
// Get the current index of the selected item
auto deckViewCurrentIndex = deckView->currentIndex();
auto nextIndex = deckViewCurrentIndex.siblingAtRow(deckViewCurrentIndex.row() + changeBy);
if (!nextIndex.isValid()) {
nextIndex = deckViewCurrentIndex;
// Increment to the next valid index, skipping header rows
AbstractDecklistNode *node;
do {
if (changeBy > 0) {
nextIndex = deckView->indexBelow(nextIndex);
} else {
nextIndex = deckView->indexAbove(nextIndex);
}
node = static_cast<AbstractDecklistNode *>(nextIndex.internalPointer());
} while (node && node->isDeckHeader());
}
if (nextIndex.isValid()) {
deckView->setCurrentIndex(nextIndex);
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
}
}
/**
* @brief Loads and displays all sets for the current selected card.
*/
void PrintingSelector::getAllSetsForCurrentCard()
{
if (selectedCard.isNull()) {
return;
}
CardInfoPerSetMap cardInfoPerSets = selectedCard->getSets();
const QList<CardInfoPerSet> sortedSets = sortToolBar->sortSets(cardInfoPerSets);
const QList<CardInfoPerSet> filteredSets =
sortToolBar->filterSets(sortedSets, searchBar->getSearchText().trimmed().toLower());
QList<CardInfoPerSet> setsToUse;
if (SettingsCache::instance().getBumpSetsWithCardsInDeckToTop()) {
setsToUse = sortToolBar->prependPrintingsInDeck(filteredSets, selectedCard, deckModel);
} else {
setsToUse = filteredSets;
}
// Defer widget creation
currentIndex = 0;
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=]() mutable {
for (int i = 0; i < BATCH_SIZE && currentIndex < setsToUse.size(); ++i, ++currentIndex) {
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(this, deckEditor, deckModel, deckView,
cardSizeWidget->getSlider(), selectedCard,
setsToUse[currentIndex], currentZone);
flowWidget->addWidget(cardDisplayWidget);
cardDisplayWidget->clampSetNameToPicture();
}
// Stop timer when done
if (currentIndex >= setsToUse.size()) {
widgetLoadingBufferTimer->stop();
}
});
currentIndex = 0;
widgetLoadingBufferTimer->start(0); // Process as soon as possible
}
/**
* @brief Toggles the visibility of the sorting options toolbar.
*
* @param _state The visibility state to set.
*/
void PrintingSelector::toggleVisibilitySortOptions(bool _state)
{
sortToolBar->setVisible(_state);
}
/**
* @brief Toggles the visibility of the search bar.
*
* @param _state The visibility state to set.
*/
void PrintingSelector::toggleVisibilitySearchBar(bool _state)
{
searchBar->setVisible(_state);
}
/**
* @brief Toggles the visibility of the card size slider.
*
* @param _state The visibility state to set.
*/
void PrintingSelector::toggleVisibilityCardSizeSlider(bool _state)
{
cardSizeWidget->setVisible(_state);
}
/**
* @brief Toggles the visibility of the navigation buttons.
*
* @param _state The visibility state to set.
*/
void PrintingSelector::toggleVisibilityNavigationButtons(bool _state)
{
cardSelectionBar->setVisible(_state);
}

View file

@ -0,0 +1,58 @@
#ifndef PRINTING_SELECTOR_H
#define PRINTING_SELECTOR_H
#include "../../../../deck/deck_list_model.h"
#include "../../../../deck/deck_view.h"
#include "../../../../game/cards/card_database.h"
#include "../cards/card_size_widget.h"
#include "../general/layout_containers/flow_widget.h"
#include <QLabel>
#include <QTreeView>
#include <QVBoxLayout>
#include <QWidget>
#define BATCH_SIZE 10
class PrintingSelectorCardSearchWidget;
class PrintingSelectorCardSelectionWidget;
class PrintingSelectorCardSortingWidget;
class PrintingSelectorViewOptionsToolbarWidget;
class TabDeckEditor;
class PrintingSelector : public QWidget
{
Q_OBJECT
public:
PrintingSelector(QWidget *parent, TabDeckEditor *deckEditor, DeckListModel *deckModel, QTreeView *deckView);
void setCard(const CardInfoPtr &newCard, const QString &_currentZone);
void getAllSetsForCurrentCard();
public slots:
void updateDisplay();
void selectPreviousCard();
void selectNextCard();
void toggleVisibilitySortOptions(bool _state);
void toggleVisibilitySearchBar(bool _state);
void toggleVisibilityCardSizeSlider(bool _state);
void toggleVisibilityNavigationButtons(bool _state);
private:
QVBoxLayout *layout;
PrintingSelectorViewOptionsToolbarWidget *viewOptionsToolbar;
PrintingSelectorCardSortingWidget *sortToolBar;
PrintingSelectorCardSearchWidget *searchBar;
FlowWidget *flowWidget;
CardSizeWidget *cardSizeWidget;
PrintingSelectorCardSelectionWidget *cardSelectionBar;
TabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
CardInfoPtr selectedCard;
QString currentZone;
QTimer *widgetLoadingBufferTimer;
int currentIndex = 0;
void selectCard(int changeBy);
};
#endif // PRINTING_SELECTOR_H

View file

@ -0,0 +1,74 @@
#include "printing_selector_card_display_widget.h"
#include "card_amount_widget.h"
#include "printing_selector_card_overlay_widget.h"
#include "set_name_and_collectors_number_display_widget.h"
#include <QGraphicsEffect>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <utility>
/**
* @brief Constructs a PrintingSelectorCardDisplayWidget to display card information.
*
* This widget is responsible for displaying the selected card's printing information, including
* the card's image and set details. It also handles the layout of the card's display, including
* its size, set name, and collectors number. The card is displayed within a `QVBoxLayout` with
* two main components: the overlay (which combines the card image and buttons) and the set name and collectors number
* display.
*
* @param parent The parent widget for this display.
* @param deckEditor The TabDeckEditor instance for deck management.
* @param deckModel The DeckListModel instance providing deck data.
* @param deckView The QTreeView instance displaying the deck.
* @param cardSizeSlider The slider controlling the size of the displayed card.
* @param rootCard The root card object, representing the card to be displayed.
* @param setInfoForCard The set-specific information for the card being displayed.
* @param currentZone The current zone in which the card is located.
*/
PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *parent,
TabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
CardInfoPtr _rootCard,
const CardInfoPerSet &_setInfoForCard,
QString &_currentZone)
: QWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), deckView(_deckView),
cardSizeSlider(_cardSizeSlider), rootCard(std::move(_rootCard)), setInfoForCard(_setInfoForCard),
currentZone(_currentZone)
{
layout = new QVBoxLayout(this);
setLayout(layout);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Create the overlay widget for the card display
overlayWidget = new PrintingSelectorCardOverlayWidget(this, deckEditor, deckModel, deckView, cardSizeSlider,
rootCard, setInfoForCard);
// Create the widget to display the set name and collector's number
const QString combinedSetName =
QString(setInfoForCard.getPtr()->getLongName() + " (" + setInfoForCard.getPtr()->getShortName() + ")");
setNameAndCollectorsNumberDisplayWidget = new SetNameAndCollectorsNumberDisplayWidget(
this, combinedSetName, setInfoForCard.getProperty("num"), cardSizeSlider);
// Add the widgets to the layout
layout->addWidget(overlayWidget, 0, Qt::AlignHCenter);
layout->addWidget(setNameAndCollectorsNumberDisplayWidget, 1, Qt::AlignHCenter | Qt::AlignBottom);
}
/**
* @brief Adjusts the width of the set name display to fit the card overlay widget.
*
* This method ensures that the set name and collector's number display widget does not exceed
* the width of the card's overlay widget. It clamps the set name widget to match the width of
* the overlay widget and updates the display.
*/
void PrintingSelectorCardDisplayWidget::clampSetNameToPicture()
{
if (overlayWidget != nullptr && setNameAndCollectorsNumberDisplayWidget != nullptr) {
setNameAndCollectorsNumberDisplayWidget->setMaximumWidth(overlayWidget->width());
}
update();
}

View file

@ -0,0 +1,52 @@
#ifndef PRINTING_SELECTOR_CARD_DISPLAY_WIDGET_H
#define PRINTING_SELECTOR_CARD_DISPLAY_WIDGET_H
#include "../../../../client/ui/widgets/cards/card_info_picture_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../../../../deck/deck_view.h"
#include "../../../../game/cards/card_database.h"
#include "../../../tabs/tab_deck_editor.h"
#include "all_zones_card_amount_widget.h"
#include "card_amount_widget.h"
#include "printing_selector_card_overlay_widget.h"
#include "set_name_and_collectors_number_display_widget.h"
#include <QLabel>
#include <QPainter>
#include <QPushButton>
#include <QTreeView>
#include <QVBoxLayout>
#include <QWidget>
class PrintingSelectorCardDisplayWidget : public QWidget
{
Q_OBJECT
public:
PrintingSelectorCardDisplayWidget(QWidget *parent,
TabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
CardInfoPtr _rootCard,
const CardInfoPerSet &_setInfoForCard,
QString &_currentZone);
public slots:
void clampSetNameToPicture();
private:
QVBoxLayout *layout;
SetNameAndCollectorsNumberDisplayWidget *setNameAndCollectorsNumberDisplayWidget;
TabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
CardInfoPtr rootCard;
CardInfoPtr setCard;
CardInfoPerSet setInfoForCard;
QString currentZone;
PrintingSelectorCardOverlayWidget *overlayWidget;
};
#endif // PRINTING_SELECTOR_CARD_DISPLAY_WIDGET_H

View file

@ -0,0 +1,185 @@
#include "printing_selector_card_overlay_widget.h"
#include "../../../../game/cards/card_database_manager.h"
#include "printing_selector_card_display_widget.h"
#include <QMenu>
#include <QMouseEvent>
#include <QVBoxLayout>
#include <utility>
/**
* @brief Constructs a PrintingSelectorCardOverlayWidget for displaying a card overlay.
*
* This widget is responsible for showing the card's image and providing interactive features such
* as a context menu and the ability to adjust the card's scale. It includes the card's image as well
* as a widget that displays the card amounts in different zones (mainboard, sideboard, etc.).
*
* @param parent The parent widget for this overlay.
* @param deckEditor The TabDeckEditor instance for deck management.
* @param deckModel The DeckListModel instance providing deck data.
* @param deckView The QTreeView instance displaying the deck.
* @param cardSizeSlider The slider controlling the size of the card.
* @param rootCard The root card object that contains information about the card.
* @param setInfoForCard The set-specific information for the card being displayed.
*/
PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *parent,
TabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
CardInfoPtr _rootCard,
const CardInfoPerSet &_setInfoForCard)
: QWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), deckView(_deckView),
cardSizeSlider(_cardSizeSlider), rootCard(std::move(_rootCard)), setInfoForCard(_setInfoForCard)
{
// Set up the main layout
auto *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
setLayout(mainLayout);
// Add CardInfoPictureWidget
cardInfoPicture = new CardInfoPictureWidget(this);
cardInfoPicture->setMinimumSize(0, 0);
cardInfoPicture->setScaleFactor(cardSizeSlider->value());
setCard = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(rootCard->getName(),
setInfoForCard.getProperty("uuid"));
cardInfoPicture->setCard(setCard);
mainLayout->addWidget(cardInfoPicture);
// Add AllZonesCardAmountWidget
allZonesCardAmountWidget =
new AllZonesCardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, setCard, setInfoForCard);
allZonesCardAmountWidget->raise(); // Ensure it's on top of the picture
// Set initial visibility based on amounts
if (allZonesCardAmountWidget->getMainboardAmount() > 0 || allZonesCardAmountWidget->getSideboardAmount() > 0) {
allZonesCardAmountWidget->setVisible(true);
} else {
allZonesCardAmountWidget->setVisible(false);
}
// Attempt to cast the parent to PrintingSelectorCardDisplayWidget
if (const auto *parentWidget = qobject_cast<PrintingSelectorCardDisplayWidget *>(parent)) {
connect(cardInfoPicture, &CardInfoPictureWidget::cardScaleFactorChanged, parentWidget,
&PrintingSelectorCardDisplayWidget::clampSetNameToPicture);
}
connect(cardSizeSlider, &QSlider::valueChanged, cardInfoPicture, &CardInfoPictureWidget::setScaleFactor);
}
/**
* @brief Handles the mouse press event for right-clicks to show the context menu.
*
* If the right mouse button is pressed, a custom context menu will appear. For other mouse buttons,
* the event is passed to the base class for default handling.
*
* @param event The mouse event triggered by the user.
*/
void PrintingSelectorCardOverlayWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::RightButton) {
customMenu(event->pos());
} else {
QWidget::mousePressEvent(event); // Pass other events to the base class
}
}
/**
* @brief Resizes the overlay widget to match the card's size.
*
* This method ensures that the amount widget matches the card's size when the overlay widget is resized.
* It also resizes the card info picture widget to match the new size.
*
* @param event The resize event triggered when the widget is resized.
*/
void PrintingSelectorCardOverlayWidget::resizeEvent(QResizeEvent *event)
{
// Ensure the amount widget matches the parent size
QWidget::resizeEvent(event);
if (allZonesCardAmountWidget) {
allZonesCardAmountWidget->resize(cardInfoPicture->size());
}
resize(cardInfoPicture->size());
}
/**
* @brief Handles the mouse enter event when the cursor enters the overlay widget area.
*
* When the cursor enters the widget, the card information is updated, and the card amount widget
* is displayed if the amounts are zero for both the mainboard and sideboard.
*
* @param event The event triggered when the mouse enters the widget.
*/
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void PrintingSelectorCardOverlayWidget::enterEvent(QEnterEvent *event)
#else
void PrintingSelectorCardOverlayWidget::enterEvent(QEvent *event)
#endif
{
QWidget::enterEvent(event);
deckEditor->updateCardInfo(setCard);
// Check if either mainboard or sideboard amount is greater than 0
if (allZonesCardAmountWidget->getMainboardAmount() > 0 || allZonesCardAmountWidget->getSideboardAmount() > 0) {
// Don't change visibility if amounts are greater than 0
return;
}
// Show the widget if amounts are 0
allZonesCardAmountWidget->setVisible(true);
}
/**
* @brief Handles the mouse leave event when the cursor leaves the overlay widget area.
*
* When the cursor leaves the widget, the card amount widget is hidden if both the mainboard and sideboard
* amounts are zero.
*
* @param event The event triggered when the mouse leaves the widget.
*/
void PrintingSelectorCardOverlayWidget::leaveEvent(QEvent *event)
{
QWidget::leaveEvent(event);
// Check if either mainboard or sideboard amount is greater than 0
if (allZonesCardAmountWidget->getMainboardAmount() > 0 || allZonesCardAmountWidget->getSideboardAmount() > 0) {
// Don't hide the widget if amounts are greater than 0
return;
}
// Hide the widget if amounts are 0
allZonesCardAmountWidget->setVisible(false);
}
/**
* @brief Creates and shows a custom context menu when the right mouse button is clicked.
*
* The context menu includes an option to show related cards, which displays a submenu with actions
* for each related card. When an action is triggered, the card information is updated, and the
* printing selector is shown.
*
* @param point The position of the mouse when the right-click occurred.
*/
void PrintingSelectorCardOverlayWidget::customMenu(QPoint point)
{
QMenu menu;
// filling out the related cards submenu
auto *relatedMenu = new QMenu(tr("Show Related cards"));
menu.addMenu(relatedMenu);
auto relatedCards = rootCard->getAllRelatedCards();
if (relatedCards.isEmpty()) {
relatedMenu->setDisabled(true);
} else {
for (const CardRelation *rel : relatedCards) {
const QString &relatedCardName = rel->getName();
QAction *relatedCard = relatedMenu->addAction(relatedCardName);
connect(relatedCard, &QAction::triggered, deckEditor, [this, relatedCardName] {
deckEditor->updateCardInfo(CardDatabaseManager::getInstance()->getCard(relatedCardName));
deckEditor->showPrintingSelector();
});
}
}
menu.exec(this->mapToGlobal(point));
}

View file

@ -0,0 +1,49 @@
#ifndef PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H
#define PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H
#include "../../../../client/ui/widgets/cards/card_info_picture_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../../../../deck/deck_view.h"
#include "../../../../game/cards/card_database.h"
#include "../../../tabs/tab_deck_editor.h"
#include "all_zones_card_amount_widget.h"
#include "card_amount_widget.h"
#include "set_name_and_collectors_number_display_widget.h"
class PrintingSelectorCardOverlayWidget : public QWidget
{
Q_OBJECT
public:
explicit PrintingSelectorCardOverlayWidget(QWidget *parent,
TabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
CardInfoPtr _rootCard,
const CardInfoPerSet &_setInfoForCard);
protected:
void resizeEvent(QResizeEvent *event) override;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void enterEvent(QEnterEvent *event) override;
#else
void enterEvent(QEvent *event) override;
#endif
void leaveEvent(QEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void customMenu(QPoint point);
private:
CardInfoPictureWidget *cardInfoPicture;
AllZonesCardAmountWidget *allZonesCardAmountWidget;
TabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
CardInfoPtr rootCard;
CardInfoPtr setCard;
CardInfoPerSet setInfoForCard;
};
#endif // PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H

View file

@ -0,0 +1,38 @@
#include "printing_selector_card_search_widget.h"
/**
* @brief Constructs a PrintingSelectorCardSearchWidget 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.
*/
PrintingSelectorCardSearchWidget::PrintingSelectorCardSearchWidget(PrintingSelector *parent) : parent(parent)
{
layout = new QHBoxLayout(this);
setLayout(layout);
searchBar = new QLineEdit(this);
searchBar->setPlaceholderText(tr("Search by set name or set code"));
layout->addWidget(searchBar);
// Add a debounce timer for the search bar to limit frequent updates
searchDebounceTimer = new QTimer(this);
searchDebounceTimer->setSingleShot(true);
connect(searchBar, &QLineEdit::textChanged, this, [this]() {
searchDebounceTimer->start(300); // 300ms debounce
});
connect(searchDebounceTimer, &QTimer::timeout, parent, &PrintingSelector::updateDisplay);
}
/**
* @brief Retrieves the current text in the search bar.
*
* @return The text entered by the user in the search bar.
*/
QString PrintingSelectorCardSearchWidget::getSearchText()
{
return searchBar->text();
}

View file

@ -0,0 +1,25 @@
#ifndef PRINTING_SELECTOR_CARD_SEARCH_WIDGET_H
#define PRINTING_SELECTOR_CARD_SEARCH_WIDGET_H
#include "printing_selector.h"
#include <QLineEdit>
#include <QTimer>
#include <QWidget>
class PrintingSelectorCardSearchWidget : public QWidget
{
Q_OBJECT
public:
explicit PrintingSelectorCardSearchWidget(PrintingSelector *parent);
QString getSearchText();
private:
QHBoxLayout *layout;
PrintingSelector *parent;
QLineEdit *searchBar;
QTimer *searchDebounceTimer;
};
#endif // PRINTING_SELECTOR_CARD_SEARCH_WIDGET_H

View file

@ -0,0 +1,37 @@
#include "printing_selector_card_selection_widget.h"
/**
* @brief Constructs a PrintingSelectorCardSelectionWidget for navigating through cards in the deck.
*
* This widget provides buttons that allow users to navigate between cards in the deck.
* It includes buttons for moving to the previous and next card in the deck.
*
* @param parent The parent PrintingSelector widget responsible for managing card selection.
*/
PrintingSelectorCardSelectionWidget::PrintingSelectorCardSelectionWidget(PrintingSelector *parent) : parent(parent)
{
cardSelectionBarLayout = new QHBoxLayout(this);
previousCardButton = new QPushButton(this);
previousCardButton->setText(tr("Previous Card in Deck"));
nextCardButton = new QPushButton(this);
nextCardButton->setText(tr("Next Card in Deck"));
connectSignals();
cardSelectionBarLayout->addWidget(previousCardButton);
cardSelectionBarLayout->addWidget(nextCardButton);
}
/**
* @brief Connects the signals from the buttons to the appropriate slots in the parent widget.
*
* This method connects the click signals of the previous and next card buttons to
* the selectPreviousCard and selectNextCard slots in the parent PrintingSelector widget.
*/
void PrintingSelectorCardSelectionWidget::connectSignals()
{
connect(previousCardButton, &QPushButton::clicked, parent, &PrintingSelector::selectPreviousCard);
connect(nextCardButton, &QPushButton::clicked, parent, &PrintingSelector::selectNextCard);
}

View file

@ -0,0 +1,26 @@
#ifndef PRINTING_SELECTOR_CARD_SELECTION_WIDGET_H
#define PRINTING_SELECTOR_CARD_SELECTION_WIDGET_H
#include "printing_selector.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QWidget>
class PrintingSelectorCardSelectionWidget : public QWidget
{
Q_OBJECT
public:
explicit PrintingSelectorCardSelectionWidget(PrintingSelector *parent);
void connectSignals();
private:
PrintingSelector *parent;
QHBoxLayout *cardSelectionBarLayout;
QPushButton *previousCardButton;
QPushButton *nextCardButton;
};
#endif // PRINTING_SELECTOR_CARD_SELECTION_WIDGET_H

View file

@ -0,0 +1,210 @@
#include "printing_selector_card_sorting_widget.h"
#include "../../../../settings/cache_settings.h"
#include "../../../../utility/card_set_comparator.h"
const QString PrintingSelectorCardSortingWidget::SORT_OPTIONS_ALPHABETICAL = tr("Alphabetical");
const QString PrintingSelectorCardSortingWidget::SORT_OPTIONS_PREFERENCE = tr("Preference");
const QString PrintingSelectorCardSortingWidget::SORT_OPTIONS_RELEASE_DATE = tr("Release Date");
const QStringList PrintingSelectorCardSortingWidget::SORT_OPTIONS = {SORT_OPTIONS_ALPHABETICAL, SORT_OPTIONS_PREFERENCE,
SORT_OPTIONS_RELEASE_DATE};
/**
* @brief A widget for sorting and filtering card sets in the Printing Selector.
*
* This widget allows users to choose sorting options for the card sets, such as alphabetical order, release date, or
* user-defined preferences. It also allows users to toggle the sorting order between ascending and descending.
*/
PrintingSelectorCardSortingWidget::PrintingSelectorCardSortingWidget(PrintingSelector *parent) : parent(parent)
{
sortToolBar = new QHBoxLayout(this);
sortOptionsSelector = new QComboBox(this);
sortOptionsSelector->addItems(SORT_OPTIONS);
sortOptionsSelector->setCurrentIndex(SettingsCache::instance().getPrintingSelectorSortOrder());
connect(sortOptionsSelector, &QComboBox::currentTextChanged, this,
&PrintingSelectorCardSortingWidget::updateSortSetting);
connect(sortOptionsSelector, &QComboBox::currentTextChanged, parent, &PrintingSelector::updateDisplay);
sortToolBar->addWidget(sortOptionsSelector);
toggleSortOrder = new QPushButton(this);
toggleSortOrder->setText(tr("Descending"));
descendingSort = true;
connect(toggleSortOrder, &QPushButton::clicked, this, &PrintingSelectorCardSortingWidget::updateSortOrder);
sortToolBar->addWidget(toggleSortOrder);
}
/**
* @brief Updates the sorting order (ascending or descending).
*
* This function toggles the sort order between ascending and descending and updates the display.
*/
void PrintingSelectorCardSortingWidget::updateSortOrder()
{
if (descendingSort) {
toggleSortOrder->setText(tr("Ascending"));
} else {
toggleSortOrder->setText(tr("Descending"));
}
descendingSort = !descendingSort;
parent->updateDisplay();
}
/**
* @brief Updates the sorting setting in the application settings.
*
* This function saves the selected sorting option (from the combobox) to the application settings.
*/
void PrintingSelectorCardSortingWidget::updateSortSetting()
{
SettingsCache::instance().setPrintingSelectorSortOrder(sortOptionsSelector->currentIndex());
}
/**
* @brief Sorts a list of card sets based on the selected sorting option.
*
* This function sorts the card sets according to the selected sorting option in the combobox. The options include:
* - Alphabetical
* - Preference
* - Release Date
* - Contained in Deck
* - Potential Cards in Deck
*
* @param cardInfoPerSets The list of card sets to be sorted.
* @return A sorted list of card sets.
*/
QList<CardInfoPerSet> PrintingSelectorCardSortingWidget::sortSets(CardInfoPerSetMap cardInfoPerSets)
{
QList<CardSetPtr> sortedSets;
for (const auto &cardInfoPerSetList : cardInfoPerSets) {
for (const auto &set : cardInfoPerSetList) {
sortedSets << set.getPtr();
break;
}
}
if (sortedSets.empty()) {
sortedSets << CardSet::newInstance("", "", "", QDate());
}
if (sortOptionsSelector->currentText() == SORT_OPTIONS_PREFERENCE) {
std::sort(sortedSets.begin(), sortedSets.end(), SetPriorityComparator());
std::reverse(sortedSets.begin(), sortedSets.end());
} else if (sortOptionsSelector->currentText() == SORT_OPTIONS_RELEASE_DATE) {
std::sort(sortedSets.begin(), sortedSets.end(), SetReleaseDateComparator());
}
QList<CardInfoPerSet> sortedCardInfoPerSets;
// Reconstruct sorted list of CardInfoPerSet
for (const auto &set : sortedSets) {
for (auto it = cardInfoPerSets.begin(); it != cardInfoPerSets.end(); ++it) {
for (const auto &cardInfoPerSet : it.value()) {
if (cardInfoPerSet.getPtr() == set) {
sortedCardInfoPerSets << it.value();
break;
}
}
}
}
if (descendingSort) {
std::reverse(sortedCardInfoPerSets.begin(), sortedCardInfoPerSets.end());
}
return sortedCardInfoPerSets;
}
/**
* @brief Filters a list of card sets based on the search text.
*
* This function filters the given list of card sets by comparing their long and short names with the provided search
* text. If the search text matches either the long or short name of a card set, that set is included in the filtered
* list.
*
* @param sets The list of card sets to be filtered.
* @param searchText The search text used to filter the card sets.
* @return A filtered list of card sets.
*/
QList<CardInfoPerSet> PrintingSelectorCardSortingWidget::filterSets(const QList<CardInfoPerSet> &sets,
const QString &searchText)
{
if (searchText.isEmpty()) {
return sets;
}
QList<CardInfoPerSet> filteredSets;
for (const auto &set : sets) {
const QString longName = set.getPtr()->getLongName().toLower();
const QString shortName = set.getPtr()->getShortName().toLower();
if (longName.contains(searchText) || shortName.contains(searchText)) {
filteredSets << set;
}
}
return filteredSets;
}
/**
* @brief Prepend card printings that are contained in the deck to the list of card sets.
*
* This function adjusts the list of card sets by moving the printings that are already contained in the deck to the
* beginning of the list, sorted by the count of cards in the deck.
*
* @param sets The original list of card sets.
* @param selectedCard The currently selected card.
* @param deckModel The model representing the deck.
* @return A list of card sets with the printings contained in the deck prepended.
*/
QList<CardInfoPerSet> PrintingSelectorCardSortingWidget::prependPrintingsInDeck(const QList<CardInfoPerSet> &sets,
const CardInfoPtr &selectedCard,
DeckListModel *deckModel)
{
if (!selectedCard) {
return {};
}
CardInfoPerSetMap cardInfoPerSets = selectedCard->getSets();
QList<QPair<CardInfoPerSet, int>> countList;
// Collect sets with their counts
for (const auto &cardInfoPerSetList : cardInfoPerSets) {
for (const auto &cardInfoPerSet : cardInfoPerSetList) {
QModelIndex find_card =
deckModel->findCard(selectedCard->getName(), DECK_ZONE_MAIN, cardInfoPerSet.getProperty("uuid"));
if (find_card.isValid()) {
int count =
deckModel->data(find_card, Qt::DisplayRole).toInt(); // Ensure the count is treated as an integer
if (count > 0) {
countList.append(qMakePair(cardInfoPerSet, count));
}
}
break;
}
}
// Sort sets by count in descending numerical order
std::sort(countList.begin(), countList.end(),
[](const QPair<CardInfoPerSet, int> &a, const QPair<CardInfoPerSet, int> &b) {
return a.second > b.second; // Ensure numerical comparison
});
// Create a copy of the original list to modify
QList<CardInfoPerSet> result = sets;
// Prepend sorted sets and remove them from the original list
for (const auto &pair : countList) {
auto it = std::find_if(result.begin(), result.end(), [&pair](const CardInfoPerSet &item) {
return item.getProperty("uuid") == pair.first.getProperty("uuid");
});
if (it != result.end()) {
result.erase(it); // Remove the matching entry
}
result.prepend(pair.first); // Prepend the sorted item
}
return result;
}

View file

@ -0,0 +1,39 @@
#ifndef PRINTING_SELECTOR_CARD_SORTING_WIDGET_H
#define PRINTING_SELECTOR_CARD_SORTING_WIDGET_H
#include "printing_selector.h"
#include <QComboBox>
#include <QPushButton>
#include <QWidget>
class PrintingSelectorCardSortingWidget : public QWidget
{
Q_OBJECT
public:
explicit PrintingSelectorCardSortingWidget(PrintingSelector *parent);
QList<CardInfoPerSet> sortSets(CardInfoPerSetMap cardInfoPerSets);
static QList<CardInfoPerSet> filterSets(const QList<CardInfoPerSet> &sets, const QString &searchText);
static QList<CardInfoPerSet> prependPrintingsInDeck(const QList<CardInfoPerSet> &sets,
const CardInfoPtr &selectedCard,
DeckListModel *deckModel);
public slots:
void updateSortOrder();
void updateSortSetting();
private:
PrintingSelector *parent;
QHBoxLayout *sortToolBar;
static const QString SORT_OPTIONS_ALPHABETICAL;
static const QString SORT_OPTIONS_PREFERENCE;
static const QString SORT_OPTIONS_RELEASE_DATE;
static const QString SORT_OPTIONS_CONTAINED_IN_DECK;
static const QString SORT_OPTIONS_POTENTIAL_CARDS;
static const QStringList SORT_OPTIONS;
QComboBox *sortOptionsSelector;
bool descendingSort;
QPushButton *toggleSortOrder;
};
#endif // PRINTING_SELECTOR_CARD_SORTING_WIDGET_H

View file

@ -0,0 +1,140 @@
#include "printing_selector_view_options_toolbar_widget.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
/**
* @class PrintingSelectorViewOptionsToolbarWidget
* @brief A widget that provides a toolbar for view options with collapsible and expandable functionality.
*
* This widget allows the user to collapse or expand the view options for the PrintingSelector,
* providing a more compact interface when collapsed and a full view of options when expanded.
*/
PrintingSelectorViewOptionsToolbarWidget::PrintingSelectorViewOptionsToolbarWidget(QWidget *_parent,
PrintingSelector *_printingSelector)
: QWidget(_parent), printingSelector(_printingSelector)
{
// Set up layout for the widget
layout = new QVBoxLayout();
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
setLayout(layout);
// Set up the expanded widget with its layout
expandedWidget = new QWidget(this);
auto *expandedLayout = new QVBoxLayout(expandedWidget);
expandedLayout->setContentsMargins(0, 0, 0, 0);
expandedLayout->setSpacing(0);
// Collapse button to toggle between expanded and collapsed states
collapseButton = new QPushButton("", this);
collapseButton->setFixedSize(20, 20);
collapseButton->setToolTip("Collapse");
collapseButton->setStyleSheet("border: none;");
connect(collapseButton, &QPushButton::clicked, this, &PrintingSelectorViewOptionsToolbarWidget::collapse);
expandedLayout->addWidget(collapseButton, 0, Qt::AlignLeft);
// View options widget
viewOptions = new PrintingSelectorViewOptionsWidget(expandedWidget, printingSelector);
expandedLayout->addWidget(viewOptions);
expandedWidget->setLayout(expandedLayout);
// Set up the collapsed widget with its layout
collapsedWidget = new QWidget(this);
auto *collapsedLayout = new QHBoxLayout(collapsedWidget);
collapsedLayout->setContentsMargins(5, 0, 5, 0);
collapsedLayout->setSpacing(0);
// Expand button to show full options
expandButton = new QPushButton("", this);
expandButton->setFixedSize(20, 20);
expandButton->setToolTip("Expand");
expandButton->setStyleSheet("border: none;");
connect(expandButton, &QPushButton::clicked, this, &PrintingSelectorViewOptionsToolbarWidget::expand);
collapsedLayout->addWidget(expandButton);
// Label for collapsed state
auto *collapsedLabel = new QLabel(tr("Display Options"), this);
collapsedLayout->addWidget(collapsedLabel);
collapsedWidget->setLayout(collapsedLayout);
// Stack widget to switch between expanded and collapsed states
stackedWidget = new QStackedWidget(this);
stackedWidget->addWidget(expandedWidget);
stackedWidget->addWidget(collapsedWidget);
layout->addWidget(stackedWidget);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
// Default to the expanded widget
stackedWidget->setCurrentWidget(expandedWidget);
// Connect the stacked widget to update the layout when it changes
connect(stackedWidget, &QStackedWidget::currentChanged, this,
&PrintingSelectorViewOptionsToolbarWidget::onWidgetChanged);
}
/**
* @brief Toggles the widget to the collapsed state.
*/
void PrintingSelectorViewOptionsToolbarWidget::collapse()
{
stackedWidget->setCurrentWidget(collapsedWidget);
updateGeometry();
}
/**
* @brief Toggles the widget to the expanded state.
*/
void PrintingSelectorViewOptionsToolbarWidget::expand()
{
stackedWidget->setCurrentWidget(expandedWidget);
updateGeometry();
}
/**
* @brief Handles the geometry update when the stacked widget changes.
*
* This ensures that the parent layout is also updated when the widget's display state changes.
*/
void PrintingSelectorViewOptionsToolbarWidget::onWidgetChanged(int)
{
updateGeometry();
if (parentWidget() && parentWidget()->layout()) {
parentWidget()->layout()->invalidate();
}
}
/**
* @brief Provides the recommended size for the widget based on the current view.
*
* @return QSize The suggested size for the widget.
*/
QSize PrintingSelectorViewOptionsToolbarWidget::sizeHint() const
{
return stackedWidget->currentWidget()->sizeHint();
}
/**
* @brief Provides the minimum size required for the widget based on the current view.
*
* @return QSize The minimum size required for the widget.
*/
QSize PrintingSelectorViewOptionsToolbarWidget::minimumSizeHint() const
{
return stackedWidget->currentWidget()->minimumSizeHint();
}
/**
* @brief Returns the view options widget contained within this toolbar.
*
* @return PrintingSelectorViewOptionsWidget* The view options widget.
*/
PrintingSelectorViewOptionsWidget *PrintingSelectorViewOptionsToolbarWidget::getViewOptionsWidget() const
{
return viewOptions;
}

View file

@ -0,0 +1,36 @@
#ifndef PRINTING_SELECTOR_SORT_AND_SEARCH_TOOLBAR_WIDGET_H
#define PRINTING_SELECTOR_SORT_AND_SEARCH_TOOLBAR_WIDGET_H
#include "printing_selector.h"
#include "printing_selector_view_options_widget.h"
#include <QPushButton>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <QWidget>
class PrintingSelectorViewOptionsToolbarWidget : public QWidget
{
Q_OBJECT
public:
explicit PrintingSelectorViewOptionsToolbarWidget(QWidget *parent, PrintingSelector *printingSelector);
void collapse();
void expand();
void onWidgetChanged(int);
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
PrintingSelectorViewOptionsWidget *getViewOptionsWidget() const;
private:
QVBoxLayout *layout;
PrintingSelector *printingSelector;
PrintingSelectorViewOptionsWidget *viewOptions;
QWidget *expandedWidget;
QPushButton *collapseButton;
QWidget *collapsedWidget;
QPushButton *expandButton;
QStackedWidget *stackedWidget;
};
#endif // PRINTING_SELECTOR_SORT_AND_SEARCH_TOOLBAR_WIDGET_H

View file

@ -0,0 +1,69 @@
#include "printing_selector_view_options_widget.h"
#include "../../../../settings/cache_settings.h"
/**
* @class PrintingSelectorViewOptionsWidget
* @brief A widget that provides the view options for the PrintingSelector, including checkboxes
* for sorting, search bar, card size slider, and navigation buttons.
*
* This widget allows the user to toggle the visibility of various interface components of the
* PrintingSelector through checkboxes. The state of the checkboxes is saved and restored using
* the `SettingsCache`.
*/
PrintingSelectorViewOptionsWidget::PrintingSelectorViewOptionsWidget(QWidget *parent,
PrintingSelector *_printingSelector)
: QWidget(parent), printingSelector(_printingSelector)
{
// Set up the layout for the widget
layout = new QHBoxLayout(this);
setLayout(layout);
// Create the flow widget to hold the checkboxes
flowWidget = new FlowWidget(this, Qt::ScrollBarPolicy::ScrollBarAlwaysOff, Qt::ScrollBarPolicy::ScrollBarAsNeeded);
// Create the checkbox for sorting options visibility
sortCheckBox = new QCheckBox(flowWidget);
sortCheckBox->setText(tr("Display Sorting Options"));
sortCheckBox->setChecked(SettingsCache::instance().getPrintingSelectorSortOptionsVisible());
connect(sortCheckBox, &QCheckBox::QT_STATE_CHANGED, printingSelector,
&PrintingSelector::toggleVisibilitySortOptions);
connect(sortCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setPrintingSelectorSortOptionsVisible);
// Create the checkbox for search bar visibility
searchCheckBox = new QCheckBox(flowWidget);
searchCheckBox->setText(tr("Display Search Bar"));
searchCheckBox->setChecked(SettingsCache::instance().getPrintingSelectorSearchBarVisible());
connect(searchCheckBox, &QCheckBox::QT_STATE_CHANGED, printingSelector,
&PrintingSelector::toggleVisibilitySearchBar);
connect(searchCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setPrintingSelectorSearchBarVisible);
// Create the checkbox for card size slider visibility
cardSizeCheckBox = new QCheckBox(flowWidget);
cardSizeCheckBox->setText(tr("Display Card Size Slider"));
cardSizeCheckBox->setChecked(SettingsCache::instance().getPrintingSelectorCardSizeSliderVisible());
connect(cardSizeCheckBox, &QCheckBox::QT_STATE_CHANGED, printingSelector,
&PrintingSelector::toggleVisibilityCardSizeSlider);
connect(cardSizeCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setPrintingSelectorCardSizeSliderVisible);
// Create the checkbox for navigation buttons visibility
navigationCheckBox = new QCheckBox(flowWidget);
navigationCheckBox->setText(tr("Display Navigation Buttons"));
navigationCheckBox->setChecked(SettingsCache::instance().getPrintingSelectorNavigationButtonsVisible());
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, printingSelector,
&PrintingSelector::toggleVisibilityNavigationButtons);
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setPrintingSelectorNavigationButtonsVisible);
// Add checkboxes to the flow widget
flowWidget->addWidget(sortCheckBox);
flowWidget->addWidget(searchCheckBox);
flowWidget->addWidget(cardSizeCheckBox);
flowWidget->addWidget(navigationCheckBox);
// Add flow widget to the main layout
layout->addWidget(flowWidget);
}

View file

@ -0,0 +1,28 @@
#ifndef PRINTING_SELECTOR_VIEW_OPTIONS_WIDGET_H
#define PRINTING_SELECTOR_VIEW_OPTIONS_WIDGET_H
#include "../general/layout_containers/flow_widget.h"
#include "printing_selector.h"
#include <QCheckBox>
#include <QHBoxLayout>
#include <QWidget>
class PrintingSelectorViewOptionsWidget : public QWidget
{
Q_OBJECT
public:
explicit PrintingSelectorViewOptionsWidget(QWidget *parent, PrintingSelector *_printingSelector);
private:
QHBoxLayout *layout;
FlowWidget *flowWidget;
PrintingSelector *printingSelector;
QCheckBox *sortCheckBox;
QCheckBox *searchCheckBox;
QCheckBox *cardSizeCheckBox;
QCheckBox *navigationCheckBox;
};
#endif // PRINTING_SELECTOR_VIEW_OPTIONS_WIDGET_H

View file

@ -0,0 +1,102 @@
#include "set_name_and_collectors_number_display_widget.h"
#include <QSlider>
/**
* @class SetNameAndCollectorsNumberDisplayWidget
* @brief A widget to display the set name and collectors number with adjustable font size.
*
* This widget displays the set name and collectors number on two separate labels. The font size is resized dynamically
* when the card size is changed.
*/
SetNameAndCollectorsNumberDisplayWidget::SetNameAndCollectorsNumberDisplayWidget(QWidget *parent,
const QString &_setName,
const QString &_collectorsNumber,
QSlider *_cardSizeSlider)
: QWidget(parent)
{
// Set up the layout for the widget
layout = new QVBoxLayout(this);
setLayout(layout);
// Set the widget's size policy and minimum size
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
setMinimumSize(QWidget::sizeHint());
// Create and configure the set name label
setName = new QLabel(_setName);
setName->setWordWrap(true);
setName->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
setName->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
// Create and configure the collectors number label
collectorsNumber = new QLabel(_collectorsNumber);
collectorsNumber->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
collectorsNumber->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
// Store the card size slider and connect its signal to the font size adjustment slot
cardSizeSlider = _cardSizeSlider;
connect(cardSizeSlider, &QSlider::valueChanged, this, &SetNameAndCollectorsNumberDisplayWidget::adjustFontSize);
// Add labels to the layout
layout->addWidget(setName);
layout->addWidget(collectorsNumber);
}
/**
* @brief Adjusts the font size of the labels based on the slider value.
*
* This method adjusts the font size of the set name and collectors number labels
* according to the scale percentage provided by the slider. The font size is clamped
* to a range between the defined minimum and maximum font sizes.
*
* @param scalePercentage The scale percentage from the slider.
*/
void SetNameAndCollectorsNumberDisplayWidget::adjustFontSize(int scalePercentage)
{
// Define the base font size and the range
const int minFontSize = 8; // Minimum font size
const int maxFontSize = 32; // Maximum font size
const int basePercentage = 100; // Scale at 100%
// Calculate the new font size
int newFontSize = minFontSize + (scalePercentage - basePercentage) * (maxFontSize - minFontSize) / 225;
// Clamp the font size to the defined range
newFontSize = std::clamp(newFontSize, minFontSize, maxFontSize);
// Update the fonts for both labels
QFont setNameFont = setName->font();
setNameFont.setPointSize(newFontSize);
setName->setFont(setNameFont);
QFont collectorsNumberFont = collectorsNumber->font();
collectorsNumberFont.setPointSize(newFontSize);
collectorsNumber->setFont(collectorsNumberFont);
// Optionally trigger a resize to accommodate new font size
adjustSize();
}
/**
* @brief Handles resize events to adjust the height of the set name label.
*
* This method calculates the height required to display the set name label with word wrapping.
* It adjusts the minimum height of the set name label to fit the text.
*
* @param event The resize event.
*/
void SetNameAndCollectorsNumberDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event); // Ensure the parent class handles the event first
QFontMetrics fm(setName->font());
int labelWidth = setName->width(); // Get the current width of the QLabel
QString text = setName->text(); // The text to be rendered
// Calculate the height required to render the text with word wrapping
int textHeight = fm.boundingRect(0, 0, labelWidth, 0, Qt::TextWordWrap, text).height();
// Set the minimum height to accommodate the required text height
setName->setMinimumHeight(textHeight);
}

View file

@ -0,0 +1,29 @@
#ifndef SET_NAME_AND_COLLECTORS_NUMBER_DISPLAY_WIDGET_H
#define SET_NAME_AND_COLLECTORS_NUMBER_DISPLAY_WIDGET_H
#include <QLabel>
#include <QSlider>
#include <QVBoxLayout>
#include <QWidget>
class SetNameAndCollectorsNumberDisplayWidget : public QWidget
{
Q_OBJECT
public:
SetNameAndCollectorsNumberDisplayWidget(QWidget *parent,
const QString &setName,
const QString &collectorsNumber,
QSlider *cardSizeSlider);
void resizeEvent(QResizeEvent *event) override;
public slots:
void adjustFontSize(int scalePercentage);
private:
QVBoxLayout *layout;
QLabel *setName;
QLabel *collectorsNumber;
QSlider *cardSizeSlider;
};
#endif // SET_NAME_AND_COLLECTORS_NUMBER_DISPLAY_WIDGET_H

View file

@ -1,13 +1,11 @@
#include "deck_list_model.h"
#include "../game/cards/card_database.h"
#include "../game/cards/card_database_manager.h"
#include "../main.h"
#include "../settings/cache_settings.h"
#include "deck_loader.h"
#include <QBrush>
#include <QFile>
#include <QFont>
#include <QPrinter>
#include <QProgressDialog>
@ -309,8 +307,10 @@ InnerDecklistNode *DeckListModel::createNodeIfNeeded(const QString &name, InnerD
return newNode;
}
DecklistModelCardNode *
DeckListModel::findCardNode(const QString &cardName, const QString &zoneName, const QString &providerId) const
DecklistModelCardNode *DeckListModel::findCardNode(const QString &cardName,
const QString &zoneName,
const QString &providerId,
const QString &cardNumber) const
{
InnerDecklistNode *zoneNode, *typeNode;
CardInfoPtr info;
@ -332,17 +332,18 @@ DeckListModel::findCardNode(const QString &cardName, const QString &zoneName, co
return nullptr;
}
if (providerId.isEmpty()) {
return dynamic_cast<DecklistModelCardNode *>(typeNode->findChild(cardName));
}
return dynamic_cast<DecklistModelCardNode *>(typeNode->findCardChildByNameAndProviderId(cardName, providerId));
return dynamic_cast<DecklistModelCardNode *>(
typeNode->findCardChildByNameProviderIdAndNumber(cardName, providerId, cardNumber));
}
QModelIndex DeckListModel::findCard(const QString &cardName, const QString &zoneName, const QString &providerId) const
QModelIndex DeckListModel::findCard(const QString &cardName,
const QString &zoneName,
const QString &providerId,
const QString &cardNumber) const
{
DecklistModelCardNode *cardNode;
cardNode = findCardNode(cardName, zoneName, providerId);
cardNode = findCardNode(cardName, zoneName, providerId, cardNumber);
if (!cardNode) {
return {};
}
@ -357,7 +358,7 @@ QModelIndex DeckListModel::addPreferredPrintingCard(const QString &cardName, con
}
QModelIndex DeckListModel::addCard(const QString &cardName,
const CardInfoPerSet cardInfoSet,
const CardInfoPerSet &cardInfoSet,
const QString &zoneName,
bool abAddAnyway)
{
@ -382,18 +383,19 @@ QModelIndex DeckListModel::addCard(const QString &cardName,
InnerDecklistNode *cardTypeNode = createNodeIfNeeded(cardType, zoneNode);
const QModelIndex parentIndex = nodeToIndex(cardTypeNode);
auto *cardNode = dynamic_cast<DecklistModelCardNode *>(
cardTypeNode->findCardChildByNameAndProviderId(cardName, cardInfoSet.getProperty("uuid")));
auto *cardNode = dynamic_cast<DecklistModelCardNode *>(cardTypeNode->findCardChildByNameProviderIdAndNumber(
cardName, cardInfoSet.getProperty("uuid"), cardInfoSet.getProperty("num")));
const auto cardSetName = cardInfoSet.getPtr().isNull() ? "" : cardInfoSet.getPtr()->getCorrectedShortName();
if (!cardNode) {
auto *decklistCard =
deckList->addCard(cardInfo->getName(), zoneName, cardInfoSet.getPtr()->getCorrectedShortName(),
cardInfoSet.getProperty("num"), cardInfoSet.getProperty("uuid"));
auto *decklistCard = deckList->addCard(cardInfo->getName(), zoneName, cardSetName,
cardInfoSet.getProperty("num"), cardInfoSet.getProperty("uuid"));
beginInsertRows(parentIndex, static_cast<int>(cardTypeNode->size()), static_cast<int>(cardTypeNode->size()));
cardNode = new DecklistModelCardNode(decklistCard, cardTypeNode);
endInsertRows();
} else {
cardNode->setNumber(cardNode->getNumber() + 1);
cardNode->setCardSetShortName(cardInfoSet.getPtr()->getCorrectedShortName());
cardNode->setCardSetShortName(cardSetName);
cardNode->setCardCollectorNumber(cardInfoSet.getProperty("num"));
cardNode->setCardProviderId(cardInfoSet.getProperty("uuid"));
deckList->updateDeckHash();

View file

@ -66,6 +66,10 @@ public:
{
return dataNode;
}
[[nodiscard]] bool isDeckHeader() const override
{
return false;
}
};
class DeckListModel : public QAbstractItemModel
@ -90,10 +94,15 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
bool removeRows(int row, int count, const QModelIndex &parent) override;
QModelIndex findCard(const QString &cardName, const QString &zoneName, const QString &providerId = "") const;
QModelIndex findCard(const QString &cardName,
const QString &zoneName,
const QString &providerId = "",
const QString &cardNumber = "") const;
QModelIndex addPreferredPrintingCard(const QString &cardName, const QString &zoneName, bool abAddAnyway);
QModelIndex
addCard(const ::QString &cardName, CardInfoPerSet cardInfoSet, const QString &zoneName, bool abAddAnyway = false);
QModelIndex addCard(const ::QString &cardName,
const CardInfoPerSet &cardInfoSet,
const QString &zoneName,
bool abAddAnyway = false);
void sort(int column, Qt::SortOrder order) override;
void cleanList();
DeckLoader *getDeckList() const
@ -109,8 +118,10 @@ private:
Qt::SortOrder lastKnownOrder;
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
QModelIndex nodeToIndex(AbstractDecklistNode *node) const;
DecklistModelCardNode *
findCardNode(const QString &cardName, const QString &zoneName, const QString &providerId = "") const;
DecklistModelCardNode *findCardNode(const QString &cardName,
const QString &zoneName,
const QString &providerId = "",
const QString &cardNumber = "") const;
void emitRecursiveUpdates(const QModelIndex &index);
void sortHelper(InnerDecklistNode *node, Qt::SortOrder order);

View file

@ -163,7 +163,7 @@ void DlgEditTokens::actAddToken()
QString setName = CardDatabase::TOKENS_SETNAME;
CardInfoPerSetMap sets;
sets.insert(setName, CardInfoPerSet(databaseModel->getDatabase()->getSet(setName)));
sets[setName].append(CardInfoPerSet(databaseModel->getDatabase()->getSet(setName)));
CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(),
QList<CardRelation *>(), sets, false, -1, false);
card->setCardType("Token");

View file

@ -338,6 +338,14 @@ AppearanceSettingsPage::AppearanceSettingsPage()
displayCardNamesCheckBox.setChecked(settings.getDisplayCardNames());
connect(&displayCardNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setDisplayCardNames);
overrideAllCardArtWithPersonalPreferenceCheckBox.setChecked(settings.getOverrideAllCardArtWithPersonalPreference());
connect(&overrideAllCardArtWithPersonalPreferenceCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
&SettingsCache::setOverrideAllCardArtWithPersonalPreference);
bumpSetsWithCardsInDeckToTopCheckBox.setChecked(settings.getBumpSetsWithCardsInDeckToTop());
connect(&bumpSetsWithCardsInDeckToTopCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
&SettingsCache::setBumpSetsWithCardsInDeckToTop);
cardScalingCheckBox.setChecked(settings.getScaleCards());
connect(&cardScalingCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setCardScaling);
@ -354,10 +362,12 @@ AppearanceSettingsPage::AppearanceSettingsPage()
auto *cardsGrid = new QGridLayout;
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
cardsGrid->addWidget(&cardScalingCheckBox, 1, 0, 1, 2);
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 2, 0, 1, 1);
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 2, 1, 1, 1);
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 3, 0);
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 3, 1);
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 2, 0, 1, 2);
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 3, 0, 1, 2);
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 4, 0, 1, 1);
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 4, 1, 1, 1);
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 5, 0);
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 5, 1);
cardsGroupBox = new QGroupBox;
cardsGroupBox->setLayout(cardsGrid);
@ -452,6 +462,11 @@ void AppearanceSettingsPage::retranslateUi()
cardsGroupBox->setTitle(tr("Card rendering"));
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
overrideAllCardArtWithPersonalPreferenceCheckBox.setText(
tr("Override all card art with personal set preference (Pre-ProviderID change behavior) [Requires Client "
"restart]"));
bumpSetsWithCardsInDeckToTopCheckBox.setText(
tr("Bump sets that the deck contains cards from to the top in the printing selector"));
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
verticalCardOverlapPercentLabel.setText(
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));

View file

@ -93,6 +93,8 @@ private:
QLabel maxFontSizeForCardsLabel;
QCheckBox showShortcutsCheckBox;
QCheckBox displayCardNamesCheckBox;
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
QCheckBox cardScalingCheckBox;
QLabel verticalCardOverlapPercentLabel;
QSpinBox verticalCardOverlapPercentBox;

View file

@ -266,8 +266,11 @@ CardInfoPtr CardInfo::newInstance(const QString &_name,
_sets, _cipt, _tableRow, _upsideDownArt));
ptr->setSmartPointer(ptr);
for (const CardInfoPerSet &set : _sets) {
set.getPtr()->append(ptr);
for (const auto &cardInfoPerSetList : _sets) {
for (const CardInfoPerSet &set : cardInfoPerSetList) {
set.getPtr()->append(ptr);
break;
}
}
return ptr;
@ -288,7 +291,7 @@ QString CardInfo::getCorrectedName() const
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{
_set->append(smartThis);
sets.insert(_set->getShortName(), _info);
sets[_set->getShortName()].append(_info);
refreshCachedSetNames();
}
@ -297,9 +300,12 @@ void CardInfo::refreshCachedSetNames()
{
QStringList setList;
// update the cached list of set names
for (const auto &set : sets) {
if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
for (const auto &cardInfoPerSetList : sets) {
for (const auto &set : cardInfoPerSetList) {
if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
}
break;
}
}
setsNames = setList.join(", ");
@ -396,8 +402,10 @@ void CardDatabase::addCard(CardInfoPtr card)
// if card already exists just add the new set property
if (cards.contains(card->getName())) {
CardInfoPtr sameCard = cards[card->getName()];
for (const CardInfoPerSet &set : card->getSets()) {
sameCard->addToSet(set.getPtr(), set);
for (const auto &cardInfoPerSetList : card->getSets()) {
for (const CardInfoPerSet &set : cardInfoPerSetList) {
sameCard->addToSet(set.getPtr(), set);
}
}
return;
}
@ -456,12 +464,14 @@ CardInfoPtr CardDatabase::getCardByNameAndProviderId(const QString &cardName, co
return info;
}
for (const auto &set : info->getSets()) {
if (set.getProperty("uuid") == providerId) {
CardInfoPtr cardFromSpecificSet = info->clone();
cardFromSpecificSet->setPixmapCacheKey(QLatin1String("card_") + QString(info->getName()) + QString("_") +
QString(set.getProperty("uuid")));
return cardFromSpecificSet;
for (const auto &cardInfoPerSetList : info->getSets()) {
for (const auto &set : cardInfoPerSetList) {
if (set.getProperty("uuid") == providerId) {
CardInfoPtr cardFromSpecificSet = info->clone();
cardFromSpecificSet->setPixmapCacheKey(QLatin1String("card_") + QString(info->getName()) +
QString("_") + QString(set.getProperty("uuid")));
return cardFromSpecificSet;
}
}
}
return {};
@ -614,7 +624,7 @@ void CardDatabase::refreshPreferredPrintings()
}
}
CardInfoPerSet CardDatabase::getPreferredSetForCard(const QString &cardName)
CardInfoPerSet CardDatabase::getPreferredSetForCard(const QString &cardName) const
{
CardInfoPtr cardInfo = getCard(cardName);
if (!cardInfo) {
@ -630,11 +640,13 @@ CardInfoPerSet CardDatabase::getPreferredSetForCard(const QString &cardName)
CardInfoPerSet preferredCard;
SetPriorityComparator comparator;
for (auto &cardInfoForSet : setMap) {
CardSetPtr currentSet = cardInfoForSet.getPtr();
if (!preferredSet || comparator(currentSet, preferredSet)) {
preferredSet = currentSet;
preferredCard = cardInfoForSet;
for (const auto &cardInfoPerSetList : setMap) {
for (auto &cardInfoForSet : cardInfoPerSetList) {
CardSetPtr currentSet = cardInfoForSet.getPtr();
if (!preferredSet || comparator(currentSet, preferredSet)) {
preferredSet = currentSet;
preferredCard = cardInfoForSet;
}
}
}
@ -657,12 +669,18 @@ CardInfoPerSet CardDatabase::getSpecificSetForCard(const QString &cardName, cons
return CardInfoPerSet(nullptr);
}
for (auto &cardInfoForSet : setMap) {
if (cardInfoForSet.getProperty("uuid") == providerId) {
return cardInfoForSet;
for (const auto &cardInfoPerSetList : setMap) {
for (auto &cardInfoForSet : cardInfoPerSetList) {
if (cardInfoForSet.getProperty("uuid") == providerId) {
return cardInfoForSet;
}
}
}
if (providerId.isNull()) {
return getPreferredSetForCard(cardName);
}
return CardInfoPerSet(nullptr);
}
@ -689,6 +707,25 @@ bool CardDatabase::isProviderIdForPreferredPrinting(const QString &cardName, con
return providerId == getPreferredPrintingProviderIdForCard(cardName);
}
CardInfoPerSet CardDatabase::getSetInfoForCard(const CardInfoPtr &_card)
{
const CardInfoPerSetMap &setMap = _card->getSets();
if (setMap.empty()) {
return CardInfoPerSet(nullptr);
}
for (const auto &cardInfoPerSetList : setMap) {
for (const auto &cardInfoForSet : cardInfoPerSetList) {
if (QLatin1String("card_") + _card->getName() + QString("_") + cardInfoForSet.getProperty("uuid") ==
_card->getPixmapCacheKey()) {
return cardInfoForSet;
}
}
}
return CardInfoPerSet(nullptr);
}
void CardDatabase::refreshCachedReverseRelatedCards()
{
for (const CardInfoPtr &card : cards)

View file

@ -23,7 +23,7 @@ class ICardDatabaseParser;
typedef QMap<QString, QString> QStringMap;
typedef QSharedPointer<CardInfo> CardInfoPtr;
typedef QSharedPointer<CardSet> CardSetPtr;
typedef QMap<QString, CardInfoPerSet> CardInfoPerSetMap;
typedef QMap<QString, QList<CardInfoPerSet>> CardInfoPerSetMap;
Q_DECLARE_METATYPE(CardInfoPtr)
@ -306,15 +306,15 @@ public:
{
if (!sets.contains(setName))
return "";
return sets[setName].getProperty(propertyName);
}
void setSetProperty(const QString &setName, const QString &_name, const QString &_value)
{
if (!sets.contains(setName))
return;
sets[setName].setProperty(_name, _value);
emit cardInfoChanged(smartThis);
for (const auto &set : sets[setName]) {
if (QLatin1String("card_") + this->getName() + QString("_") + QString(set.getProperty("uuid")) ==
this->getPixmapCacheKey()) {
return set.getProperty(propertyName);
}
}
return sets[setName][0].getProperty(propertyName);
}
// related cards
@ -450,22 +450,23 @@ public:
~CardDatabase() override;
void clear();
void removeCard(CardInfoPtr card);
CardInfoPtr getCard(const QString &cardName) const;
QList<CardInfoPtr> getCards(const QStringList &cardNames) const;
CardInfoPtr getCardByNameAndProviderId(const QString &cardName, const QString &providerId) const;
CardInfoPerSet getPreferredSetForCard(const QString &cardName);
CardInfoPerSet getSpecificSetForCard(const QString &cardName, const QString &providerId) const;
[[nodiscard]] CardInfoPtr getCard(const QString &cardName) const;
[[nodiscard]] QList<CardInfoPtr> getCards(const QStringList &cardNames) const;
[[nodiscard]] CardInfoPtr getCardByNameAndProviderId(const QString &cardName, const QString &providerId) const;
[[nodiscard]] CardInfoPerSet getPreferredSetForCard(const QString &cardName) const;
[[nodiscard]] CardInfoPerSet getSpecificSetForCard(const QString &cardName, const QString &providerId) const;
QString getPreferredPrintingProviderIdForCard(const QString &cardName);
CardInfoPtr guessCard(const QString &cardName) const;
[[nodiscard]] CardInfoPtr guessCard(const QString &cardName) const;
/*
* Get a card by its simple name. The name will be simplified in this
* function, so you don't need to simplify it beforehand.
*/
CardInfoPtr getCardBySimpleName(const QString &cardName) const;
[[nodiscard]] CardInfoPtr getCardBySimpleName(const QString &cardName) const;
CardSetPtr getSet(const QString &setName);
bool isProviderIdForPreferredPrinting(const QString &cardName, const QString &providerId);
static CardInfoPerSet getSetInfoForCard(const CardInfoPtr &_card);
QList<CardInfoPtr> getCardList() const
{
return cards.values();

View file

@ -97,9 +97,11 @@ bool CardDatabaseModel::checkCardHasAtLeastOneEnabledSet(CardInfoPtr card)
if (!showOnlyCardsFromEnabledSets)
return true;
for (const auto &set : card->getSets()) {
if (set.getPtr()->getEnabled())
return true;
for (const auto &cardInfoPerSetList : card->getSets()) {
for (const auto &set : cardInfoPerSetList) {
if (set.getPtr()->getEnabled())
return true;
}
}
return false;

View file

@ -221,7 +221,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
if (attrs.hasAttribute("rarity")) {
setInfo.setProperty("rarity", attrs.value("rarity").toString());
}
_sets.insert(setName, setInfo);
_sets[setName].append(setInfo);
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {
CardRelation::AttachType attach = CardRelation::DoesNotAttach;
@ -331,24 +331,26 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
// sets
const CardInfoPerSetMap sets = info->getSets();
for (CardInfoPerSet set : sets) {
xml.writeStartElement("set");
xml.writeAttribute("rarity", set.getProperty("rarity"));
xml.writeAttribute("muId", set.getProperty("muid"));
xml.writeAttribute("uuId", set.getProperty("uuid"));
for (const auto &cardInfoPerSetList : sets) {
for (const CardInfoPerSet &set : cardInfoPerSetList) {
xml.writeStartElement("set");
xml.writeAttribute("rarity", set.getProperty("rarity"));
xml.writeAttribute("muId", set.getProperty("muid"));
xml.writeAttribute("uuId", set.getProperty("uuid"));
tmpString = set.getProperty("num");
if (!tmpString.isEmpty()) {
xml.writeAttribute("num", tmpString);
tmpString = set.getProperty("num");
if (!tmpString.isEmpty()) {
xml.writeAttribute("num", tmpString);
}
tmpString = set.getProperty("picurl");
if (!tmpString.isEmpty()) {
xml.writeAttribute("picURL", tmpString);
}
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
}
tmpString = set.getProperty("picurl");
if (!tmpString.isEmpty()) {
xml.writeAttribute("picURL", tmpString);
}
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
}
// related cards

View file

@ -181,7 +181,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
attrName = "picurl";
setInfo.setProperty(attrName, attr.value().toString());
}
_sets.insert(setName, setInfo);
_sets[setName].append(setInfo);
}
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {
@ -284,14 +284,16 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
xml.writeEndElement();
// sets
for (CardInfoPerSet set : info->getSets()) {
xml.writeStartElement("set");
for (QString propName : set.getProperties()) {
xml.writeAttribute(propName, set.getProperty(propName));
}
for (const auto &cardInfoPerSetList : info->getSets()) {
for (const CardInfoPerSet &set : cardInfoPerSetList) {
xml.writeStartElement("set");
for (const QString &propName : set.getProperties()) {
xml.writeAttribute(propName, set.getProperty(propName));
}
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
}
}
// related cards

View file

@ -108,10 +108,12 @@ static void setupParserRules()
};
search["RarityQuery"] = [](const peg::SemanticValues &sv) -> Filter {
StringMatcher matcher = sv[0].get<StringMatcher>();
return [=](CardData x) -> bool {
for (const auto &set : x->getSets().values()) {
if (matcher(set.getProperty("rarity")))
return true;
return [=](const CardData &x) -> bool {
for (const auto &cardInfoPerSetList : x->getSets().values()) {
for (const auto &set : cardInfoPerSetList) {
if (matcher(set.getProperty("rarity")))
return true;
}
}
return false;
};

View file

@ -203,11 +203,13 @@ bool FilterItem::acceptText(const CardInfoPtr info) const
bool FilterItem::acceptSet(const CardInfoPtr info) const
{
bool status = false;
for (const auto &set : info->getSets()) {
if (set.getPtr()->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
set.getPtr()->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
status = true;
break;
for (const auto &cardInfoPerSetList : info->getSets()) {
for (const auto &set : cardInfoPerSetList) {
if (set.getPtr()->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
set.getPtr()->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
status = true;
break;
}
}
}
@ -336,9 +338,11 @@ bool FilterItem::acceptRarity(const CardInfoPtr info) const
}
}
for (const auto &set : info->getSets()) {
if (set.getProperty("rarity").compare(converted_term, Qt::CaseInsensitive) == 0) {
return true;
for (const auto &cardInfoPerSetList : info->getSets()) {
for (const auto &set : cardInfoPerSetList) {
if (set.getProperty("rarity").compare(converted_term, Qt::CaseInsensitive) == 0) {
return true;
}
}
}
return false;

View file

@ -1764,7 +1764,8 @@ void Player::actCreateRelatedCard()
* then let's allow it to be created via "create another token"
*/
if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) {
CardInfoPtr cardInfo = CardDatabaseManager::getInstance()->getCard(cardRelation->getName());
CardInfoPtr cardInfo = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
cardRelation->getName(), sourceCard->getProviderId());
setLastToken(cardInfo);
}
}
@ -1927,11 +1928,13 @@ void Player::createCard(const CardItem *sourceCard,
case CardRelation::AttachTo:
cmd.set_target_card_id(sourceCard->getId());
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
cmd.set_card_provider_id(sourceCard->getProviderId().toStdString());
break;
case CardRelation::TransformInto:
cmd.set_target_card_id(sourceCard->getId());
cmd.set_target_mode(Command_CreateToken::TRANSFORM_INTO);
cmd.set_card_provider_id(sourceCard->getProviderId().toStdString());
break;
}
@ -2090,7 +2093,8 @@ void Player::eventCreateToken(const Event_CreateToken &event)
return;
}
CardItem *card = new CardItem(this, nullptr, QString::fromStdString(event.card_name()), QString(), event.card_id());
CardItem *card = new CardItem(this, nullptr, QString::fromStdString(event.card_name()),
QString::fromStdString(event.card_provider_id()), event.card_id());
// use db PT if not provided in event
if (!QString::fromStdString(event.pt()).isEmpty()) {
card->setPT(QString::fromStdString(event.pt()));
@ -3820,13 +3824,17 @@ void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu)
return;
}
const auto &currentCardSet = CardDatabase::getSetInfoForCard(cardInfo);
cardMenu->addSeparator();
auto viewRelatedCards = new QMenu(tr("View related cards"));
cardMenu->addMenu(viewRelatedCards);
for (const CardRelation *relatedCard : relatedCards) {
QString relatedCardName = relatedCard->getName();
QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
connect(viewCard, &QAction::triggered, game, [this, relatedCardName] { game->viewCardInfo(relatedCardName); });
connect(viewCard, &QAction::triggered, game, [this, relatedCardName, currentCardSet] {
game->viewCardInfo(relatedCardName, currentCardSet.getProperty("uuid"));
});
}
}
@ -3845,13 +3853,20 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
return;
}
const auto &currentCardSet = CardDatabase::getSetInfoForCard(cardInfo);
cardMenu->addSeparator();
int index = 0;
QAction *createRelatedCards = nullptr;
for (const CardRelation *cardRelation : relatedCards) {
CardInfoPtr relatedCard = CardDatabaseManager::getInstance()->getCard(cardRelation->getName());
if (relatedCard == nullptr)
CardInfoPtr relatedCard = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
cardRelation->getName(), currentCardSet.getProperty("uuid"));
if (relatedCard == nullptr) {
relatedCard = CardDatabaseManager::getInstance()->getCard(cardRelation->getName());
}
if (relatedCard == nullptr) {
continue;
}
QString relatedCardName;
if (relatedCard->getPowTough().size() > 0) {

View file

@ -243,6 +243,17 @@ SettingsCache::SettingsCache()
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
overrideAllCardArtWithPersonalPreference =
settings->value("cards/overrideallcardartwithpersonalpreference", false).toBool();
bumpSetsWithCardsInDeckToTop = settings->value("cards/bumpsetswithcardsindecktotop", true).toBool();
printingSelectorSortOrder = settings->value("cards/printingselectorsortorder", 1).toInt();
printingSelectorCardSize = settings->value("cards/printingselectorcardsize", 100).toInt();
printingSelectorSortOptionsVisible = settings->value("cards/printingselectorsortoptionsvisible", true).toBool();
printingSelectorSearchBarVisible = settings->value("cards/printingselectorcardsearchbarvisible", true).toBool();
printingSelectorCardSizeSliderVisible =
settings->value("cards/printingselectorcardsizeslidervisible", true).toBool();
printingSelectorNavigationButtonsVisible =
settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
horizontalHand = settings->value("hand/horizontal", true).toBool();
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
@ -534,6 +545,62 @@ void SettingsCache::setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames)
emit displayCardNamesChanged();
}
void SettingsCache::setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T _overrideAllCardArt)
{
overrideAllCardArtWithPersonalPreference = static_cast<bool>(_overrideAllCardArt);
settings->setValue("cards/overrideallcardartwithpersonalpreference", overrideAllCardArtWithPersonalPreference);
emit overrideAllCardArtWithPersonalPreferenceChanged();
}
void SettingsCache::setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop)
{
bumpSetsWithCardsInDeckToTop = static_cast<bool>(_bumpSetsWithCardsInDeckToTop);
settings->setValue("cards/bumpsetswithcardsindecktotop", bumpSetsWithCardsInDeckToTop);
emit bumpSetsWithCardsInDeckToTopChanged();
}
void SettingsCache::setPrintingSelectorSortOrder(int _printingSelectorSortOrder)
{
printingSelectorSortOrder = _printingSelectorSortOrder;
settings->setValue("cards/printingselectorsortorder", printingSelectorSortOrder);
emit printingSelectorSortOrderChanged();
}
void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
{
printingSelectorCardSize = _printingSelectorCardSize;
settings->setValue("cards/printingselectorcardsize", printingSelectorCardSize);
emit printingSelectorCardSizeChanged();
}
void SettingsCache::setPrintingSelectorSortOptionsVisible(QT_STATE_CHANGED_T _sortOptionsVisible)
{
printingSelectorSortOptionsVisible = _sortOptionsVisible;
settings->setValue("cards/printingselectorsortoptionsvisible", printingSelectorSortOptionsVisible);
emit printingSelectorSortOptionsVisibleChanged();
}
void SettingsCache::setPrintingSelectorSearchBarVisible(QT_STATE_CHANGED_T _searchBarVisible)
{
printingSelectorSearchBarVisible = _searchBarVisible;
settings->setValue("cards/printingselectorsearchbarvisible", printingSelectorSearchBarVisible);
emit printingSelectorSearchBarVisibleChanged();
}
void SettingsCache::setPrintingSelectorCardSizeSliderVisible(QT_STATE_CHANGED_T _cardSizeSliderVisible)
{
printingSelectorCardSizeSliderVisible = _cardSizeSliderVisible;
settings->setValue("cards/printingselectorcardsizeslidervisible", printingSelectorCardSizeSliderVisible);
emit printingSelectorCardSizeSliderVisibleChanged();
}
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible)
{
printingSelectorNavigationButtonsVisible = _navigationButtonsVisible;
settings->setValue("cards/printingselectornavigationbuttonsvisible", printingSelectorNavigationButtonsVisible);
emit printingSelectorNavigationButtonsVisibleChanged();
}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
{
horizontalHand = static_cast<bool>(_horizontalHand);

View file

@ -48,6 +48,14 @@ signals:
void themeChanged();
void picDownloadChanged();
void displayCardNamesChanged();
void overrideAllCardArtWithPersonalPreferenceChanged();
void bumpSetsWithCardsInDeckToTopChanged();
void printingSelectorSortOrderChanged();
void printingSelectorCardSizeChanged();
void printingSelectorSortOptionsVisibleChanged();
void printingSelectorSearchBarVisibleChanged();
void printingSelectorCardSizeSliderVisibleChanged();
void printingSelectorNavigationButtonsVisibleChanged();
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@ -100,6 +108,14 @@ private:
QByteArray tabGameSplitterSizes;
bool showShortcuts;
bool displayCardNames;
bool overrideAllCardArtWithPersonalPreference;
bool bumpSetsWithCardsInDeckToTop;
int printingSelectorSortOrder;
int printingSelectorCardSize;
bool printingSelectorSortOptionsVisible;
bool printingSelectorSearchBarVisible;
bool printingSelectorCardSizeSliderVisible;
bool printingSelectorNavigationButtonsVisible;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@ -304,6 +320,38 @@ public:
{
return displayCardNames;
}
bool getOverrideAllCardArtWithPersonalPreference() const
{
return overrideAllCardArtWithPersonalPreference;
}
bool getBumpSetsWithCardsInDeckToTop() const
{
return bumpSetsWithCardsInDeckToTop;
}
int getPrintingSelectorSortOrder() const
{
return printingSelectorSortOrder;
}
int getPrintingSelectorCardSize() const
{
return printingSelectorCardSize;
}
bool getPrintingSelectorSortOptionsVisible() const
{
return printingSelectorSortOptionsVisible;
}
bool getPrintingSelectorSearchBarVisible() const
{
return printingSelectorSearchBarVisible;
}
bool getPrintingSelectorCardSizeSliderVisible() const
{
return printingSelectorCardSizeSliderVisible;
}
bool getPrintingSelectorNavigationButtonsVisible() const
{
return printingSelectorNavigationButtonsVisible;
}
bool getHorizontalHand() const
{
return horizontalHand;
@ -584,6 +632,14 @@ public slots:
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
void setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T _overrideAllCardArt);
void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
void setPrintingSelectorSortOrder(int _printingSelectorSortOrder);
void setPrintingSelectorCardSize(int _printingSelectorCardSize);
void setPrintingSelectorSortOptionsVisible(QT_STATE_CHANGED_T _sortOptionsVisible);
void setPrintingSelectorSearchBarVisible(QT_STATE_CHANGED_T _searchBarVisible);
void setPrintingSelectorCardSizeSliderVisible(QT_STATE_CHANGED_T _cardSizeSliderVisible);
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);

View file

@ -1,6 +1,6 @@
#include "layouts_settings.h"
LayoutsSettings::LayoutsSettings(QString settingPath, QObject *parent)
LayoutsSettings::LayoutsSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "layouts.ini", parent)
{
}
@ -25,7 +25,7 @@ void LayoutsSettings::setDeckEditorGeometry(const QByteArray &value)
setValue(value, "layouts/deckEditor_geometry");
}
const QSize LayoutsSettings::getDeckEditorCardSize()
QSize LayoutsSettings::getDeckEditorCardSize()
{
QVariant previous = getValue("layouts/deckEditor_CardSize");
return previous == QVariant() ? QSize(250, 500) : previous.toSize();
@ -36,7 +36,7 @@ void LayoutsSettings::setDeckEditorCardSize(const QSize &value)
setValue(value, "layouts/deckEditor_CardSize");
}
const QSize LayoutsSettings::getDeckEditorDeckSize()
QSize LayoutsSettings::getDeckEditorDeckSize()
{
QVariant previous = getValue("layouts/deckEditor_DeckSize");
return previous == QVariant() ? QSize(250, 360) : previous.toSize();
@ -47,7 +47,18 @@ void LayoutsSettings::setDeckEditorDeckSize(const QSize &value)
setValue(value, "layouts/deckEditor_DeckSize");
}
const QSize LayoutsSettings::getDeckEditorFilterSize()
QSize LayoutsSettings::getDeckEditorPrintingSelectorSize()
{
QVariant previous = getValue("layouts/deckEditor_PrintingSelectorSize");
return previous == QVariant() ? QSize(525, 250) : previous.toSize();
}
void LayoutsSettings::setDeckEditorPrintingSelectorSize(const QSize &value)
{
setValue(value, "layouts/deckEditor_PrintingSelectorSize");
}
QSize LayoutsSettings::getDeckEditorFilterSize()
{
QVariant previous = getValue("layouts/deckEditor_FilterSize");
return previous == QVariant() ? QSize(250, 250) : previous.toSize();

View file

@ -15,6 +15,7 @@ public:
void setDeckEditorGeometry(const QByteArray &value);
void setDeckEditorCardSize(const QSize &value);
void setDeckEditorDeckSize(const QSize &value);
void setDeckEditorPrintingSelectorSize(const QSize &value);
void setDeckEditorFilterSize(const QSize &value);
void setDeckEditorDbHeaderState(const QByteArray &value);
void setSetsDialogHeaderState(const QByteArray &value);
@ -34,9 +35,10 @@ public:
const QByteArray getDeckEditorLayoutState();
const QByteArray getDeckEditorGeometry();
const QSize getDeckEditorCardSize();
const QSize getDeckEditorDeckSize();
const QSize getDeckEditorFilterSize();
QSize getDeckEditorCardSize();
QSize getDeckEditorDeckSize();
QSize getDeckEditorPrintingSelectorSize();
QSize getDeckEditorFilterSize();
const QByteArray getDeckEditorDbHeaderState();
const QByteArray getSetsDialogHeaderState();
@ -57,7 +59,7 @@ signals:
public slots:
private:
explicit LayoutsSettings(QString settingPath, QObject *parent = nullptr);
explicit LayoutsSettings(const QString &settingPath, QObject *parent = nullptr);
LayoutsSettings(const LayoutsSettings & /*other*/);
};

View file

@ -21,4 +21,40 @@ public:
}
};
class SetReleaseDateComparator
{
public:
/*
* Returns true if a has higher download priority than b
* Enabled sets have priority over disabled sets
* Both groups follow the user-defined order
*/
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
{
if (a->getEnabled()) {
return !b->getEnabled() || a->getReleaseDate() < b->getReleaseDate();
} else {
return !b->getEnabled() && a->getReleaseDate() < b->getReleaseDate();
}
}
};
class CardSetPriorityComparator
{
public:
/*
* Returns true if a has higher download priority than b
* Enabled sets have priority over disabled sets
* Both groups follow the user-defined order
*/
inline bool operator()(const CardInfoPerSet &a, const CardInfoPerSet &b) const
{
if (a.getPtr()->getEnabled()) {
return !b.getPtr()->getEnabled() || a.getPtr()->getSortKey() < b.getPtr()->getSortKey();
} else {
return !b.getPtr()->getEnabled() && a.getPtr()->getSortKey() < b.getPtr()->getSortKey();
}
}
};
#endif // SET_PRIORITY_COMPARATOR_H

View file

@ -156,12 +156,17 @@ AbstractDecklistNode *InnerDecklistNode::findChild(const QString &_name)
return nullptr;
}
AbstractDecklistNode *InnerDecklistNode::findCardChildByNameAndProviderId(const QString &_name,
const QString &_providerId)
AbstractDecklistNode *InnerDecklistNode::findCardChildByNameProviderIdAndNumber(const QString &_name,
const QString &_providerId,
const QString &_cardNumber)
{
for (int i = 0; i < size(); i++) {
if (at(i) != nullptr && at(i)->getName() == _name && at(i)->getCardProviderId() == _providerId) {
return at(i);
for (const auto &i : *this) {
if (i != nullptr && i->getName() == _name) {
if (i->getCardCollectorNumber() == _cardNumber) {
if (i->getCardProviderId() == _providerId) {
return i;
}
}
}
}
return nullptr;
@ -319,13 +324,13 @@ void AbstractDecklistCardNode::writeElement(QXmlStreamWriter *xml)
xml->writeAttribute("number", QString::number(getNumber()));
xml->writeAttribute("name", getName());
if (getCardSetShortName().isEmpty()) {
if (!getCardSetShortName().isEmpty()) {
xml->writeAttribute("setShortName", getCardSetShortName());
}
if (getCardCollectorNumber().isEmpty()) {
if (!getCardCollectorNumber().isEmpty()) {
xml->writeAttribute("collectorNumber", getCardCollectorNumber());
}
if (getCardProviderId().isEmpty()) {
if (!getCardProviderId().isEmpty()) {
xml->writeAttribute("uuid", getCardProviderId());
}
}

View file

@ -66,6 +66,7 @@ public:
virtual QString getCardProviderId() const = 0;
virtual QString getCardSetShortName() const = 0;
virtual QString getCardCollectorNumber() const = 0;
[[nodiscard]] virtual bool isDeckHeader() const = 0;
InnerDecklistNode *getParent() const
{
return parent;
@ -128,10 +129,16 @@ public:
{
cardCollectorNumber = _cardCollectorNumber;
}
[[nodiscard]] bool isDeckHeader() const override
{
return true;
}
void clearTree();
AbstractDecklistNode *findChild(const QString &_name);
AbstractDecklistNode *findCardChildByNameAndProviderId(const QString &_name, const QString &_providerId);
AbstractDecklistNode *findCardChildByNameProviderIdAndNumber(const QString &_name,
const QString &_providerId,
const QString &_cardNumber = "");
int height() const override;
int recursiveCount(bool countTotalCards = false) const;
bool compare(AbstractDecklistNode *other) const override;
@ -233,6 +240,10 @@ public:
{
cardSetNumber = _cardSetNumber;
}
[[nodiscard]] bool isDeckHeader() const override
{
return false;
}
};
class DeckList : public QObject

View file

@ -25,4 +25,6 @@ message Command_CreateToken {
// What to do with the target card. Ignored if there is no target card.
optional TargetMode target_mode = 11;
optional string card_provider_id = 12;
}

View file

@ -14,4 +14,5 @@ message Event_CreateToken {
optional bool destroy_on_zone_change = 7;
optional sint32 x = 8;
optional sint32 y = 9;
optional string card_provider_id = 10;
}

View file

@ -391,6 +391,7 @@ static Event_CreateToken makeCreateTokenEvent(Server_CardZone *zone, Server_Card
event.set_zone_name(zone->getName().toStdString());
event.set_card_id(card->getId());
event.set_card_name(card->getName().toStdString());
event.set_card_provider_id(card->getProviderId().toStdString());
event.set_color(card->getColor().toStdString());
event.set_pt(card->getPT().toStdString());
event.set_annotation(card->getAnnotation().toStdString());
@ -1400,7 +1401,8 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
}
}
QString cardName = nameFromStdString(cmd.card_name());
const QString cardName = nameFromStdString(cmd.card_name());
const QString cardProviderId = nameFromStdString(cmd.card_provider_id());
if (zone->hasCoords()) {
xCoord = zone->getFreeGridColumn(xCoord, yCoord, cardName, false);
}
@ -1411,7 +1413,7 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
yCoord = 0;
}
auto *card = new Server_Card(cardName, QString(), newCardId(), xCoord, yCoord);
auto *card = new Server_Card(cardName, cardProviderId, newCardId(), xCoord, yCoord);
card->moveToThread(thread());
card->setPT(nameFromStdString(cmd.pt()));
card->setColor(nameFromStdString(cmd.color()));

View file

@ -160,6 +160,30 @@ void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T /* _showShortcuts */)
void SettingsCache::setDisplayCardNames(QT_STATE_CHANGED_T /* _displayCardNames */)
{
}
void SettingsCache::setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T /* _displayCardNames */)
{
}
void SettingsCache::setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T /* _bumpSetsWithCardsInDeckToTop */)
{
}
void SettingsCache::setPrintingSelectorSortOrder(int /* _printingSelectorSortOrder */)
{
}
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
{
}
void SettingsCache::setPrintingSelectorSortOptionsVisible(QT_STATE_CHANGED_T /* _sortOptionsVisible */)
{
}
void SettingsCache::setPrintingSelectorSearchBarVisible(QT_STATE_CHANGED_T /* _searchBarVisible */)
{
}
void SettingsCache::setPrintingSelectorCardSizeSliderVisible(QT_STATE_CHANGED_T /* _cardSizeSliderVisible */)
{
}
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
{
}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}

View file

@ -10,9 +10,9 @@
#define PICTURELOADER_H
#include "../cockatrice/src/game/cards/card_database.h"
#include "../cockatrice/src/settings/cache_settings.h"
#include "../cockatrice/src/utility/macros.h"
#include "../../cockatrice/src/game/cards/card_database.h"
#include "../../cockatrice/src/settings/cache_settings.h"
#include "../../cockatrice/src/utility/macros.h"
extern SettingsCache *settingsCache;

View file

@ -3,7 +3,8 @@
#include "game/cards/card_database_parser/cockatrice_xml_4.h"
#include "qt-json/json.h"
#include <QtWidgets>
#include <QDebug>
#include <QRegularExpression>
#include <algorithm>
#include <climits>
@ -42,7 +43,7 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
return false;
}
QListIterator<QVariant> it(setsMap.values());
QListIterator it(setsMap.values());
QVariantMap map;
QString shortName;
@ -176,7 +177,7 @@ CardInfoPtr OracleImporter::addCard(QString name,
// insert the card and its properties
QList<CardRelation *> reverseRelatedCards;
CardInfoPerSetMap setsInfo;
setsInfo.insert(setInfo.getPtr()->getShortName(), setInfo);
setsInfo[setInfo.getPtr()->getShortName()].append(setInfo);
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards,
setsInfo, cipt, tableRow, upsideDown);
@ -193,9 +194,7 @@ QString OracleImporter::getStringPropertyFromMap(const QVariantMap &card, const
return card.contains(propertyName) ? card.value(propertyName).toString() : QString("");
}
int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
const QList<QVariant> &cardsList,
bool skipSpecialCards)
int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet, const QList<QVariant> &cardsList)
{
// mtgjson name => xml name
static const QMap<QString, QString> cardProperties{
@ -213,23 +212,17 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
QMap<QString, QList<SplitCardPart>> splitCards;
QString ptSeparator("/");
QVariantMap card;
QString layout, name, text, colors, colorIdentity, maintype, faceName;
static const bool isToken = false;
QString layout, name, text, colors, colorIdentity, faceName;
static constexpr bool isToken = false;
static const QList<QString> setsWithCardsWithSameNameButDifferentText = {"UST"};
QVariantHash properties;
CardInfoPerSet setInfo;
QList<CardRelation *> relatedCards;
static const QList<QString> specialNumChars = {"", "s", ""};
QMap<QString, QVariant> specialPromoCards;
QList<QString> allNameProps;
for (const QVariant &cardVar : cardsList) {
card = cardVar.toMap();
// skip alternatives
if (getStringPropertyFromMap(card, "isAlternative") == "true") {
continue;
}
/* Currently used layouts are:
* augment, double_faced_token, flip, host, leveler, meld, normal, planar,
* saga, scheme, split, token, transform, vanguard
@ -251,7 +244,7 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
// card properties
properties.clear();
QMapIterator<QString, QString> it(cardProperties);
QMapIterator it(cardProperties);
while (it.hasNext()) {
it.next();
QString mtgjsonProperty = it.key();
@ -263,7 +256,7 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
// per-set properties
setInfo = CardInfoPerSet(currentSet);
QMapIterator<QString, QString> it2(setInfoProperties);
QMapIterator it2(setInfoProperties);
while (it2.hasNext()) {
it2.next();
QString mtgjsonProperty = it2.key();
@ -274,7 +267,7 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
}
// Identifiers
QMapIterator<QString, QString> it3(identifierProperties);
QMapIterator it3(identifierProperties);
while (it3.hasNext()) {
it3.next();
auto mtgjsonProperty = it3.key();
@ -285,43 +278,16 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
}
}
QString numComponent{};
if (skipSpecialCards) {
QString numProperty = setInfo.getProperty("num");
// skip promo cards if it's not the only print, cards with two faces are different cards
if (allNameProps.contains(faceName)) {
// check for alternative versions
if (layout != "normal")
continue;
QString numComponent;
const QString numProperty = setInfo.getProperty("num");
const QChar lastChar = numProperty.at(numProperty.size() - 1);
// alternative versions have a letter in the end of num like abc
// note this will also catch p and s, those will get removed later anyway
QChar lastChar = numProperty.at(numProperty.size() - 1);
if (!lastChar.isLetter())
continue;
numComponent = " (" + QString(lastChar) + ")";
faceName += numComponent; // add to facename to make it unique
}
if (getStringPropertyFromMap(card, "isPromo") == "true") {
specialPromoCards.insert(faceName, cardVar);
continue;
}
bool skip = false;
// skip cards containing special stuff in the collectors number like promo cards
for (const QString &specialChar : specialNumChars) {
if (numProperty.contains(specialChar)) {
skip = true;
break;
}
}
if (skip) {
specialPromoCards.insert(faceName, cardVar);
continue;
} else {
allNameProps.append(faceName);
}
// Un-Sets do some wonky stuff. Split up these cards as individual entries.
if (setsWithCardsWithSameNameButDifferentText.contains(currentSet->getShortName()) &&
allNameProps.contains(faceName) && layout == "normal" && lastChar.isLetter()) {
numComponent = " (" + QString(lastChar).toLower() + ")";
}
allNameProps.append(faceName);
// special handling properties
colors = card.value("colors").toStringList().join("");
@ -463,18 +429,6 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
numCards++;
}
// only add the unique promo cards that didn't already exist in the set
if (skipSpecialCards) {
QList<QVariant> nonDuplicatePromos;
for (auto cardIter = specialPromoCards.constBegin(); cardIter != specialPromoCards.constEnd(); ++cardIter) {
if (!allNameProps.contains(cardIter.key())) {
nonDuplicatePromos.append(cardIter.value());
}
}
if (!nonDuplicatePromos.isEmpty()) {
numCards += importCardsFromSet(currentSet, nonDuplicatePromos, false);
}
}
return numCards;
}

View file

@ -143,7 +143,7 @@ public:
bool readSetsFromByteArray(const QByteArray &data);
int startImport();
bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion);
int importCardsFromSet(const CardSetPtr &currentSet, const QList<QVariant> &cards, bool skipSpecialNums = true);
int importCardsFromSet(const CardSetPtr &currentSet, const QList<QVariant> &cards);
QList<SetToDownload> &getSets()
{
return allSets;

View file

@ -164,6 +164,30 @@ void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T /* _showShortcuts */)
void SettingsCache::setDisplayCardNames(QT_STATE_CHANGED_T /* _displayCardNames */)
{
}
void SettingsCache::setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T /* _overrideAllCardArt */)
{
}
void SettingsCache::setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T /* _bumpSetsWithCardsInDeckToTop */)
{
}
void SettingsCache::setPrintingSelectorSortOrder(int /* _printingSelectorSortOrder */)
{
}
void SettingsCache::setPrintingSelectorCardSize(int /* _printingSelectorCardSize */)
{
}
void SettingsCache::setPrintingSelectorSortOptionsVisible(QT_STATE_CHANGED_T /* _sortOptionsVisible */)
{
}
void SettingsCache::setPrintingSelectorSearchBarVisible(QT_STATE_CHANGED_T /* _searchBarVisible */)
{
}
void SettingsCache::setPrintingSelectorCardSizeSliderVisible(QT_STATE_CHANGED_T /* _cardSizeSliderVisible */)
{
}
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
{
}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}

View file

@ -12,7 +12,7 @@
#include "../../cockatrice/src/game/cards/card_database.h"
#include "../../cockatrice/src/settings/cache_settings.h"
#include "../cockatrice/src/utility/macros.h"
#include "../../cockatrice/src/utility/macros.h"
extern SettingsCache *settingsCache;