* move message_log_widget to game

* move files

* update headers

* fix cmakelists

* oracle fixes

* split implementation out to cpp

* fix recursive import

* fix main file

* format
This commit is contained in:
ebbit1q 2025-09-20 14:35:52 +02:00 committed by GitHub
parent f484c98152
commit 17dcaf9afa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
337 changed files with 728 additions and 721 deletions

View file

@ -0,0 +1,118 @@
#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.
*/
AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
const ExactCard &rootCard)
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
rootCard(rootCard)
{
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, DECK_ZONE_MAIN);
zoneLabelSideboard = new ShadowBackgroundLabel(this, tr("Sideboard"));
buttonBoxSideboard =
new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard, 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,44 @@
#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 "card_amount_widget.h"
#include <QVBoxLayout>
#include <QWidget>
class AllZonesCardAmountWidget : public QWidget
{
Q_OBJECT
public:
explicit AllZonesCardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
const ExactCard &rootCard);
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;
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
ExactCard rootCard;
QLabel *zoneLabelMainboard;
CardAmountWidget *buttonBoxMainboard;
QLabel *zoneLabelSideboard;
CardAmountWidget *buttonBoxSideboard;
};
#endif // ALL_ZONES_CARD_AMOUNT_WIDGET_H

View file

@ -0,0 +1,300 @@
#include "card_amount_widget.h"
#include <QPainter>
#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 zoneName The zone name (e.g., DECK_ZONE_MAIN or DECK_ZONE_SIDE).
*/
CardAmountWidget::CardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
const ExactCard &rootCard,
const QString &zoneName)
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
rootCard(rootCard), 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)
{
// Add the card and expand the list UI
auto newCardIndex = deckModel->addCard(rootCard, zone);
recursiveExpand(newCardIndex);
// Check if a card without a providerId already exists in the deckModel and replace it, if so.
QModelIndex find_card = deckModel->findCard(rootCard.getName(), zone);
QString foundProviderId = deckModel->data(find_card.sibling(find_card.row(), 4), Qt::DisplayRole).toString();
if (find_card.isValid() && find_card != newCardIndex && foundProviderId == "") {
auto amount = deckModel->data(find_card, Qt::DisplayRole);
for (int i = 0; i < amount.toInt() - 1; i++) {
deckModel->addCard(rootCard, zone);
}
deckModel->removeRow(find_card.row(), find_card.parent());
}
// Set Index and Focus as if the user had just clicked the new card and modify the deckEditor saveState
newCardIndex = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
rootCard.getPrinting().getProperty("num"));
deckView->setCurrentIndex(newCardIndex);
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
deckEditor->setModified(true);
}
/**
* @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, rootCard.getPrinting().getUuid(),
rootCard.getPrinting().getProperty("num"));
offsetCountAtIndex(idx, -1);
deckEditor->setModified(true);
}
/**
* @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 (rootCard.getPrinting().getUuid().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() == rootCard.getPrinting().getProperty("uuid")) {
count++;
}
}
}
}
return count;
}

View file

@ -0,0 +1,63 @@
#ifndef CARD_AMOUNT_WIDGET_H
#define CARD_AMOUNT_WIDGET_H
#include "../../../card/card_info.h"
#include "../../../deck/deck_list_model.h"
#include "../../../deck/deck_loader.h"
#include "../../../tabs/abstract_tab_deck_editor.h"
#include "../general/display/dynamic_font_size_push_button.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTreeView>
#include <QWidget>
class CardAmountWidget : public QWidget
{
Q_OBJECT
public:
explicit CardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
QSlider *cardSizeSlider,
const ExactCard &rootCard,
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:
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
ExactCard rootCard;
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,247 @@
#include "printing_selector.h"
#include "../../../dialogs/dlg_select_set_for_cards.h"
#include "../../../picture_loader/picture_loader.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 <QFrame>
#include <QScrollBar>
#include <qboxlayout.h>
/**
* @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, AbstractTabDeckEditor *_deckEditor)
: QWidget(parent), deckEditor(_deckEditor), deckModel(deckEditor->deckDockWidget->deckModel),
deckView(deckEditor->deckDockWidget->deckView)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout = new QVBoxLayout(this);
setLayout(layout);
widgetLoadingBufferTimer = new QTimer(this);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
sortToolBar = new PrintingSelectorCardSortingWidget(this);
sortToolBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
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().getPrintingSelectorNavigationButtonsVisible());
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
&PrintingSelector::toggleVisibilityNavigationButtons);
connect(navigationCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setPrintingSelectorNavigationButtonsVisible);
cardSizeWidget =
new CardSizeWidget(displayOptionsWidget, flowWidget, SettingsCache::instance().getPrintingSelectorCardSize());
connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
&SettingsCache::setPrintingSelectorCardSize);
displayOptionsWidget->addSettingsWidget(sortToolBar);
displayOptionsWidget->addSettingsWidget(navigationCheckBox);
displayOptionsWidget->addSettingsWidget(cardSizeWidget);
sortAndOptionsContainer = new QWidget(this);
sortAndOptionsLayout = new QHBoxLayout(sortAndOptionsContainer);
sortAndOptionsLayout->setSpacing(3);
sortAndOptionsLayout->setContentsMargins(0, 0, 0, 0);
sortAndOptionsContainer->setLayout(sortAndOptionsLayout);
searchBar = new PrintingSelectorCardSearchWidget(this);
sortAndOptionsLayout->addWidget(searchBar);
sortAndOptionsLayout->addWidget(displayOptionsWidget);
layout->addWidget(sortAndOptionsContainer);
layout->addWidget(flowWidget);
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this);
cardSelectionBar->setVisible(SettingsCache::instance().getPrintingSelectorNavigationButtonsVisible());
layout->addWidget(cardSelectionBar);
// Connect deck model data change signal to update display
connect(deckModel, &DeckListModel::rowsInserted, this, &PrintingSelector::printingsInDeckChanged);
connect(deckModel, &DeckListModel::rowsRemoved, this, &PrintingSelector::printingsInDeckChanged);
retranslateUi();
}
void PrintingSelector::retranslateUi()
{
navigationCheckBox->setText(tr("Display Navigation Buttons"));
}
void PrintingSelector::printingsInDeckChanged()
{
// 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;
}
// we don't need to redraw the widget if the card is the same
if (!selectedCard.isNull() && selectedCard->getName() == newCard->getName()) {
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;
}
SetToPrintingsMap setMap = selectedCard->getSets();
const QList<PrintingInfo> sortedPrintings = sortToolBar->sortSets(setMap);
const QList<PrintingInfo> filteredPrintings =
sortToolBar->filterSets(sortedPrintings, searchBar->getSearchText().trimmed().toLower());
QList<PrintingInfo> printingsToUse;
if (SettingsCache::instance().getBumpSetsWithCardsInDeckToTop()) {
printingsToUse = sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckModel);
} else {
printingsToUse = filteredPrintings;
}
printingsToUse = sortToolBar->prependPinnedPrintings(printingsToUse, selectedCard->getName());
// Defer widget creation
currentIndex = 0;
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) {
ExactCard card = ExactCard(selectedCard, printingsToUse[currentIndex]);
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(
this, deckEditor, deckModel, deckView, cardSizeWidget->getSlider(), card, currentZone);
flowWidget->addWidget(cardDisplayWidget);
cardDisplayWidget->clampSetNameToPicture();
connect(cardDisplayWidget, &PrintingSelectorCardDisplayWidget::cardPreferenceChanged, this,
&PrintingSelector::updateDisplay);
}
// Stop timer when done
if (currentIndex >= printingsToUse.size()) {
widgetLoadingBufferTimer->stop();
}
});
currentIndex = 0;
widgetLoadingBufferTimer->start(0); // Process as soon as possible
}
/**
* @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,69 @@
#ifndef PRINTING_SELECTOR_H
#define PRINTING_SELECTOR_H
#include "../../../card/card_info.h"
#include "../../../deck/deck_list_model.h"
#include "../cards/card_size_widget.h"
#include "../general/layout_containers/flow_widget.h"
#include "../quick_settings/settings_button_widget.h"
#include <QCheckBox>
#include <QLabel>
#include <QPushButton>
#include <QTreeView>
#include <QVBoxLayout>
#include <QWidget>
#define BATCH_SIZE 10
class PrintingSelectorCardSearchWidget;
class PrintingSelectorCardSelectionWidget;
class PrintingSelectorCardSortingWidget;
class PrintingSelectorViewOptionsWidget;
class AbstractTabDeckEditor;
class PrintingSelector : public QWidget
{
Q_OBJECT
public:
PrintingSelector(QWidget *parent, AbstractTabDeckEditor *deckEditor);
void setCard(const CardInfoPtr &newCard, const QString &_currentZone);
void getAllSetsForCurrentCard();
DeckListModel *getDeckModel() const
{
return deckModel;
};
public slots:
void retranslateUi();
void updateDisplay();
void selectPreviousCard();
void selectNextCard();
void toggleVisibilityNavigationButtons(bool _state);
private slots:
void printingsInDeckChanged();
private:
QVBoxLayout *layout;
SettingsButtonWidget *displayOptionsWidget;
QWidget *sortAndOptionsContainer;
QHBoxLayout *sortAndOptionsLayout;
QCheckBox *navigationCheckBox;
PrintingSelectorCardSortingWidget *sortToolBar;
PrintingSelectorCardSearchWidget *searchBar;
FlowWidget *flowWidget;
CardSizeWidget *cardSizeWidget;
PrintingSelectorCardSelectionWidget *cardSelectionBar;
AbstractTabDeckEditor *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 _currentZone The current zone in which the card is located.
*/
PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
const ExactCard &_rootCard,
QString &_currentZone)
: QWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), deckView(_deckView),
cardSizeSlider(_cardSizeSlider), rootCard(_rootCard), 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);
connect(overlayWidget, &PrintingSelectorCardOverlayWidget::cardPreferenceChanged, this,
[this]() { emit cardPreferenceChanged(); });
CardSetPtr set = rootCard.getPrinting().getSet();
// Create the widget to display the set name and collector's number
QString combinedSetName = QString(set->getLongName() + " (" + set->getShortName() + ")");
setNameAndCollectorsNumberDisplayWidget = new SetNameAndCollectorsNumberDisplayWidget(
this, combinedSetName, rootCard.getPrinting().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,44 @@
#ifndef PRINTING_SELECTOR_CARD_DISPLAY_WIDGET_H
#define PRINTING_SELECTOR_CARD_DISPLAY_WIDGET_H
#include "../../../card/card_info.h"
#include "../../../deck/deck_list_model.h"
#include "../../../tabs/abstract_tab_deck_editor.h"
#include "printing_selector_card_overlay_widget.h"
#include "set_name_and_collectors_number_display_widget.h"
#include <QPainter>
#include <QWidget>
class PrintingSelectorCardDisplayWidget : public QWidget
{
Q_OBJECT
public:
PrintingSelectorCardDisplayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
const ExactCard &_rootCard,
QString &_currentZone);
public slots:
void clampSetNameToPicture();
signals:
void cardPreferenceChanged();
private:
QVBoxLayout *layout;
SetNameAndCollectorsNumberDisplayWidget *setNameAndCollectorsNumberDisplayWidget;
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
ExactCard rootCard;
QString currentZone;
PrintingSelectorCardOverlayWidget *overlayWidget;
};
#endif // PRINTING_SELECTOR_CARD_DISPLAY_WIDGET_H

