More performant display updating.

This commit is contained in:
Lukas Brübach 2025-03-01 21:31:31 +01:00
parent 268d3f2e6b
commit d60b613fd5
12 changed files with 320 additions and 245 deletions

View file

@ -65,10 +65,8 @@ void TabDeckEditorVisual::createCentralFrame()
&TabDeckEditorVisual::changeModelIndexAndCardInfo);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChangedDatabaseDisplay, this,
&AbstractTabDeckEditor::updateCard);
connect(tabContainer, &TabDeckEditorVisualTabWidget::mainboardCardClicked, this,
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClicked, this,
&TabDeckEditorVisual::processMainboardCardClick);
connect(tabContainer, &TabDeckEditorVisualTabWidget::sideboardCardClicked, this,
&TabDeckEditorVisual::processSideboardCardClick);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClickedDatabaseDisplay, this,
&TabDeckEditorVisual::processCardClickDatabaseDisplay);
@ -161,10 +159,12 @@ void TabDeckEditorVisual::changeModelIndexToCard(const CardInfoPtr &activeCard)
deckDockWidget->deckView->setCurrentIndex(index);
}
void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
QString zoneName)
{
if (event->button() == Qt::LeftButton) {
actSwapCard(instance->getInfo(), DECK_ZONE_MAIN);
actSwapCard(instance->getInfo(), zoneName);
} else if (event->button() == Qt::RightButton) {
actDecrementCard(instance->getInfo());
} else if (event->button() == Qt::MiddleButton) {
@ -172,17 +172,6 @@ void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event, CardInfo
}
}
void TabDeckEditorVisual::processSideboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
{
if (event->button() == Qt::LeftButton) {
actSwapCard(instance->getInfo(), DECK_ZONE_SIDE);
} else if (event->button() == Qt::RightButton) {
actDecrementCardFromSideboard(instance->getInfo());
} else if (event->button() == Qt::MiddleButton) {
deckDockWidget->actRemoveCard();
}
}
void TabDeckEditorVisual::processCardClickDatabaseDisplay(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
{

View file

@ -44,8 +44,8 @@ public:
public slots:
void onDeckChanged() override;
void showPrintingSelector() override;
void processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void processSideboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void
processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
};

View file

@ -20,13 +20,10 @@ TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
visualDeckView = new VisualDeckEditorWidget(this, deckModel);
visualDeckView->setObjectName("visualDeckView");
visualDeckView->updateDisplay();
connect(visualDeckView, &VisualDeckEditorWidget::activeCardChanged, this,
&TabDeckEditorVisualTabWidget::onCardChanged);
connect(visualDeckView, &VisualDeckEditorWidget::mainboardCardClicked, this,
&TabDeckEditorVisualTabWidget::onMainboardCardClickedDeckEditor);
connect(visualDeckView, &VisualDeckEditorWidget::sideboardCardClicked, this,
&TabDeckEditorVisualTabWidget::onSideboardCardClickedDeckEditor);
connect(visualDeckView, &VisualDeckEditorWidget::cardClicked, this,
&TabDeckEditorVisualTabWidget::onCardClickedDeckEditor);
visualDatabaseDisplay =
new VisualDatabaseDisplayWidget(this, deckEditor, cardDatabaseModel, cardDatabaseDisplayModel);
@ -57,16 +54,11 @@ void TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay(CardInfoPtr acti
emit cardChangedDatabaseDisplay(activeCard);
}
void TabDeckEditorVisualTabWidget::onMainboardCardClickedDeckEditor(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
void TabDeckEditorVisualTabWidget::onCardClickedDeckEditor(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
QString zoneName)
{
emit mainboardCardClicked(event, instance);
}
void TabDeckEditorVisualTabWidget::onSideboardCardClickedDeckEditor(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
{
emit sideboardCardClicked(event, instance);
emit cardClicked(event, instance, zoneName);
}
void TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay(QMouseEvent *event,

View file

@ -39,15 +39,13 @@ public:
public slots:
void onCardChanged(CardInfoPtr activeCard);
void onCardChangedDatabaseDisplay(CardInfoPtr activeCard);
void onMainboardCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void onSideboardCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void onCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
signals:
void cardChanged(CardInfoPtr activeCard);
void cardChangedDatabaseDisplay(CardInfoPtr activeCard);
void mainboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void sideboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
private:

View file

@ -1,23 +1,33 @@
#include "deck_card_zone_display_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../../../../utility/card_info_comparator.h"
#include "overlapped_card_group_display_widget.h"
#include <QResizeEvent>
DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
QList<QPair<QString, QList<CardInfoPtr>>> cardLists,
QString bannerText,
DeckListModel *_deckListModel,
QString _zoneName,
QString _activeSortCriteria,
int bannerOpacity,
int subBannerOpacity)
: QWidget(parent), cardLists(cardLists), bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity)
: QWidget(parent), deckListModel(_deckListModel), zoneName(_zoneName), activeSortCriteria(_activeSortCriteria),
bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity)
{
layout = new QVBoxLayout(this);
setLayout(layout);
banner = new BannerWidget(this, bannerText, Qt::Orientation::Vertical, bannerOpacity);
banner = new BannerWidget(this, zoneName, Qt::Orientation::Vertical, bannerOpacity);
layout->addWidget(banner);
cardGroupContainer = new QWidget(this);
cardGroupLayout = new QVBoxLayout(cardGroupContainer);
cardGroupContainer->setLayout(cardGroupLayout);
layout->addWidget(cardGroupContainer);
displayCards();
connect(deckListModel, &DeckListModel::dataChanged, this, &DeckCardZoneDisplayWidget::displayCards);
}
void DeckCardZoneDisplayWidget::resizeEvent(QResizeEvent *event)
{
@ -31,7 +41,7 @@ void DeckCardZoneDisplayWidget::resizeEvent(QResizeEvent *event)
}
void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
{
emit cardClicked(event, card);
emit cardClicked(event, card, zoneName);
}
void DeckCardZoneDisplayWidget::onHover(CardInfoPtr card)
{
@ -40,15 +50,70 @@ void DeckCardZoneDisplayWidget::onHover(CardInfoPtr card)
void DeckCardZoneDisplayWidget::displayCards()
{
for (QPair<QString, QList<CardInfoPtr>> &pair : cardLists) {
QString criteriaValue = pair.first;
QList<CardInfoPtr> cardList = pair.second;
addCardGroupIfItDoesNotExist();
deleteCardGroupIfItDoesNotExist();
}
OverlappedCardGroupDisplayWidget *display_widget =
new OverlappedCardGroupDisplayWidget(this, &cardList, criteriaValue, subBannerOpacity);
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
layout->addWidget(display_widget);
void DeckCardZoneDisplayWidget::addCardGroupIfItDoesNotExist()
{
QList<OverlappedCardGroupDisplayWidget *> cardGroupsDisplayWidgets =
cardGroupContainer->findChildren<OverlappedCardGroupDisplayWidget *>();
QList<QString> cardGroups = getSortCriteriaValueList();
for (QString cardGroup : cardGroups) {
bool found = false;
for (OverlappedCardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
if (cardGroupDisplayWidget->cardGroupCategory == cardGroup) {
found = true;
}
}
if (!found) {
OverlappedCardGroupDisplayWidget *display_widget = new OverlappedCardGroupDisplayWidget(
this, deckListModel, zoneName, cardGroup, activeSortCriteria, subBannerOpacity);
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
cardGroupLayout->addWidget(display_widget);
}
}
}
}
void DeckCardZoneDisplayWidget::deleteCardGroupIfItDoesNotExist()
{
QList<OverlappedCardGroupDisplayWidget *> cardGroupsDisplayWidgets =
cardGroupLayout->findChildren<OverlappedCardGroupDisplayWidget *>();
for (OverlappedCardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
bool found = false;
for (QString cardGroup : getSortCriteriaValueList()) {
if (cardGroupDisplayWidget->cardGroupCategory == cardGroup) {
found = true;
}
}
if (!found) {
cardGroupLayout->removeWidget(cardGroupDisplayWidget);
}
}
}
void DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged(QString _activeSortCriteria)
{
activeSortCriteria = _activeSortCriteria;
}
QList<QString> DeckCardZoneDisplayWidget::getSortCriteriaValueList()
{
QList<QString> sortCriteriaValues;
QList<CardInfoPtr> *cardsInZone = deckListModel->getCardsAsCardInfoPtrsForZone(zoneName);
for (CardInfoPtr cardInZone : *cardsInZone) {
sortCriteriaValues.append(cardInZone->getProperty(activeSortCriteria));
}
sortCriteriaValues.removeDuplicates();
sortCriteriaValues.sort();
return sortCriteriaValues;
}

View file

@ -1,6 +1,7 @@
#ifndef DECK_CARD_ZONE_DISPLAY_WIDGET_H
#define DECK_CARD_ZONE_DISPLAY_WIDGET_H
#include "../../../../deck/deck_list_model.h"
#include "../../../../game/cards/card_database.h"
#include "../general/display/banner_widget.h"
#include "../general/layout_containers/overlap_widget.h"
@ -15,10 +16,13 @@ class DeckCardZoneDisplayWidget : public QWidget
public:
DeckCardZoneDisplayWidget(QWidget *parent,
QList<QPair<QString, QList<CardInfoPtr>>> cardLists,
QString bannerText,
DeckListModel *deckListModel,
QString zoneName,
QString activeSortCriteria,
int bannerOpacity,
int subBannerOpacity);
DeckListModel *deckListModel;
QString zoneName;
void addCardsToOverlapWidget();
void resizeEvent(QResizeEvent *event) override;
@ -26,15 +30,21 @@ public slots:
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void onHover(CardInfoPtr card);
void displayCards();
void addCardGroupIfItDoesNotExist();
void deleteCardGroupIfItDoesNotExist();
void onActiveSortCriteriaChanged(QString activeSortCriteria);
QList<QString> getSortCriteriaValueList();
signals:
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card, QString zoneName);
void cardHovered(CardInfoPtr card);
private:
QList<QPair<QString, QList<CardInfoPtr>>> cardLists;
QString activeSortCriteria;
QVBoxLayout *layout;
BannerWidget *banner;
QWidget *cardGroupContainer;
QVBoxLayout *cardGroupLayout;
int bannerOpacity = 20;
int subBannerOpacity = 10;
OverlapWidget *overlapWidget;

View file

@ -1,45 +1,119 @@
#include "overlapped_card_group_display_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../../../../game/cards/card_database_manager.h"
#include "../../../../utility/card_info_comparator.h"
#include "card_info_picture_with_text_overlay_widget.h"
#include <QResizeEvent>
OverlappedCardGroupDisplayWidget::OverlappedCardGroupDisplayWidget(QWidget *parent,
QList<CardInfoPtr> *cards,
QString bannerText,
DeckListModel *_deckListModel,
QString _zoneName,
QString _cardGroupCategory,
QString _activeSortCriteria,
int bannerOpacity)
: QWidget(parent), cardsToDisplay(cards)
: QWidget(parent), deckListModel(_deckListModel), zoneName(_zoneName), cardGroupCategory(_cardGroupCategory),
activeSortCriteria(_activeSortCriteria)
{
layout = new QVBoxLayout(this);
setLayout(layout);
setMinimumSize(QSize(0, 0));
banner = new BannerWidget(this, bannerText, Qt::Orientation::Vertical, bannerOpacity);
banner = new BannerWidget(this, cardGroupCategory, Qt::Orientation::Vertical, bannerOpacity);
overlapWidget = new OverlapWidget(this, 80, 1, 1, Qt::Vertical, true);
layout->addWidget(banner);
layout->addWidget(overlapWidget);
addCardsToOverlapWidget();
updateCardDisplays();
connect(deckListModel, &DeckListModel::dataChanged, this, &OverlappedCardGroupDisplayWidget::updateCardDisplays);
}
void OverlappedCardGroupDisplayWidget::addCardsToOverlapWidget()
void OverlappedCardGroupDisplayWidget::updateCardDisplays()
{
for (int i = 0; i < cardsToDisplay->size(); i++) {
CardInfoPtr card = cardsToDisplay->at(i);
if (card) {
CardInfoPictureWithTextOverlayWidget *display =
new CardInfoPictureWithTextOverlayWidget(overlapWidget, true);
display->setCard(card);
QList<CardInfoPtr> cardsInZone = getCardsMatchingGroup(deckListModel->getCardsAsCardInfoPtrsForZone(zoneName));
QList<CardInfoPictureWithTextOverlayWidget *> existingWidgets =
overlapWidget->findChildren<CardInfoPictureWithTextOverlayWidget *>();
QHash<QString, int> requiredCounts;
for (const CardInfoPtr &card : cardsInZone) {
requiredCounts[card->getName()]++;
}
QHash<QString, QList<CardInfoPictureWithTextOverlayWidget *>> widgetMap;
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
widgetMap[widget->getInfo()->getName()].append(widget);
}
for (auto it = widgetMap.begin(); it != widgetMap.end(); ++it) {
QString name = it.key();
QList<CardInfoPictureWithTextOverlayWidget *> &widgets = it.value();
int neededCount = requiredCounts.value(name, 0);
while (widgets.size() > neededCount) {
CardInfoPictureWithTextOverlayWidget *widgetToRemove = widgets.takeLast();
overlapWidget->removeWidget(widgetToRemove);
delete widgetToRemove;
}
}
for (auto it = requiredCounts.begin(); it != requiredCounts.end(); ++it) {
QString name = it.key();
int missingCount = it.value() - widgetMap[name].size();
for (int i = 0; i < missingCount; ++i) {
auto *display = new CardInfoPictureWithTextOverlayWidget(overlapWidget, true);
auto cardIt = std::find_if(cardsInZone.begin(), cardsInZone.end(),
[&](const CardInfoPtr &c) { return c->getName() == name; });
if (cardIt != cardsInZone.end()) {
display->setCard(*cardIt);
}
connect(display, &CardInfoPictureWithTextOverlayWidget::imageClicked, this,
&OverlappedCardGroupDisplayWidget::onClick);
connect(display, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this,
&OverlappedCardGroupDisplayWidget::onHover);
connect(display, SIGNAL(imageClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
connect(display, SIGNAL(hoveredOnCard(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
overlapWidget->addWidget(display);
}
}
overlapWidget->adjustMaxColumnsAndRows();
}
QList<CardInfoPtr> OverlappedCardGroupDisplayWidget::getCardsMatchingGroup(QList<CardInfoPtr> *cardsToSort)
{
QList<CardInfoPtr> activeList;
QStringList sortCriteria;
sortCriteria.append(activeSortCriteria);
sortCardList(cardsToSort, sortCriteria, Qt::SortOrder::AscendingOrder);
for (int i = 0; i < cardsToSort->size(); ++i) {
CardInfoPtr info = cardsToSort->at(i);
if (info) {
if (info->getProperty(activeSortCriteria) == cardGroupCategory) {
activeList.append(info);
}
} else {
qDebug() << "Card not found in database!";
}
}
return activeList;
}
void OverlappedCardGroupDisplayWidget::sortCardList(QList<CardInfoPtr> *cardsToSort,
const QStringList properties,
Qt::SortOrder order = Qt::AscendingOrder)
{
CardInfoComparator comparator(properties, order);
std::sort(cardsToSort->begin(), cardsToSort->end(), comparator);
}
void OverlappedCardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
{
emit cardClicked(event, card);

View file

@ -1,6 +1,7 @@
#ifndef OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
#define OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
#include "../../../../deck/deck_list_model.h"
#include "../../../../game/cards/card_database.h"
#include "../general/display/banner_widget.h"
#include "../general/layout_containers/overlap_widget.h"
@ -15,20 +16,32 @@ class OverlappedCardGroupDisplayWidget : public QWidget
Q_OBJECT
public:
OverlappedCardGroupDisplayWidget(QWidget *parent, QList<CardInfoPtr> *cards, QString bannerText, int bannerOpacity);
void addCardsToOverlapWidget();
OverlappedCardGroupDisplayWidget(QWidget *parent,
DeckListModel *deckListModel,
QString zoneName,
QString cardGroupCategory,
QString activeSortCriteria,
int bannerOpacity);
QList<CardInfoPtr> getCardsMatchingGroup(QList<CardInfoPtr> *cardsToSort);
void resizeEvent(QResizeEvent *event) override;
DeckListModel *deckListModel;
QString zoneName;
QString cardGroupCategory;
QString activeSortCriteria;
public slots:
void sortCardList(QList<CardInfoPtr> *cardsToSort, QStringList properties, Qt::SortOrder order);
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void onHover(CardInfoPtr card);
void updateCardDisplays();
signals:
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void cardHovered(CardInfoPtr card);
private:
QList<CardInfoPtr> *cardsToDisplay;
QVBoxLayout *layout;
BannerWidget *banner;
OverlapWidget *overlapWidget;

View file

@ -100,41 +100,26 @@ QHash<QString, int> ManaBaseWidget::analyzeManaBase()
QHash<QString, int> ManaBaseWidget::determineManaProduction(const QString &rulesText)
{
// Initialize mana counts
QHash<QString, int> manaCounts;
manaCounts.insert("W", 0);
manaCounts.insert("U", 0);
manaCounts.insert("B", 0);
manaCounts.insert("R", 0);
manaCounts.insert("G", 0);
manaCounts.insert("C", 0);
QHash<QString, int> manaCounts = {{"W", 0}, {"U", 0}, {"B", 0}, {"R", 0}, {"G", 0}, {"C", 0}};
// Define regex patterns for different mana production rules
QRegularExpression tapAddColorless(R"(\{T\}:\s*Add\s*\{C\}|Add\s*one\s*colorless\s*mana)");
QRegularExpression tapAddAnyColor(
R"(\{T\}:\s*Add\s*one\s*mana\s*of\s*any\s*color|Add\s*one\s*mana\s*of\s*any\s*color)");
QRegularExpression tapAddSpecificColor(
R"(\{T\}:\s*Add\s*\{(W|U|B|R|G)\}|Add\s*one\s*(white|blue|black|red|green)\s*mana)");
QString text = rulesText.toLower(); // Normalize case for matching
// Check for mana production rules in the text
if (tapAddColorless.match(rulesText).hasMatch()) {
manaCounts["C"] += 1; // Adds colorless mana
// Quick keyword-based checks for any color and colorless mana
if (text.contains("{t}: add one mana of any color") || text.contains("add one mana of any color")) {
for (const auto &color : {QStringLiteral("W"), QStringLiteral("U"), QStringLiteral("B"), QStringLiteral("R"),
QStringLiteral("G")}) {
manaCounts[color]++;
}
}
if (text.contains("{t}: add {c}") || text.contains("add one colorless mana")) {
manaCounts["C"]++;
}
if (tapAddAnyColor.match(rulesText).hasMatch()) {
manaCounts["W"] += 1; // Assumes at least 1 of any color can be produced
manaCounts["U"] += 1;
manaCounts["B"] += 1;
manaCounts["R"] += 1;
manaCounts["G"] += 1;
}
// Check for specific color production
QRegularExpression specificColorRegex(R"(\{T\}:\s*Add\s*\{(W|U|B|R|G)\})");
auto match = specificColorRegex.match(rulesText);
// Optimized regex for specific mana symbols
static const QRegularExpression specificColorRegex(R"(\{T\}:\s*Add\s*\{([WUBRG])\})");
QRegularExpressionMatch match = specificColorRegex.match(rulesText);
if (match.hasMatch()) {
QString color = match.captured(1);
manaCounts[color] += 1;
manaCounts[match.captured(1)]++;
}
return manaCounts;

View file

@ -99,38 +99,29 @@ void ManaDevotionWidget::updateDisplay()
// Function to count mana symbols W, U, B, R, G in the input string
std::unordered_map<char, int> ManaDevotionWidget::countManaSymbols(const QString &manaString)
{
// Only track counts for W, U, B, R, G
std::unordered_map<char, int> manaCounts = {{'W', 0}, {'U', 0}, {'B', 0}, {'R', 0}, {'G', 0}};
// Convert QString to std::string for regex processing
std::string stdManaString = manaString.toStdString();
std::regex regexPattern(R"(\{([WUBRG])\/([WUBRG])\})");
std::string::const_iterator searchStart(stdManaString.cbegin());
std::smatch match;
// Go through the string and find pairs within {}/ for W, U, B, R, G
while (std::regex_search(searchStart, stdManaString.cend(), match, regexPattern)) {
char mana1 = match[1].str()[0];
char mana2 = match[2].str()[0];
// Increment the count for both mana symbols
manaCounts[mana1]++;
manaCounts[mana2]++;
// Move past the current match
searchStart = match.suffix().first;
}
// Now go through the string again but ignore the {}/ parts and non-WUBRG symbols
for (int i = 0; i < manaString.size(); ++i) {
int len = manaString.length();
for (int i = 0; i < len; ++i) {
if (manaString[i] == '{') {
// Skip over the {X/Y} pattern
while (manaString[i] != '}' && i < manaString.size()) {
++i;
++i; // Move past '{'
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
char mana1 = manaString[i].toLatin1();
++i; // Move to next character
if (i < len && manaString[i] == '/') {
++i; // Move past '/'
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
char mana2 = manaString[i].toLatin1();
manaCounts[mana1]++;
manaCounts[mana2]++;
}
} else {
manaCounts[mana1]++;
}
}
while (i < len && manaString[i] != '}') {
++i; // Skip to closing '}'
}
} else if (manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
// If it's one of W, U, B, R, G, count it
manaCounts[manaString[i].toLatin1()]++;
}
}

View file

@ -19,8 +19,6 @@
VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_deckListModel)
: QWidget(parent), deckListModel(_deckListModel)
{
this->mainDeckCards = new QList<CardInfoPtr>;
this->sideboardCards = new QList<CardInfoPtr>;
connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorWidget::decklistDataChanged);
// The Main Widget and Main Layout, which contain a single Widget: The Scroll Area
@ -36,7 +34,9 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_
<< "cmc"
<< "name";
sortByComboBox->addItems(sortProperties);
connect(sortByComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(activeSortCriteriaChanged()));
connect(sortByComboBox, &QComboBox::currentIndexChanged, this,
&VisualDeckEditorWidget::actChangeActiveSortCriteria);
actChangeActiveSortCriteria();
scrollArea = new QScrollArea();
scrollArea->setWidgetResizable(true);
@ -52,13 +52,63 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_
scrollArea->addScrollBarWidget(zoneContainer, Qt::AlignHCenter);
scrollArea->setWidget(zoneContainer);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
updateZoneWidgets();
overlap_control_widget = new OverlapControlWidget(80, 1, 1, Qt::Vertical, this);
overlapControlWidget = new OverlapControlWidget(80, 1, 1, Qt::Vertical, this);
mainLayout->addWidget(sortByComboBox);
mainLayout->addWidget(scrollArea);
mainLayout->addWidget(overlap_control_widget);
mainLayout->addWidget(overlapControlWidget);
}
void VisualDeckEditorWidget::updateZoneWidgets()
{
addZoneIfDoesNotExist();
deleteZoneIfDoesNotExist();
}
void VisualDeckEditorWidget::addZoneIfDoesNotExist()
{
QList<DeckCardZoneDisplayWidget *> cardZoneDisplayWidgets =
zoneContainer->findChildren<DeckCardZoneDisplayWidget *>();
for (const QString &zone : *deckListModel->getZones()) {
bool found = false;
for (DeckCardZoneDisplayWidget *displayWidget : cardZoneDisplayWidgets) {
if (displayWidget->zoneName == zone) {
found = true;
}
}
if (!found) {
DeckCardZoneDisplayWidget *zoneDisplayWidget =
new DeckCardZoneDisplayWidget(zoneContainer, deckListModel, zone, activeSortCriteria, 20, 10);
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardHovered, this, &VisualDeckEditorWidget::onHover);
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardClicked, this,
&VisualDeckEditorWidget::onCardClick);
connect(this, &VisualDeckEditorWidget::activeSortCriteriaChanged, zoneDisplayWidget,
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
zoneContainerLayout->addWidget(zoneDisplayWidget);
}
}
}
void VisualDeckEditorWidget::deleteZoneIfDoesNotExist()
{
QList<DeckCardZoneDisplayWidget *> cardZoneDisplayWidgets =
zoneContainer->findChildren<DeckCardZoneDisplayWidget *>();
for (DeckCardZoneDisplayWidget *displayWidget : cardZoneDisplayWidgets) {
bool found = false;
for (const QString &zone : *deckListModel->getZones()) {
if (displayWidget->zoneName == zone) {
found = true;
}
}
if (!found) {
zoneContainerLayout->removeWidget(displayWidget);
}
}
}
void VisualDeckEditorWidget::resizeEvent(QResizeEvent *event)
@ -67,11 +117,10 @@ void VisualDeckEditorWidget::resizeEvent(QResizeEvent *event)
zoneContainer->setMaximumWidth(scrollArea->viewport()->width());
}
void VisualDeckEditorWidget::activeSortCriteriaChanged()
void VisualDeckEditorWidget::actChangeActiveSortCriteria()
{
activeSortCriteria = sortByComboBox->currentText();
qDebug() << "activeSortCriteria changed: " << activeSortCriteria;
updateDisplay();
emit activeSortCriteriaChanged(activeSortCriteria);
}
void VisualDeckEditorWidget::decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight)
@ -81,69 +130,7 @@ void VisualDeckEditorWidget::decklistDataChanged(QModelIndex topLeft, QModelInde
(void)bottomRight;
// Necessary to delay this in this manner else the updateDisplay will nuke widgets while their onClick event
// hasn't returned yet. Interval of 0 means QT will schedule this after the current event loop has finished.
QTimer::singleShot(0, this, [this] { updateDisplay(); });
}
void VisualDeckEditorWidget::updateDisplay()
{
// Clear the layout first
populateCards();
zoneContainer = new QWidget(scrollArea);
zoneContainer->setMaximumWidth(scrollArea->viewport()->width());
zoneContainerLayout = new QVBoxLayout(zoneContainer);
DeckCardZoneDisplayWidget *mainBoardWidget =
new DeckCardZoneDisplayWidget(zoneContainer, sortCards(mainDeckCards), tr("Mainboard"), 20, 10);
connect(mainBoardWidget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
connect(mainBoardWidget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onMainboardClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
DeckCardZoneDisplayWidget *sideBoardWidget =
new DeckCardZoneDisplayWidget(zoneContainer, sortCards(sideboardCards), tr("Sideboard"), 40, 30);
connect(sideBoardWidget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
connect(sideBoardWidget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onSideboardClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
zoneContainerLayout->addWidget(mainBoardWidget);
zoneContainerLayout->addWidget(sideBoardWidget);
scrollArea->setWidget(zoneContainer);
update();
}
QList<QPair<QString, QList<CardInfoPtr>>> VisualDeckEditorWidget::sortCards(QList<CardInfoPtr> *cardsToSort)
{
QList<QPair<QString, QList<CardInfoPtr>>> sortedCardGroups;
QList<CardInfoPtr> activeList;
QStringList sortCriteria;
sortCriteria.append(activeSortCriteria);
sortCardList(sortCriteria, Qt::SortOrder::AscendingOrder);
QString lastSortCriteriaValue = cardsToSort->isEmpty() ? "" : cardsToSort->at(0)->getProperty(activeSortCriteria);
for (int i = 0; i < cardsToSort->size(); ++i) {
CardInfoPtr info = cardsToSort->at(i);
if (info) {
QString currentCriteriaValue = info->getProperty(activeSortCriteria);
if (currentCriteriaValue != lastSortCriteriaValue) {
// Save the current tuple (criteriaValue, list) and start a new list
sortedCardGroups.append(qMakePair(lastSortCriteriaValue, activeList));
activeList.clear();
lastSortCriteriaValue = currentCriteriaValue;
}
activeList.append(info);
} else {
qDebug() << "Card not found in database!";
}
}
// Add the last tuple to sortedCardGroups
if (!activeList.isEmpty()) {
sortedCardGroups.append(qMakePair(lastSortCriteriaValue, activeList));
}
return sortedCardGroups;
updateZoneWidgets();
}
/*void VisualDeckEditorWidget::sortCards()
@ -187,31 +174,9 @@ void VisualDeckEditorWidget::onHover(CardInfoPtr hoveredCard)
emit activeCardChanged(hoveredCard);
}
void VisualDeckEditorWidget::onMainboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
void VisualDeckEditorWidget::onCardClick(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
QString zoneName)
{
emit mainboardCardClicked(event, instance);
}
void VisualDeckEditorWidget::onSideboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
{
emit sideboardCardClicked(event, instance);
}
void VisualDeckEditorWidget::populateCards()
{
mainDeckCards->clear();
sideboardCards->clear();
if (!deckListModel)
return;
mainDeckCards = deckListModel->getCardsAsCardInfoPtrsForZone(DECK_ZONE_MAIN);
sideboardCards = deckListModel->getCardsAsCardInfoPtrsForZone(DECK_ZONE_SIDE);
}
void VisualDeckEditorWidget::sortCardList(const QStringList properties, Qt::SortOrder order = Qt::AscendingOrder)
{
CardInfoComparator comparator(properties, order);
std::sort(mainDeckCards->begin(), mainDeckCards->end(), comparator);
std::sort(sideboardCards->begin(), sideboardCards->end(), comparator);
emit cardClicked(event, instance, zoneName);
}

View file

@ -17,41 +17,34 @@ class VisualDeckEditorWidget : public QWidget
public:
explicit VisualDeckEditorWidget(QWidget *parent, DeckListModel *deckListModel);
void resizeEvent(QResizeEvent *event) override;
void updateDisplay();
QWidget *displayCards(QList<QPair<QString, QList<CardInfoPtr>>> cardLists, int bannerOpacity);
QList<QPair<QString, QList<CardInfoPtr>>> sortCards(QList<CardInfoPtr> *cardsToSort);
OverlapWidget *getSortedCards();
void populateCards();
void sortCardList(QStringList properties, Qt::SortOrder order);
void setDeckList(const DeckList &new_deck_list_model);
void setDeckList(const DeckList &_deckListModel);
public slots:
void decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight);
void updateZoneWidgets();
void addZoneIfDoesNotExist();
void deleteZoneIfDoesNotExist();
signals:
void activeCardChanged(CardInfoPtr activeCard);
void mainboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void sideboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void activeSortCriteriaChanged(QString activeSortCriteria);
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
protected slots:
void onHover(CardInfoPtr hoveredCard);
void onMainboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void onSideboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void activeSortCriteriaChanged();
void onCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void actChangeActiveSortCriteria();
private:
DeckListModel *deckListModel;
QList<CardInfoPtr> *mainDeckCards;
QList<CardInfoPtr> *sideboardCards;
QVBoxLayout *mainLayout;
QComboBox *sortByComboBox;
QString activeSortCriteria = "maintype";
FlowWidget *flowWidget;
QScrollArea *scrollArea;
QWidget *zoneContainer;
QVBoxLayout *zoneContainerLayout;
OverlapControlWidget *overlap_control_widget;
OverlapControlWidget *overlapControlWidget;
QWidget *container;
};