Refactor printing selector onto a host interface

Move the deck-editor coupling out of PrintingSelector behind PrintingSelectorHost so the same widget can run where there is no deck. The deck editor keeps its behaviour through DeckEditorPrintingSelectorHost; a selection-only host hides deck controls, reports a picked printing, and highlights it in the grid.
This commit is contained in:
Lukas Brübach 2026-11-09 11:15:03 +01:00
parent 60941f5c70
commit 0014bb4b44
16 changed files with 362 additions and 89 deletions

View file

@ -218,6 +218,7 @@ set(cockatrice_SOURCES
src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_printing_selector_host.cpp
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
src/interface/widgets/deck_editor/deck_state_manager.cpp
src/interface/widgets/deck_editor/deck_zone_dialog.cpp

View file

@ -4,6 +4,7 @@
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
#include "../printing_selector/printing_selector.h"
#include "deck_editor_deck_dock_widget.h"
#include "deck_editor_printing_selector_host.h"
#include "printing_disabled_info_widget.h"
#include <QFlags>
@ -32,9 +33,12 @@ DeckEditorPrintingSelectorDockWidget::DeckEditorPrintingSelectorDockWidget(Abstr
retranslateUi();
}
DeckEditorPrintingSelectorDockWidget::~DeckEditorPrintingSelectorDockWidget() = default;
void DeckEditorPrintingSelectorDockWidget::createPrintingSelectorDock()
{
printingSelector = new PrintingSelector(this, deckEditor);
printingSelectorHost = std::make_unique<DeckEditorPrintingSelectorHost>(deckEditor);
printingSelector = new PrintingSelector(this, printingSelectorHost.get());
printingSelector->setObjectName("printingSelector");
auto *printingSelectorFrame = new QVBoxLayout;
printingSelectorFrame->setObjectName("printingSelectorFrame");

View file

@ -8,8 +8,10 @@
#define DECK_EDITOR_PRINTING_SELECTOR_DOCK_WIDGET_H
#include <QDockWidget>
#include <memory>
#include <qtmetamacros.h>
class DeckEditorPrintingSelectorHost;
class PrintingDisabledInfoWidget;
class AbstractTabDeckEditor;
class PrintingSelector;
@ -20,6 +22,7 @@ class DeckEditorPrintingSelectorDockWidget : public QDockWidget
Q_OBJECT
public:
explicit DeckEditorPrintingSelectorDockWidget(AbstractTabDeckEditor *parent);
~DeckEditorPrintingSelectorDockWidget() override;
void createPrintingSelectorDock();
void retranslateUi();
@ -27,6 +30,7 @@ public:
private:
AbstractTabDeckEditor *deckEditor;
std::unique_ptr<DeckEditorPrintingSelectorHost> printingSelectorHost;
QWidget *printingSelectorDockContents;
PrintingDisabledInfoWidget *printingDisabledInfoWidget;

View file

@ -0,0 +1,33 @@
#include "deck_editor_printing_selector_host.h"
#include "../tabs/abstract_tab_deck_editor.h"
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/database/card_database_querier.h>
#include <libcockatrice/utility/card_ref.h>
DeckEditorPrintingSelectorHost::DeckEditorPrintingSelectorHost(AbstractTabDeckEditor *_deckEditor)
: deckEditor(_deckEditor)
{
}
DeckStateManager *DeckEditorPrintingSelectorHost::getDeckStateManager() const
{
return deckEditor->deckStateManager;
}
void DeckEditorPrintingSelectorHost::showCard(const ExactCard &card)
{
deckEditor->updateCard(card);
}
void DeckEditorPrintingSelectorHost::showRelatedCard(const QString &cardName)
{
deckEditor->updateCard(CardDatabaseManager::query()->getCard(CardRef{.name = cardName}));
deckEditor->showPrintingSelector();
}
bool DeckEditorPrintingSelectorHost::isSelectionOnly() const
{
return false;
}

View file

@ -0,0 +1,29 @@
/**
* @file deck_editor_printing_selector_host.h
* @ingroup DeckEditorWidgets
* @brief Connects a PrintingSelector to a deck editor tab.
*/
#ifndef DECK_EDITOR_PRINTING_SELECTOR_HOST_H
#define DECK_EDITOR_PRINTING_SELECTOR_HOST_H
#include "../printing_selector/printing_selector_host.h"
class AbstractTabDeckEditor;
/** @brief Deck-editor implementation of PrintingSelectorHost. */
class DeckEditorPrintingSelectorHost final : public PrintingSelectorHost
{
public:
explicit DeckEditorPrintingSelectorHost(AbstractTabDeckEditor *deckEditor);
[[nodiscard]] DeckStateManager *getDeckStateManager() const override;
void showCard(const ExactCard &card) override;
void showRelatedCard(const QString &cardName) override;
[[nodiscard]] bool isSelectionOnly() const override;
private:
AbstractTabDeckEditor *deckEditor;
};
#endif // DECK_EDITOR_PRINTING_SELECTOR_HOST_H

View file

@ -5,7 +5,6 @@
#include "../deck_editor/deck_state_manager.h"
#include "../general/layout_containers/flow_widget.h"
#include "../quick_settings/settings_button_widget.h"
#include "../tabs/abstract_tab_deck_editor.h"
#include "deck_list_model.h"
#include "libcockatrice/card/card_info.h"
#include "libcockatrice/card/printing/exact_card.h"
@ -16,10 +15,10 @@
#include "printing_selector_card_search_widget.h"
#include "printing_selector_card_selection_widget.h"
#include "printing_selector_card_sorting_widget.h"
#include "printing_selector_host.h"
#include "printing_selector_placeholder_widget.h"
#include <QCheckBox>
#include <QDebug>
#include <QHBoxLayout>
#include <QHideEvent>
#include <QList>
@ -27,8 +26,8 @@
#include <QScrollArea>
#include <QScrollBar>
#include <QSharedPointer>
#include <QSizePolicy>
#include <QShowEvent>
#include <QSizePolicy>
#include <QString>
#include <QTimer>
#include <QVBoxLayout>
@ -46,10 +45,10 @@
* for the selected card.
*
* @param parent The parent widget for the PrintingSelector.
* @param deckEditor The TabDeckEditor instance used for managing the deck.
* @param _host The host supplying deck state and routing card activations.
*/
PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deckEditor)
: QWidget(parent), deckEditor(_deckEditor), deckStateManager(_deckEditor->deckStateManager)
PrintingSelector::PrintingSelector(QWidget *parent, PrintingSelectorHost *_host)
: QWidget(parent), host(_host), deckStateManager(_host->getDeckStateManager())
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout = new QVBoxLayout(this);
@ -70,14 +69,16 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
displayOptionsWidget = new SettingsButtonWidget(this);
displayOptionsWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
// Create the checkbox for navigation buttons visibility
navigationCheckBox = new QCheckBox(this);
navigationCheckBox->setChecked(
SettingsCache::instance().cardsDisplay().getPrintingSelectorNavigationButtonsVisible());
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
&PrintingSelector::toggleVisibilityNavigationButtons);
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::setPrintingSelectorNavigationButtonsVisible);
// Navigation only makes sense while the selector is attached to a deck.
if (deckStateManager) {
navigationCheckBox = new QCheckBox(this);
navigationCheckBox->setChecked(
SettingsCache::instance().cardsDisplay().getPrintingSelectorNavigationButtonsVisible());
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
&PrintingSelector::toggleVisibilityNavigationButtons);
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::setPrintingSelectorNavigationButtonsVisible);
}
cardSizeWidget = new CardSizeWidget(displayOptionsWidget, flowWidget,
SettingsCache::instance().cardsDisplay().getPrintingSelectorCardSize());
@ -86,7 +87,9 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
cardSizeWidget->enableCtrlScrollResize(flowWidget);
displayOptionsWidget->addSettingsWidget(sortToolBar);
displayOptionsWidget->addSettingsWidget(navigationCheckBox);
if (navigationCheckBox) {
displayOptionsWidget->addSettingsWidget(navigationCheckBox);
}
displayOptionsWidget->addSettingsWidget(cardSizeWidget);
sortAndOptionsContainer = new QWidget(this);
@ -107,26 +110,31 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
placeholderWidget->setVisible(true);
flowWidget->setVisible(false);
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this, deckStateManager);
cardSelectionBar->setVisible(
SettingsCache::instance().cardsDisplay().getPrintingSelectorNavigationButtonsVisible());
layout->addWidget(cardSelectionBar);
if (deckStateManager) {
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this, deckStateManager);
cardSelectionBar->setVisible(
SettingsCache::instance().cardsDisplay().getPrintingSelectorNavigationButtonsVisible());
layout->addWidget(cardSelectionBar);
// Connect deck model data change signal to update display
connect(deckStateManager, &DeckStateManager::uniqueCardsChanged, this, &PrintingSelector::printingsInDeckChanged);
connect(deckStateManager, &DeckStateManager::cardModified, this, &PrintingSelector::updateCardAmounts);
// Connect deck model data change signal to update display
connect(deckStateManager, &DeckStateManager::uniqueCardsChanged, this,
&PrintingSelector::printingsInDeckChanged);
connect(deckStateManager, &DeckStateManager::cardModified, this, &PrintingSelector::updateCardAmounts);
}
retranslateUi();
}
void PrintingSelector::retranslateUi()
{
navigationCheckBox->setText(tr("Display Navigation Buttons"));
if (navigationCheckBox) {
navigationCheckBox->setText(tr("Display Navigation Buttons"));
}
}
void PrintingSelector::printingsInDeckChanged()
{
if (SettingsCache::instance().cardsDisplay().getBumpSetsWithCardsInDeckToTop()) {
if (deckStateManager && SettingsCache::instance().cardsDisplay().getBumpSetsWithCardsInDeckToTop()) {
displayDirty = true;
if (isVisible()) {
// Coalesce deck changes while the model settles.
@ -190,7 +198,7 @@ static QMap<QString, ZoneCounts> tallyUuidCounts(const DeckListModel *model, con
void PrintingSelector::updateCardAmounts()
{
if (selectedCard.isNull()) {
if (!deckStateManager || selectedCard.isNull()) {
return;
}
@ -209,11 +217,17 @@ void PrintingSelector::updateDisplay()
widgetLoadingBufferTimer->deleteLater();
widgetLoadingBufferTimer = new QTimer(this);
flowWidget->clearLayout();
cardDisplayWidgets.clear();
if (selectedCard.isNull()) {
// Show placeholder, hide flowWidget
placeholderWidget->setVisible(true);
flowWidget->setVisible(false);
if (placeholderText.isEmpty()) {
placeholderWidget->resetText();
} else {
placeholderWidget->setText(placeholderText);
}
setWindowTitle(tr("Printing Selector"));
} else {
// Hide placeholder, show flowWidget
@ -236,6 +250,11 @@ void PrintingSelector::setCard(const CardInfoPtr &newCard)
return;
}
// A new card invalidates the previously picked printing.
if (selectedCard.isNull() || newCard.isNull() || selectedCard->getName() != newCard->getName()) {
selectedProviderId.clear();
}
widgetLoadingBufferTimer->stop();
deckChangeTimer->stop();
selectedCard = newCard;
@ -263,16 +282,16 @@ void PrintingSelector::getAllSetsForCurrentCard()
const QList<PrintingInfo> filteredPrintings =
sortToolBar->filterSets(sortedPrintings, searchBar->getSearchText().trimmed().toLower());
QList<PrintingInfo> printingsToUse;
const DeckListModel *deckModel = deckStateManager ? deckStateManager->getModel() : nullptr;
if (SettingsCache::instance().cardsDisplay().getBumpSetsWithCardsInDeckToTop()) {
printingsToUse =
sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckStateManager->getModel());
if (deckModel && SettingsCache::instance().cardsDisplay().getBumpSetsWithCardsInDeckToTop()) {
printingsToUse = sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckModel);
} else {
printingsToUse = filteredPrintings;
}
printingsToUse = sortToolBar->prependPinnedPrintings(printingsToUse, selectedCard->getName());
auto uuidToAmounts = tallyUuidCounts(deckStateManager->getModel(), selectedCard->getName());
auto uuidToAmounts = deckModel ? tallyUuidCounts(deckModel, selectedCard->getName()) : QMap<QString, ZoneCounts>();
// Defer widget creation
currentIndex = 0;
@ -280,12 +299,24 @@ void PrintingSelector::getAllSetsForCurrentCard()
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) {
auto card = ExactCard(selectedCard, printingsToUse[currentIndex]);
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(this, deckEditor, deckStateManager,
cardSizeWidget->getSlider(), card);
auto *cardDisplayWidget =
new PrintingSelectorCardDisplayWidget(this, host, cardSizeWidget->getSlider(), card);
flowWidget->addWidget(cardDisplayWidget);
cardDisplayWidgets.append(cardDisplayWidget);
cardDisplayWidget->updateCardAmounts(uuidToAmounts);
cardDisplayWidget->setSelected(card.getPrinting().getUuid() == selectedProviderId);
connect(cardDisplayWidget, &PrintingSelectorCardDisplayWidget::cardPreferenceChanged, this,
&PrintingSelector::updateDisplay);
connect(cardDisplayWidget, &PrintingSelectorCardDisplayWidget::printingSelected, this,
[this](const ExactCard &selected) {
const QString providerId = selected.getPrinting().getUuid();
if (selectedProviderId == providerId) {
return;
}
selectedProviderId = providerId;
updateSelectedCardWidgets();
emit printingSelected(selected);
});
connect(this, &PrintingSelector::cardAmountsChanged, cardDisplayWidget,
&PrintingSelectorCardDisplayWidget::updateCardAmounts);
}
@ -306,5 +337,38 @@ void PrintingSelector::getAllSetsForCurrentCard()
*/
void PrintingSelector::toggleVisibilityNavigationButtons(bool _state)
{
cardSelectionBar->setVisible(_state);
}
if (cardSelectionBar) {
cardSelectionBar->setVisible(_state);
}
}
void PrintingSelector::setSelectedProviderId(const QString &providerId)
{
if (selectedProviderId == providerId) {
return;
}
selectedProviderId = providerId;
updateSelectedCardWidgets();
}
void PrintingSelector::updateSelectedCardWidgets() const
{
for (auto *cardDisplayWidget : cardDisplayWidgets) {
cardDisplayWidget->setSelected(!selectedProviderId.isEmpty() &&
cardDisplayWidget->getProviderId() == selectedProviderId);
}
}
void PrintingSelector::setPlaceholderText(const QString &text)
{
placeholderText = text;
if (selectedCard.isNull()) {
if (placeholderText.isEmpty()) {
placeholderWidget->resetText();
} else {
placeholderWidget->setText(placeholderText);
}
placeholderWidget->setVisible(true);
flowWidget->setVisible(false);
}
}

View file

@ -7,12 +7,18 @@
#ifndef PRINTING_SELECTOR_H
#define PRINTING_SELECTOR_H
#include "printing_selector_host.h"
#include <QList>
#include <QWidget>
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/card/printing/exact_card.h>
#include <qtmetamacros.h>
class CardSizeWidget;
class DeckStateManager;
class FlowWidget;
class PrintingSelectorCardDisplayWidget;
class PrintingSelectorPlaceholderWidget;
class QCheckBox;
class QHBoxLayout;
@ -33,20 +39,20 @@ struct ZoneCounts
int tokensboard = 0;
};
class DeckStateManager;
class PrintingSelectorCardSearchWidget;
class PrintingSelectorCardSelectionWidget;
class PrintingSelectorCardSortingWidget;
class AbstractTabDeckEditor;
class PrintingSelector : public QWidget
{
Q_OBJECT
public:
PrintingSelector(QWidget *parent, AbstractTabDeckEditor *deckEditor);
PrintingSelector(QWidget *parent, PrintingSelectorHost *host);
void setCard(const CardInfoPtr &newCard);
void setSelectedProviderId(const QString &providerId);
void setPlaceholderText(const QString &text);
void getAllSetsForCurrentCard();
protected:
@ -78,25 +84,36 @@ signals:
*/
void cardAmountsChanged(const QMap<QString, ZoneCounts> &uuidToAmounts);
/**
* A printing was picked while the selector runs in selection-only mode.
* @param card The picked card and printing.
*/
void printingSelected(const ExactCard &card);
private:
QVBoxLayout *layout;
SettingsButtonWidget *displayOptionsWidget;
QWidget *sortAndOptionsContainer;
QHBoxLayout *sortAndOptionsLayout;
QCheckBox *navigationCheckBox;
QCheckBox *navigationCheckBox = nullptr;
PrintingSelectorCardSortingWidget *sortToolBar;
PrintingSelectorCardSearchWidget *searchBar;
PrintingSelectorPlaceholderWidget *placeholderWidget;
FlowWidget *flowWidget;
CardSizeWidget *cardSizeWidget;
PrintingSelectorCardSelectionWidget *cardSelectionBar;
AbstractTabDeckEditor *deckEditor;
PrintingSelectorCardSelectionWidget *cardSelectionBar = nullptr;
PrintingSelectorHost *host;
DeckStateManager *deckStateManager;
QList<PrintingSelectorCardDisplayWidget *> cardDisplayWidgets;
CardInfoPtr selectedCard;
QString selectedProviderId;
QString placeholderText;
QTimer *widgetLoadingBufferTimer;
QTimer *deckChangeTimer;
bool displayDirty = false;
int currentIndex = 0;
void updateSelectedCardWidgets() const;
};
#endif // PRINTING_SELECTOR_H

View file

@ -5,6 +5,7 @@
#include "libcockatrice/card/set/card_set.h"
#include "printing_selector.h"
#include "printing_selector_card_overlay_widget.h"
#include "printing_selector_host.h"
#include "set_name_and_collectors_number_display_widget.h"
#include <QMap>
@ -14,8 +15,6 @@
#include <QVBoxLayout>
#include <qnamespace.h>
class AbstractTabDeckEditor;
class DeckStateManager;
class QSlider;
/**
@ -28,18 +27,20 @@ class QSlider;
* display.
*
* @param parent The parent widget for this display.
* @param deckEditor The TabDeckEditor instance for deck management.
* @param deckStateManager The DeckStateManager instance providing deck data.
* @param host The host supplying deck state and routing card activations.
* @param cardSizeSlider The slider controlling the size of the displayed card.
* @param rootCard The root card object, representing the card to be displayed.
*/
PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckStateManager *deckStateManager,
PrintingSelectorHost *host,
QSlider *cardSizeSlider,
const ExactCard &rootCard)
: QWidget(parent), rootCard(rootCard)
: QWidget(parent), rootCard(rootCard), selectionOnly(host->isSelectionOnly())
{
if (selectionOnly) {
// A plain QWidget only paints a stylesheet border with a styled background.
setAttribute(Qt::WA_StyledBackground, true);
}
layout = new QVBoxLayout(this);
layout->setContentsMargins(5, 5, 5, 5);
layout->setSpacing(3);
@ -47,9 +48,11 @@ PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *pa
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Create the overlay widget for the card display
overlayWidget = new PrintingSelectorCardOverlayWidget(this, deckEditor, deckStateManager, cardSizeSlider, rootCard);
overlayWidget = new PrintingSelectorCardOverlayWidget(this, host, cardSizeSlider, rootCard);
connect(overlayWidget, &PrintingSelectorCardOverlayWidget::cardPreferenceChanged, this,
[this]() { emit cardPreferenceChanged(); });
connect(overlayWidget, &PrintingSelectorCardOverlayWidget::printingSelected, this,
[this](const ExactCard &card) { emit printingSelected(card); });
CardSetPtr set = rootCard.getPrinting().getSet();
@ -89,3 +92,19 @@ void PrintingSelectorCardDisplayWidget::resizeEvent(QResizeEvent *event)
QWidget::resizeEvent(event);
clampSetNameToPicture();
}
void PrintingSelectorCardDisplayWidget::setSelected(bool selected)
{
if (!selectionOnly) {
return;
}
// Keep an invisible border in both states so selection does not reflow the grid.
const QString border = selected ? QStringLiteral("palette(highlight)") : QStringLiteral("transparent");
setStyleSheet(
QStringLiteral("PrintingSelectorCardDisplayWidget { border: 2px solid %1; border-radius: 4px; }").arg(border));
}
QString PrintingSelectorCardDisplayWidget::getProviderId() const
{
return rootCard.getPrinting().getUuid();
}

View file

@ -17,9 +17,8 @@
#include <QWidget>
#include <qtmetamacros.h>
class AbstractTabDeckEditor;
class DeckStateManager;
class PrintingSelectorCardOverlayWidget;
class PrintingSelectorHost;
class QSlider;
class QString;
class QVBoxLayout;
@ -33,11 +32,13 @@ class PrintingSelectorCardDisplayWidget : public QWidget
public:
PrintingSelectorCardDisplayWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckStateManager *deckStateManager,
PrintingSelectorHost *host,
QSlider *cardSizeSlider,
const ExactCard &rootCard);
void setSelected(bool selected);
[[nodiscard]] QString getProviderId() const;
public slots:
void clampSetNameToPicture();
void updateCardAmounts(const QMap<QString, ZoneCounts> &uuidToAmounts);
@ -46,9 +47,11 @@ public slots:
signals:
void cardPreferenceChanged();
void printingSelected(const ExactCard &card);
private:
ExactCard rootCard;
bool selectionOnly;
QVBoxLayout *layout;
SetNameAndCollectorsNumberDisplayWidget *setNameAndCollectorsNumberDisplayWidget;
PrintingSelectorCardOverlayWidget *overlayWidget;

View file

@ -5,17 +5,15 @@
#include "../../theme_icon.h"
#include "../../theme_manager.h"
#include "../cards/card_info_picture_widget.h"
#include "../tabs/abstract_tab_deck_editor.h"
#include "all_zones_card_amount_widget.h"
#include "libcockatrice/card/card_info.h"
#include "libcockatrice/card/database/card_database_querier.h"
#include "libcockatrice/card/printing/printing_info.h"
#include "libcockatrice/card/set/card_set.h"
#include "printing_selector_host.h"
#include <QAction>
#include <QApplication>
#include <QColor>
#include <QDebug>
#include <QFileDialog>
#include <QGuiApplication>
#include <QImage>
@ -41,14 +39,12 @@
#include <QVBoxLayout>
#include <QVariant>
#include <QtGlobal>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/settings/card_override_settings.h>
#include <libcockatrice/utility/card_ref.h>
#include <libcockatrice/utility/qt_utils.h>
#include <qnamespace.h>
class DeckStateManager;
namespace
{
/**
@ -100,17 +96,15 @@ previewPositionNear(const QRect &actionRect, const QSize &labelSize, const QRect
* 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 deckStateManager The DeckStateManager instance providing deck data.
* @param _host The host supplying deck state and routing card activations.
* @param cardSizeSlider The slider controlling the size of the card.
* @param _rootCard The root card object that contains information about the card.
*/
PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckStateManager *deckStateManager,
PrintingSelectorHost *_host,
QSlider *cardSizeSlider,
const ExactCard &_rootCard)
: QWidget(parent), deckEditor(_deckEditor), rootCard(_rootCard)
: QWidget(parent), host(_host), rootCard(_rootCard)
{
// Set up the main layout
auto *mainLayout = QtUtils::makeLayout<QVBoxLayout>(this, 0);
@ -123,6 +117,14 @@ PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *pa
cardInfoPicture->setCard(_rootCard);
mainLayout->addWidget(cardInfoPicture);
// In a selection-only host a click picks this printing instead of changing a deck.
connect(cardInfoPicture, &CardInfoPictureWidget::cardClicked, this,
[this](QMouseEvent *event, const ExactCard &card) {
if (host->isSelectionOnly() && event->button() == Qt::LeftButton) {
emit printingSelected(card);
}
});
initializePinBadge();
auto refreshPinBadge = [this] {
initializePinBadge();
@ -163,10 +165,11 @@ PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *pa
// initial state
updatePinBadgeVisibility();
// Add AllZonesCardAmountWidget
allZonesCardAmountWidget = new AllZonesCardAmountWidget(this, deckStateManager, cardSizeSlider, _rootCard);
allZonesCardAmountWidget->raise(); // Ensure it's on top of the picture
// Amount controls are deck-only; a selection-only host has no deck to change.
if (DeckStateManager *deckStateManager = host->getDeckStateManager()) {
allZonesCardAmountWidget = new AllZonesCardAmountWidget(this, deckStateManager, cardSizeSlider, _rootCard);
allZonesCardAmountWidget->raise(); // Ensure it's on top of the picture
}
connect(cardSizeSlider, &QSlider::valueChanged, cardInfoPicture, &CardInfoPictureWidget::setScaleFactor);
}
@ -216,7 +219,7 @@ void PrintingSelectorCardOverlayWidget::resizeEvent(QResizeEvent *event)
void PrintingSelectorCardOverlayWidget::enterEvent(QEnterEvent *event)
{
QWidget::enterEvent(event);
deckEditor->updateCard(rootCard);
host->showCard(rootCard);
updateVisibility();
}
@ -224,6 +227,9 @@ void PrintingSelectorCardOverlayWidget::updateCardAmounts(int mainboardAmount,
int sideboardAmount,
int tokensboardAmount)
{
if (!allZonesCardAmountWidget) {
return;
}
allZonesCardAmountWidget->setAmounts(mainboardAmount, sideboardAmount, tokensboardAmount);
updateVisibility();
}
@ -233,6 +239,9 @@ void PrintingSelectorCardOverlayWidget::updateCardAmounts(int mainboardAmount,
*/
void PrintingSelectorCardOverlayWidget::updateVisibility()
{
if (!allZonesCardAmountWidget) {
return;
}
if (allZonesCardAmountWidget->isNonZero() || underMouse()) {
allZonesCardAmountWidget->setVisible(true);
} else {
@ -387,20 +396,20 @@ void PrintingSelectorCardOverlayWidget::customMenu(QPoint point)
menu.addSeparator();
// filling out the related cards submenu
auto *relatedMenu = new QMenu(tr("Show Related cards"), &menu);
menu.addMenu(relatedMenu);
auto relatedCards = rootCard.getInfo().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->updateCard(CardDatabaseManager::query()->getCard({relatedCardName}));
deckEditor->showPrintingSelector();
});
// Related cards open in the deck editor, which a selection-only host does not have.
if (!host->isSelectionOnly()) {
auto *relatedMenu = new QMenu(tr("Show Related cards"), &menu);
menu.addMenu(relatedMenu);
auto relatedCards = rootCard.getInfo().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, this,
[this, relatedCardName] { host->showRelatedCard(relatedCardName); });
}
}
}
// The preview anchors itself to this popup's global geometry while it is open, so the