View file

@ -0,0 +1,205 @@
#include "printing_selector_card_overlay_widget.h"
#include "../../../database/card_database_manager.h"
#include "../../../settings/cache_settings.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.
*/
PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
const ExactCard &_rootCard)
: QWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), deckView(_deckView),
cardSizeSlider(_cardSizeSlider), rootCard(_rootCard)
{
// 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());
cardInfoPicture->setCard(_rootCard);
mainLayout->addWidget(cardInfoPicture);
// Add AllZonesCardAmountWidget
allZonesCardAmountWidget =
new AllZonesCardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, _rootCard);
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->updateCard(rootCard);
// 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;
auto *preferenceMenu = new QMenu(tr("Preference"));
menu.addMenu(preferenceMenu);
const auto &preferredProviderId =
SettingsCache::instance().cardOverrides().getCardPreferenceOverride(rootCard.getName());
const auto &cardProviderId = rootCard.getPrinting().getUuid();
if (preferredProviderId.isEmpty() || preferredProviderId != cardProviderId) {
auto *pinAction = preferenceMenu->addAction(tr("Pin Printing"));
connect(pinAction, &QAction::triggered, this, [this] {
SettingsCache::instance().cardOverrides().setCardPreferenceOverride(
{rootCard.getName(), rootCard.getPrinting().getUuid()});
emit cardPreferenceChanged();
});
} else {
auto *unpinAction = preferenceMenu->addAction(tr("Unpin Printing"));
connect(unpinAction, &QAction::triggered, this, [this] {
SettingsCache::instance().cardOverrides().deleteCardPreferenceOverride(rootCard.getName());
emit cardPreferenceChanged();
});
}
// filling out the related cards submenu
auto *relatedMenu = new QMenu(tr("Show Related cards"));
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::getInstance()->getCard({relatedCardName}));
deckEditor->showPrintingSelector();
});
}
}
menu.exec(this->mapToGlobal(point));
}

View file

@ -0,0 +1,48 @@
#ifndef PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H
#define PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H
#include "../../../card/card_info.h"
#include "../../../deck/deck_list_model.h"
#include "../../../tabs/abstract_tab_deck_editor.h"
#include "../cards/card_info_picture_widget.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,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
QSlider *_cardSizeSlider,
const ExactCard &_rootCard);
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);
signals:
void cardPreferenceChanged();
private:
CardInfoPictureWidget *cardInfoPicture;
AllZonesCardAmountWidget *allZonesCardAmountWidget;
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
QSlider *cardSizeSlider;
ExactCard rootCard;
};
#endif // PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H

View file

@ -0,0 +1,39 @@
#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);
layout->setContentsMargins(9, 0, 9, 0);
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,54 @@
#include "printing_selector_card_selection_widget.h"
#include "../../../dialogs/dlg_select_set_for_cards.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);
cardSelectionBarLayout->setContentsMargins(9, 0, 9, 0);
previousCardButton = new QPushButton(this);
previousCardButton->setText(tr("Previous Card in Deck"));
selectSetForCardsButton = new QPushButton(this);
connect(selectSetForCardsButton, &QPushButton::clicked, this,
&PrintingSelectorCardSelectionWidget::selectSetForCards);
selectSetForCardsButton->setText(tr("Bulk Selection"));
nextCardButton = new QPushButton(this);
nextCardButton->setText(tr("Next Card in Deck"));
connectSignals();
cardSelectionBarLayout->addWidget(previousCardButton);
cardSelectionBarLayout->addWidget(selectSetForCardsButton);
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);
}
void PrintingSelectorCardSelectionWidget::selectSetForCards()
{
DlgSelectSetForCards *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel());
if (!setSelectionDialog->exec()) {
return;
}
}