View file

@ -14,10 +14,9 @@
class QAction;
class QMenu;
class AbstractTabDeckEditor;
class AllZonesCardAmountWidget;
class CardInfoPictureWidget;
class DeckStateManager;
class PrintingSelectorHost;
class QLabel;
class QPoint;
class QSlider;
@ -28,8 +27,7 @@ class PrintingSelectorCardOverlayWidget : public QWidget
public:
explicit PrintingSelectorCardOverlayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckStateManager *_deckStateManager,
PrintingSelectorHost *_host,
QSlider *_cardSizeSlider,
const ExactCard &_rootCard);
@ -42,6 +40,7 @@ protected:
signals:
void cardPreferenceChanged();
void printingSelected(const ExactCard &card);
public slots:
void updateCardAmounts(int mainboardAmount, int sideboardAmount, int tokensboardAmount);
@ -57,9 +56,9 @@ private:
void refreshPreview();
void hidePreview();
CardInfoPictureWidget *cardInfoPicture;
AllZonesCardAmountWidget *allZonesCardAmountWidget;
AllZonesCardAmountWidget *allZonesCardAmountWidget = nullptr;
QLabel *pinBadge = nullptr;
AbstractTabDeckEditor *deckEditor;
PrintingSelectorHost *host;
ExactCard rootCard;
QLabel *cardOverridePreviewLabel = nullptr;
ExactCard hoveredOverrideCard;

View file

@ -204,7 +204,7 @@ QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPrintingsInDeck(co
const CardInfoPtr &selectedCard,
const DeckListModel *deckModel)
{
if (!selectedCard) {
if (!selectedCard || !deckModel) {
return {};
}

View file

@ -0,0 +1,39 @@
/**
* @file printing_selector_host.h
* @ingroup PrintingWidgets
* @brief Host services a PrintingSelector needs beyond its own widgets.
*/
#ifndef PRINTING_SELECTOR_HOST_H
#define PRINTING_SELECTOR_HOST_H
#include <QString>
class DeckStateManager;
class ExactCard;
/**
* @brief Dependency boundary between PrintingSelector and the surface hosting it.
*
* The deck editor supplies deck data and routes card activations back to its
* info pane. The token dialog uses the selection-only host, which has no deck.
*/
class PrintingSelectorHost
{
public:
virtual ~PrintingSelectorHost() = default;
/** @brief Deck state used for amounts and in-deck ordering, or nullptr when there is no deck. */
[[nodiscard]] virtual DeckStateManager *getDeckStateManager() const = 0;
/** @brief Shows a printing on the host's card info surface. */
virtual void showCard(const ExactCard &card) = 0;
/** @brief Opens a related card through the host. */
virtual void showRelatedCard(const QString &cardName) = 0;
/** @brief True when picking a printing only reports it instead of changing a deck. */
[[nodiscard]] virtual bool isSelectionOnly() const = 0;
};
#endif // PRINTING_SELECTOR_HOST_H

View file

@ -46,6 +46,16 @@ PrintingSelectorPlaceholderWidget::PrintingSelectorPlaceholderWidget(QWidget *pa
retranslateUi();
}
void PrintingSelectorPlaceholderWidget::setText(const QString &text)
{
textLabel->setText(text);
}
void PrintingSelectorPlaceholderWidget::resetText()
{
retranslateUi();
}
void PrintingSelectorPlaceholderWidget::retranslateUi()
{
textLabel->setText(tr("Select a card to view its available printings"));

View file

@ -13,6 +13,8 @@ class PrintingSelectorPlaceholderWidget : public QWidget
public:
explicit PrintingSelectorPlaceholderWidget(QWidget *parent = nullptr);
void setText(const QString &text);
void resetText();
private slots:
void applyInterfaceDefaultFont();

View file

@ -0,0 +1,40 @@
/**
* @file printing_selector_selection_host.h
* @ingroup PrintingWidgets
* @brief A PrintingSelectorHost for hosts that only want the picked printing.
*/
#ifndef PRINTING_SELECTOR_SELECTION_HOST_H
#define PRINTING_SELECTOR_SELECTION_HOST_H
#include "printing_selector_host.h"
/**
* @brief Host for a PrintingSelector used outside a deck editor.
*
* There is no deck: the selector hides its deck-only controls and reports a
* picked printing through its own printingSelected() signal.
*/
class PrintingSelectorSelectionHost final : public PrintingSelectorHost
{
public:
[[nodiscard]] DeckStateManager *getDeckStateManager() const override
{
return nullptr;
}
void showCard(const ExactCard & /*card*/) override
{
}
void showRelatedCard(const QString & /*cardName*/) override
{
}
[[nodiscard]] bool isSelectionOnly() const override
{
return true;
}
};
#endif // PRINTING_SELECTOR_SELECTION_HOST_H