View file

@ -0,0 +1,30 @@
#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();
public slots:
void selectSetForCards();
private:
PrintingSelector *parent;
QHBoxLayout *cardSelectionBarLayout;
QPushButton *previousCardButton;
QPushButton *selectSetForCardsButton;
QPushButton *nextCardButton;
};
#endif // PRINTING_SELECTOR_CARD_SELECTION_WIDGET_H

View file

@ -0,0 +1,230 @@
#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)
{
setMinimumWidth(300);
sortToolBar = new QHBoxLayout(this);
sortOptionsSelector = new QComboBox(this);
sortOptionsSelector->setFocusPolicy(Qt::StrongFocus);
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 setMap The list of card sets to be sorted.
* @return A sorted list of printings.
*/
QList<PrintingInfo> PrintingSelectorCardSortingWidget::sortSets(const SetToPrintingsMap &setMap)
{
QList<CardSetPtr> sortedSets;
for (const auto &printingInfos : setMap) {
for (const auto &set : printingInfos) {
sortedSets << set.getSet();
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<PrintingInfo> sortedPrintings;
// Reconstruct sorted list of PrintingInfo
for (const auto &set : sortedSets) {
for (auto it = setMap.begin(); it != setMap.end(); ++it) {
for (const auto &printingInfo : it.value()) {
if (printingInfo.getSet() == set) {
if (!sortedPrintings.contains(printingInfo)) {
sortedPrintings << printingInfo;
}
}
}
}
}
if (descendingSort) {
std::reverse(sortedPrintings.begin(), sortedPrintings.end());
}
return sortedPrintings;
}
/**
* @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 printings The list of printings to be filtered.
* @param searchText The search text used to filter the card sets.
* @return A filtered list of card sets.
*/
QList<PrintingInfo> PrintingSelectorCardSortingWidget::filterSets(const QList<PrintingInfo> &printings,
const QString &searchText)
{
if (searchText.isEmpty()) {
return printings;
}
QList<PrintingInfo> filteredPrintings;
for (const auto &printing : printings) {
const QString longName = printing.getSet()->getLongName().toLower();
const QString shortName = printing.getSet()->getShortName().toLower();
if (longName.contains(searchText) || shortName.contains(searchText)) {
filteredPrintings << printing;
}
}
return filteredPrintings;
}
QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPinnedPrintings(const QList<PrintingInfo> &printings,
const QString &cardName)
{
auto printingsToUse = printings;
const auto &cardProviderId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName);
if (!cardProviderId.isEmpty()) {
for (int i = 0; i < printingsToUse.size(); ++i) {
const auto &card = printingsToUse[i];
if (card.getUuid() == cardProviderId) {
printingsToUse.move(i, 0);
break;
}
}
}
return printingsToUse;
}
/**
* @brief Prepend card printings that are contained in the deck to the list of printings.
*
* This function adjusts the list of printings 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 printings The original list of printings.
* @param selectedCard The currently selected card.
* @param deckModel The model representing the deck.
* @return A list of printings with the printings contained in the deck prepended.
*/
QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPrintingsInDeck(const QList<PrintingInfo> &printings,
const CardInfoPtr &selectedCard,
DeckListModel *deckModel)
{
if (!selectedCard) {
return {};
}
SetToPrintingsMap setMap = selectedCard->getSets();
QList<QPair<PrintingInfo, int>> countList;
// Collect sets with their counts
for (const auto &printingList : setMap) {
for (const auto &printing : printingList) {
QModelIndex find_card =
deckModel->findCard(selectedCard->getName(), DECK_ZONE_MAIN, printing.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(printing, count));
}
}
break;
}
}
// Sort sets by count in descending numerical order
std::sort(countList.begin(), countList.end(),
[](const QPair<PrintingInfo, int> &a, const QPair<PrintingInfo, int> &b) {
return a.second > b.second; // Ensure numerical comparison
});
// Create a copy of the original list to modify
QList<PrintingInfo> result = printings;
// 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 PrintingInfo &item) { return item.getUuid() == pair.first.getUuid(); });
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,40 @@
#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<PrintingInfo> sortSets(const SetToPrintingsMap &setMap);
QList<PrintingInfo> filterSets(const QList<PrintingInfo> &printings, const QString &searchText);
QList<PrintingInfo> prependPinnedPrintings(const QList<PrintingInfo> &printings, const QString &cardName);
QList<PrintingInfo> prependPrintingsInDeck(const QList<PrintingInfo> &printings,
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,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