From 2fe639676b859572ecbd0b50118b549bd59f3ea9 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sat, 19 Apr 2025 00:15:33 +0200
Subject: [PATCH 01/56] VDS performance fixes (#5848)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Block updates, don't validate cardInfo and use ItemModel instead of looped addItem.
* Change to QVariant map directly.
---------
Co-authored-by: Lukas Brübach
---
.../deck_preview/deck_preview_widget.cpp | 33 +++++++++++--------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
index f3bebbb90..556968d2b 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
DeckPreviewWidget::DeckPreviewWidget(QWidget *_parent,
@@ -27,6 +28,8 @@ DeckPreviewWidget::DeckPreviewWidget(QWidget *_parent,
deckLoader = new DeckLoader();
deckLoader->setParent(this);
connect(deckLoader, &DeckLoader::loadFinished, this, &DeckPreviewWidget::initializeUi);
+ /* TODO: We shouldn't update the tags on *every* deck load, since it's kinda expensive. We should instead count how
+ many deck loads have finished already and if we've loaded all decks and THEN load all the tags at once. */
connect(deckLoader, &DeckLoader::loadFinished, visualDeckStorageWidget->tagFilterWidget,
&VisualDeckStorageTagFilterWidget::refreshTags);
deckLoader->loadFromFileAsync(filePath, DeckLoader::getFormatFromName(filePath), false);
@@ -194,6 +197,7 @@ void DeckPreviewWidget::updateBannerCardComboBox()
// Block signals temporarily
bool wasBlocked = bannerCardComboBox->blockSignals(true);
+ bannerCardComboBox->setUpdatesEnabled(false);
// Clear the existing items in the combo box
bannerCardComboBox->clear();
@@ -209,12 +213,7 @@ void DeckPreviewWidget::updateBannerCardComboBox()
continue;
for (int k = 0; k < currentCard->getNumber(); ++k) {
- CardInfoPtr info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
- currentCard->getName(), currentCard->getCardProviderId());
- if (info) {
- bannerCardSet.insert(
- QPair(currentCard->getName(), currentCard->getCardProviderId()));
- }
+ bannerCardSet.insert(QPair(currentCard->getName(), currentCard->getCardProviderId()));
}
}
}
@@ -226,14 +225,19 @@ void DeckPreviewWidget::updateBannerCardComboBox()
return a.first.toLower() < b.first.toLower();
});
- for (const auto &pair : pairList) {
- QVariantMap dataMap;
- dataMap["name"] = pair.first;
- dataMap["uuid"] = pair.second;
+ // This is *slightly* more performant than using addItem in a loop.
- bannerCardComboBox->addItem(pair.first, dataMap);
+ QStandardItemModel *model = new QStandardItemModel(pairList.size(), 1, bannerCardComboBox);
+
+ int row = 0;
+ for (const auto &pair : pairList) {
+ QStandardItem *item = new QStandardItem(pair.first);
+ item->setData(QVariant::fromValue(pair), Qt::UserRole);
+ model->setItem(row++, 0, item);
}
+ bannerCardComboBox->setModel(model);
+
// Try to restore the previous selection by finding the currentText
int restoredIndex = bannerCardComboBox->findText(currentText);
if (restoredIndex != -1) {
@@ -251,15 +255,16 @@ void DeckPreviewWidget::updateBannerCardComboBox()
// Restore the previous signal blocking state
bannerCardComboBox->blockSignals(wasBlocked);
+ bannerCardComboBox->setUpdatesEnabled(true);
}
void DeckPreviewWidget::setBannerCard(int /* changedIndex */)
{
- QVariantMap itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
- deckLoader->setBannerCard(QPair(itemData["name"].toString(), itemData["uuid"].toString()));
+ QVariant itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex());
+ deckLoader->setBannerCard(QPair(bannerCardComboBox->currentText(), itemData.toString()));
deckLoader->saveToFile(filePath, DeckLoader::getFormatFromName(filePath));
bannerCardDisplayWidget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
- itemData["name"].toString(), itemData["uuid"].toString()));
+ bannerCardComboBox->currentText(), itemData.toString()));
}
void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
From 3b1d6e394dc5ddf3f1db8a752385dc30df2a2989 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sat, 19 Apr 2025 00:28:44 +0200
Subject: [PATCH 02/56] [EDHRec] Display name above card, add bars for
inclusion and synergy instead of coloring the whole label, card size slider
(#5851)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Display name above card, add bars for inclusion and synergy instead of coloring the whole label.
* Re-add commander label.
* Add a card size slider.
* Lint.
---------
Co-authored-by: Lukas Brübach
---
cockatrice/CMakeLists.txt | 3 ++
...i_response_card_details_display_widget.cpp | 35 +++++---------
...api_response_card_details_display_widget.h | 6 ++-
...response_card_inclusion_display_widget.cpp | 41 +++++++++++++++++
...i_response_card_inclusion_display_widget.h | 27 +++++++++++
...i_response_card_synergy_display_widget.cpp | 28 +++++++++++
...api_response_card_synergy_display_widget.h | 25 ++++++++++
...ponse_commander_details_display_widget.cpp | 17 +++++++
.../tabs/api/edhrec/tab_edhrec_main.cpp | 7 +++
.../client/tabs/api/edhrec/tab_edhrec_main.h | 9 ++++
.../general/display/percent_bar_widget.cpp | 46 +++++++++++++++++++
.../general/display/percent_bar_widget.h | 33 +++++++++++++
12 files changed, 252 insertions(+), 25 deletions(-)
create mode 100644 cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
create mode 100644 cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h
create mode 100644 cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
create mode 100644 cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h
create mode 100644 cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.cpp
create mode 100644 cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.h
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index cbd0ed1d7..110c99697 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -24,7 +24,9 @@ set(cockatrice_SOURCES
src/client/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp
src/client/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
+ src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp
+ src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
src/client/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp
src/client/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp
@@ -99,6 +101,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/general/display/dynamic_font_size_label.cpp
src/client/ui/widgets/general/display/dynamic_font_size_push_button.cpp
src/client/ui/widgets/general/display/labeled_input.cpp
+ src/client/ui/widgets/general/display/percent_bar_widget.cpp
src/client/ui/widgets/general/display/shadow_background_label.cpp
src/client/ui/widgets/general/layout_containers/flow_widget.cpp
src/client/ui/widgets/general/layout_containers/overlap_control_widget.cpp
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
index f6e0cf4fa..674f011cd 100644
--- a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
+++ b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp
@@ -14,34 +14,18 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
cardPictureWidget = new CardInfoPictureWidget(this);
cardPictureWidget->setCard(CardDatabaseManager::getInstance()->guessCard(toDisplay.sanitized));
- label = new QLabel(this);
- label->setText(toDisplay.name + "\n" + toDisplay.label);
- label->setAlignment(Qt::AlignHCenter);
+ nameLabel = new QLabel(this);
+ nameLabel->setText(toDisplay.name);
+ nameLabel->setAlignment(Qt::AlignHCenter);
- int inclusionRate = 0;
- // Set label color based on inclusion rate
- if (toDisplay.potentialDecks != 0) {
- inclusionRate = (toDisplay.numDecks * 100) / toDisplay.potentialDecks;
- }
+ inclusionDisplayWidget = new EdhrecApiResponseCardInclusionDisplayWidget(this, toDisplay);
- QColor labelColor;
- if (inclusionRate <= 30) {
- labelColor = QColor(255, 0, 0); // Red
- } else if (inclusionRate <= 60) {
- int red = 255 - ((inclusionRate - 30) * 2);
- int green = (inclusionRate - 30) * 4; // Adjust green to make the transition smoother
- labelColor = QColor(red, green, 0); // purple-ish
- } else if (inclusionRate <= 90) {
- int green = (inclusionRate - 60) * 5; // Increase green
- labelColor = QColor(100, green, 100); // Green shades
- } else {
- labelColor = QColor(100, 200, 100); // Dark Green
- }
-
- label->setStyleSheet(QString("color: %1").arg(labelColor.name()));
+ synergyDisplayWidget = new EdhrecApiResponseCardSynergyDisplayWidget(this, toDisplay);
+ layout->addWidget(nameLabel);
layout->addWidget(cardPictureWidget);
- layout->addWidget(label);
+ layout->addWidget(inclusionDisplayWidget);
+ layout->addWidget(synergyDisplayWidget);
QWidget *currentParent = parentWidget();
TabEdhRecMain *parentTab = nullptr;
@@ -54,8 +38,11 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
}
if (parentTab) {
+ cardPictureWidget->setScaleFactor(parentTab->getCardSizeSlider()->getSlider()->value());
connect(cardPictureWidget, &CardInfoPictureWidget::cardClicked, this,
&EdhrecApiResponseCardDetailsDisplayWidget::actRequestPageNavigation);
+ connect(parentTab->getCardSizeSlider()->getSlider(), &QSlider::valueChanged, cardPictureWidget,
+ &CardInfoPictureWidget::setScaleFactor);
connect(this, &EdhrecApiResponseCardDetailsDisplayWidget::requestUrl, parentTab,
&TabEdhRecMain::actNavigatePage);
}
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h
index 7492659e9..820434612 100644
--- a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h
+++ b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h
@@ -3,6 +3,8 @@
#include "../../../../../ui/widgets/cards/card_info_picture_widget.h"
#include "../../api_response/cards/edhrec_api_response_card_details.h"
+#include "edhrec_api_response_card_inclusion_display_widget.h"
+#include "edhrec_api_response_card_synergy_display_widget.h"
#include
#include
@@ -22,7 +24,9 @@ private:
EdhrecApiResponseCardDetails toDisplay;
QVBoxLayout *layout;
CardInfoPictureWidget *cardPictureWidget;
- QLabel *label;
+ QLabel *nameLabel;
+ EdhrecApiResponseCardInclusionDisplayWidget *inclusionDisplayWidget;
+ EdhrecApiResponseCardSynergyDisplayWidget *synergyDisplayWidget;
};
#endif // EDHREC_COMMANDER_API_RESPONSE_CARD_DETAILS_DISPLAY_WIDGET_H
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
new file mode 100644
index 000000000..8292b00ea
--- /dev/null
+++ b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp
@@ -0,0 +1,41 @@
+#include "edhrec_api_response_card_inclusion_display_widget.h"
+
+EdhrecApiResponseCardInclusionDisplayWidget::EdhrecApiResponseCardInclusionDisplayWidget(
+ QWidget *parent,
+ const EdhrecApiResponseCardDetails &_toDisplay)
+ : QWidget(parent), toDisplay(_toDisplay)
+{
+ layout = new QVBoxLayout(this);
+ setLayout(layout);
+
+ commanderLabel = new QLabel(this);
+ commanderLabel->setAlignment(Qt::AlignCenter);
+ amountLabel = new QLabel(this);
+ amountLabel->setAlignment(Qt::AlignCenter);
+ inclusionLabel = new QLabel(this);
+ inclusionLabel->setAlignment(Qt::AlignCenter);
+ percentBarWidget = new PercentBarWidget(this, toDisplay.inclusion / (toDisplay.potentialDecks / 100.0));
+
+ if (toDisplay.inclusion != 0 && toDisplay.potentialDecks != 0) {
+ layout->addWidget(amountLabel);
+ layout->addWidget(inclusionLabel);
+ layout->addWidget(percentBarWidget);
+ commanderLabel->hide();
+ } else {
+ amountLabel->hide();
+ inclusionLabel->hide();
+ percentBarWidget->hide();
+ layout->addWidget(commanderLabel);
+ }
+
+ retranslateUi();
+}
+
+void EdhrecApiResponseCardInclusionDisplayWidget::retranslateUi()
+{
+ commanderLabel->setText(toDisplay.label);
+ amountLabel->setText(tr("In %1 decks").arg(QString::number(toDisplay.inclusion)));
+ inclusionLabel->setText(tr("%1% of %2 decks")
+ .arg(QString::number(toDisplay.inclusion / (toDisplay.potentialDecks / 100.0), 'f', 2),
+ QString::number(toDisplay.potentialDecks)));
+}
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h
new file mode 100644
index 000000000..f0fbfdfc8
--- /dev/null
+++ b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h
@@ -0,0 +1,27 @@
+#ifndef EDHREC_API_RESPONSE_CARD_INCLUSION_DISPLAY_WIDGET_H
+#define EDHREC_API_RESPONSE_CARD_INCLUSION_DISPLAY_WIDGET_H
+
+#include "../../../../../ui/widgets/general/display/percent_bar_widget.h"
+#include "../../api_response/cards/edhrec_api_response_card_details.h"
+
+#include
+#include
+#include
+
+class EdhrecApiResponseCardInclusionDisplayWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ EdhrecApiResponseCardInclusionDisplayWidget(QWidget *parent, const EdhrecApiResponseCardDetails &_toDisplay);
+ void retranslateUi();
+
+private:
+ QVBoxLayout *layout;
+ EdhrecApiResponseCardDetails toDisplay;
+ QLabel *commanderLabel;
+ QLabel *amountLabel;
+ QLabel *inclusionLabel;
+ PercentBarWidget *percentBarWidget;
+};
+
+#endif // EDHREC_API_RESPONSE_CARD_INCLUSION_DISPLAY_WIDGET_H
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
new file mode 100644
index 000000000..9d5571a8f
--- /dev/null
+++ b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp
@@ -0,0 +1,28 @@
+#include "edhrec_api_response_card_synergy_display_widget.h"
+
+EdhrecApiResponseCardSynergyDisplayWidget::EdhrecApiResponseCardSynergyDisplayWidget(
+ QWidget *parent,
+ const EdhrecApiResponseCardDetails &_toDisplay)
+ : QWidget(parent), toDisplay(_toDisplay)
+{
+ layout = new QVBoxLayout(this);
+ setLayout(layout);
+
+ label = new QLabel(this);
+ label->setAlignment(Qt::AlignCenter);
+ percentBarWidget = new PercentBarWidget(this, toDisplay.synergy * 100.0);
+
+ if (toDisplay.synergy != 0) {
+ layout->addWidget(label);
+ layout->addWidget(percentBarWidget);
+ } else {
+ hide();
+ }
+
+ retranslateUi();
+}
+
+void EdhrecApiResponseCardSynergyDisplayWidget::retranslateUi()
+{
+ label->setText(tr("%1% Synergy").arg(QString::number(toDisplay.synergy * 100.0, 'f', 1)));
+}
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h
new file mode 100644
index 000000000..ebb252880
--- /dev/null
+++ b/cockatrice/src/client/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h
@@ -0,0 +1,25 @@
+#ifndef EDHREC_API_RESPONSE_CARD_SYNERGY_DISPLAY_WIDGET_H
+#define EDHREC_API_RESPONSE_CARD_SYNERGY_DISPLAY_WIDGET_H
+
+#include "../../../../../ui/widgets/general/display/percent_bar_widget.h"
+#include "../../api_response/cards/edhrec_api_response_card_details.h"
+
+#include
+#include
+#include
+
+class EdhrecApiResponseCardSynergyDisplayWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ EdhrecApiResponseCardSynergyDisplayWidget(QWidget *parent, const EdhrecApiResponseCardDetails &_toDisplay);
+ void retranslateUi();
+
+private:
+ QVBoxLayout *layout;
+ EdhrecApiResponseCardDetails toDisplay;
+ QLabel *label;
+ PercentBarWidget *percentBarWidget;
+};
+
+#endif // EDHREC_API_RESPONSE_CARD_SYNERGY_DISPLAY_WIDGET_H
diff --git a/cockatrice/src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp b/cockatrice/src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
index e04325a35..2001cf6d1 100644
--- a/cockatrice/src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
+++ b/cockatrice/src/client/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp
@@ -2,6 +2,7 @@
#include "../../../../../../game/cards/card_database_manager.h"
#include "../../../../../ui/widgets/cards/card_info_picture_widget.h"
+#include "../../tab_edhrec_main.h"
#include "../card_prices/edhrec_api_response_card_prices_display_widget.h"
EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCommanderDetailsDisplayWidget(
@@ -16,6 +17,22 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
commanderPicture = new CardInfoPictureWidget(this);
commanderPicture->setCard(CardDatabaseManager::getInstance()->getCard(commanderDetails.getName()));
+ QWidget *currentParent = parentWidget();
+ TabEdhRecMain *parentTab = nullptr;
+
+ while (currentParent) {
+ if ((parentTab = qobject_cast(currentParent))) {
+ break;
+ }
+ currentParent = currentParent->parentWidget();
+ }
+
+ if (parentTab) {
+ connect(parentTab->getCardSizeSlider()->getSlider(), &QSlider::valueChanged, commanderPicture,
+ &CardInfoPictureWidget::setScaleFactor);
+ commanderPicture->setScaleFactor(parentTab->getCardSizeSlider()->getSlider()->value());
+ }
+
commanderDetails.debugPrint();
label = new QLabel(this);
diff --git a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
index ac30cef4d..0bd4e843a 100644
--- a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
+++ b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
@@ -94,11 +94,18 @@ TabEdhRecMain::TabEdhRecMain(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor
searchPushButton = new QPushButton(navigationContainer);
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { doSearch(); });
+ settingsButton = new SettingsButtonWidget(this);
+
+ cardSizeSlider = new CardSizeWidget(this);
+
+ settingsButton->addSettingsWidget(cardSizeSlider);
+
navigationLayout->addWidget(cardsPushButton);
navigationLayout->addWidget(topCommandersPushButton);
navigationLayout->addWidget(tagsPushButton);
navigationLayout->addWidget(searchBar);
navigationLayout->addWidget(searchPushButton);
+ navigationLayout->addWidget(settingsButton);
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
diff --git a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.h b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.h
index 1c6c67e5c..ba64cdc0a 100644
--- a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.h
+++ b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.h
@@ -2,7 +2,9 @@
#define TAB_EDHREC_MAIN_H
#include "../../../../game/cards/card_database.h"
+#include "../../../ui/widgets/cards/card_size_widget.h"
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
+#include "../../../ui/widgets/quick_settings/settings_button_widget.h"
#include "../../tab.h"
#include "display/commander/edhrec_commander_api_response_display_widget.h"
@@ -25,6 +27,11 @@ public:
return tr("EDHREC: ") + cardName;
}
+ CardSizeWidget *getCardSizeSlider()
+ {
+ return cardSizeSlider;
+ }
+
QNetworkAccessManager *networkManager;
public slots:
@@ -53,6 +60,8 @@ private:
QPushButton *tagsPushButton;
QLineEdit *searchBar;
QPushButton *searchPushButton;
+ SettingsButtonWidget *settingsButton;
+ CardSizeWidget *cardSizeSlider;
CardInfoPtr cardToQuery;
EdhrecCommanderApiResponseDisplayWidget *displayWidget;
};
diff --git a/cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.cpp b/cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.cpp
new file mode 100644
index 000000000..3726dd061
--- /dev/null
+++ b/cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.cpp
@@ -0,0 +1,46 @@
+#include "percent_bar_widget.h"
+
+PercentBarWidget::PercentBarWidget(QWidget *parent, double initialValue) : QWidget(parent), valueToDisplay(initialValue)
+{
+ setMinimumSize(50, 10);
+}
+
+void PercentBarWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+
+ QPainter painter(this);
+ QRect rect = this->rect();
+
+ const int midX = rect.width() / 2;
+ const int height = rect.height();
+
+ // Draw background border (no fill)
+ painter.setPen(QPen(Qt::black, 1));
+ painter.setBrush(Qt::NoBrush);
+ painter.drawRect(rect.adjusted(0, 0, -1, -1)); // Avoid right/bottom overflow
+
+ const double halfWidth = rect.width() / 2.0;
+
+ const int barLength = static_cast((qAbs(valueToDisplay) / 100.0) * halfWidth);
+
+ QRect fillRect;
+ if (valueToDisplay > 0.0) {
+ fillRect = QRect(midX, 0, barLength, height);
+ painter.fillRect(fillRect, Qt::green);
+ } else if (valueToDisplay < 0.0) {
+ fillRect = QRect(midX - barLength, 0, barLength, height);
+ painter.fillRect(fillRect, Qt::red);
+ }
+
+ // Draw center line at 0
+ painter.fillRect(midX - 1, 0, 3, height, Qt::white);
+
+ // Draw tick marks every 10%
+ const int tickHeight = 4;
+
+ for (int percent = -100; percent <= 100; percent += 10) {
+ int x = midX + static_cast((percent / 100.0) * halfWidth);
+ painter.drawLine(x, height - tickHeight, x, height);
+ }
+}
diff --git a/cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.h b/cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.h
new file mode 100644
index 000000000..c782b448b
--- /dev/null
+++ b/cockatrice/src/client/ui/widgets/general/display/percent_bar_widget.h
@@ -0,0 +1,33 @@
+#ifndef PERCENT_BAR_WIDGET_H
+#define PERCENT_BAR_WIDGET_H
+
+#include
+#include
+#include
+
+class PercentBarWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit PercentBarWidget(QWidget *parent, double initialValue);
+
+ void setValue(double newValue)
+ {
+ valueToDisplay = qBound(-100.0, newValue, 100.0); // Clamp to [-100, 100]
+ update(); // Trigger repaint
+ }
+
+ double value() const
+ {
+ return valueToDisplay;
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+
+private:
+ double valueToDisplay; // Ranges from -100 to 100
+};
+
+#endif // PERCENT_BAR_WIDGET_H
From 1e01c684c4a14c92dd2a32a0481274b8bfdd604e Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sat, 19 Apr 2025 01:25:39 +0200
Subject: [PATCH 03/56] Display cards as set variants if only a single set is
selected. (#5854)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../visual_database_display_widget.cpp | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
index d1e4b2db5..18369224b 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
@@ -195,13 +195,30 @@ void VisualDatabaseDisplayWidget::populateCards()
databaseDisplayModel->fetchMore(QModelIndex());
}
+ QList setFilters = filterModel->getFiltersOfType(CardFilter::AttrSet);
+ const CardFilter *setFilter = nullptr;
+ if (setFilters.length() == 1) {
+ setFilter = setFilters.at(0);
+ }
+
for (int row = start; row < end; ++row) {
qCDebug(VisualDatabaseDisplayLog) << "Adding " << row;
QModelIndex index = databaseDisplayModel->index(row, CardDatabaseModel::NameColumn);
QVariant name = databaseDisplayModel->data(index, Qt::DisplayRole);
qCDebug(VisualDatabaseDisplayLog) << name.toString();
+
if (CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(name.toString())) {
- addCard(info);
+ if (setFilter) {
+ CardInfoPerSetMap setMap = info->getSets();
+ if (setMap.contains(setFilter->term())) {
+ for (CardInfoPerSet cardSetInstance : setMap[setFilter->term()]) {
+ addCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
+ name.toString(), cardSetInstance.getProperty("uuid")));
+ }
+ }
+ } else {
+ addCard(info);
+ }
} else {
qCDebug(VisualDatabaseDisplayLog) << "Card not found in database!";
}
From 0c02d15e0dd0740696b20f1b728eea0c5f09da21 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sat, 19 Apr 2025 01:26:17 +0200
Subject: [PATCH 04/56] Allow empty collectorNumber. (#5853)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
cockatrice/src/game/cards/card_database.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/cockatrice/src/game/cards/card_database.cpp b/cockatrice/src/game/cards/card_database.cpp
index 7181ffd06..bb307b543 100644
--- a/cockatrice/src/game/cards/card_database.cpp
+++ b/cockatrice/src/game/cards/card_database.cpp
@@ -386,9 +386,10 @@ CardInfoPerSet CardDatabase::getSpecificSetForCard(const QString &cardName,
for (const auto &cardInfoPerSetList : setMap) {
for (auto &cardInfoForSet : cardInfoPerSetList) {
- if (cardInfoForSet.getPtr()->getShortName() == setShortName &&
- cardInfoForSet.getProperty("num") == collectorNumber) {
- return cardInfoForSet;
+ if (cardInfoForSet.getPtr()->getShortName() == setShortName) {
+ if (cardInfoForSet.getProperty("num") == collectorNumber || collectorNumber.isEmpty()) {
+ return cardInfoForSet;
+ }
}
}
}
From 1d259a86c129e54c9a1288cd27f6fd265f90869b Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sat, 19 Apr 2025 01:27:50 +0200
Subject: [PATCH 05/56] Don't add duplicate CardInfos to set. (#5852)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
cockatrice/src/game/cards/card_info.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/game/cards/card_info.cpp b/cockatrice/src/game/cards/card_info.cpp
index ae55ad7af..344345b41 100644
--- a/cockatrice/src/game/cards/card_info.cpp
+++ b/cockatrice/src/game/cards/card_info.cpp
@@ -289,8 +289,12 @@ QString CardInfo::getCorrectedName() const
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{
- _set->append(smartThis);
- sets[_set->getShortName()].append(_info);
+ if (!_set->contains(smartThis)) {
+ _set->append(smartThis);
+ }
+ if (!sets[_set->getShortName()].contains(_info)) {
+ sets[_set->getShortName()].append(_info);
+ }
refreshCachedSetNames();
}
From 26dcb015cec1592e2e6bb74575c58f1349c2bf8e Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sat, 19 Apr 2025 21:07:22 -0700
Subject: [PATCH 06/56] Refactor function structs into lambdas (#5675)
* change signature to use lambda
* reuse comparator
* inline structs in forEachCard
* inline structs
* Refactor exportDeckToDecklist
* fix unit test
---
.../src/client/tapped_out_interface.cpp | 17 +-
.../ui/picture_loader/picture_to_load.cpp | 3 +-
.../ui/picture_loader/picture_to_load.h | 18 ---
cockatrice/src/deck/deck_loader.cpp | 148 +++++++-----------
cockatrice/src/deck/deck_stats_interface.cpp | 17 +-
common/decklist.cpp | 57 +++----
common/decklist.h | 18 +--
.../clipboard_testing.cpp | 32 ++--
.../clipboard_testing.h | 11 +-
9 files changed, 108 insertions(+), 213 deletions(-)
diff --git a/cockatrice/src/client/tapped_out_interface.cpp b/cockatrice/src/client/tapped_out_interface.cpp
index d6a47b018..4fd103c8c 100644
--- a/cockatrice/src/client/tapped_out_interface.cpp
+++ b/cockatrice/src/client/tapped_out_interface.cpp
@@ -92,16 +92,9 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
manager->post(request, data);
}
-struct CopyMainOrSide
+void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
{
- CardDatabase &cardDatabase;
- DeckList &mainboard, &sideboard;
-
- CopyMainOrSide(CardDatabase &_cardDatabase, DeckList &_mainboard, DeckList &_sideboard)
- : cardDatabase(_cardDatabase), mainboard(_mainboard), sideboard(_sideboard){};
-
- void operator()(const InnerDecklistNode *node, const DecklistCardNode *card) const
- {
+ auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.getCard(card->getName());
if (!dbCard || dbCard->getIsToken())
return;
@@ -112,11 +105,7 @@ struct CopyMainOrSide
else
addedCard = mainboard.addCard(card->getName(), node->getName());
addedCard->setNumber(card->getNumber());
- }
-};
+ };
-void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
-{
- CopyMainOrSide copyMainOrSide(cardDatabase, mainboard, sideboard);
source.forEachCard(copyMainOrSide);
}
diff --git a/cockatrice/src/client/ui/picture_loader/picture_to_load.cpp b/cockatrice/src/client/ui/picture_loader/picture_to_load.cpp
index 9800d7cc5..81210a983 100644
--- a/cockatrice/src/client/ui/picture_loader/picture_to_load.cpp
+++ b/cockatrice/src/client/ui/picture_loader/picture_to_load.cpp
@@ -1,6 +1,7 @@
#include "picture_to_load.h"
#include "../../../settings/cache_settings.h"
+#include "../../../utility/card_set_comparator.h"
#include
#include
@@ -20,7 +21,7 @@ PictureToLoad::PictureToLoad(CardInfoPtr _card)
if (sortedSets.empty()) {
sortedSets << CardSet::newInstance("", "", "", QDate());
}
- std::sort(sortedSets.begin(), sortedSets.end(), SetDownloadPriorityComparator());
+ std::sort(sortedSets.begin(), sortedSets.end(), SetPriorityComparator());
// If the user hasn't disabled arts other than their personal preference...
if (!SettingsCache::instance().getOverrideAllCardArtWithPersonalPreference()) {
diff --git a/cockatrice/src/client/ui/picture_loader/picture_to_load.h b/cockatrice/src/client/ui/picture_loader/picture_to_load.h
index 9d1a784f0..38ebe5763 100644
--- a/cockatrice/src/client/ui/picture_loader/picture_to_load.h
+++ b/cockatrice/src/client/ui/picture_loader/picture_to_load.h
@@ -10,24 +10,6 @@ inline Q_LOGGING_CATEGORY(PictureToLoadLog, "picture_loader.picture_to_load");
class PictureToLoad
{
private:
- class SetDownloadPriorityComparator
- {
- public:
- /*
- * Returns true if a has higher download priority than b
- * Enabled sets have priority over disabled sets
- * Both groups follows the user-defined order
- */
- inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
- {
- if (a->getEnabled()) {
- return !b->getEnabled() || a->getSortKey() < b->getSortKey();
- } else {
- return !b->getEnabled() && a->getSortKey() < b->getSortKey();
- }
- }
- };
-
CardInfoPtr card;
QList sortedSets;
QList urlTemplates;
diff --git a/cockatrice/src/deck/deck_loader.cpp b/cockatrice/src/deck/deck_loader.cpp
index 1c7136bf5..d0c0f5239 100644
--- a/cockatrice/src/deck/deck_loader.cpp
+++ b/cockatrice/src/deck/deck_loader.cpp
@@ -239,54 +239,33 @@ static QString getDomainForWebsite(DeckLoader::DecklistWebsite website)
}
}
-// This struct is here to support the forEachCard function call, defined in decklist. It
-// requires a function to be called for each card, and passes an inner node and a card for
-// each card in the decklist.
-struct FormatDeckListForExport
+/**
+ * Converts the card to the String that represents it in the decklist export
+ */
+static QString toDecklistExportString(const DecklistCardNode *card)
{
- // Create refrences for the strings that will be passed in.
- QString &mainBoardCards;
- QString &sideBoardCards;
- // create main operator for struct, allowing the foreachcard to work.
- FormatDeckListForExport(QString &_mainBoardCards, QString &_sideBoardCards)
- : mainBoardCards(_mainBoardCards), sideBoardCards(_sideBoardCards){};
+ QString cardString;
+ // Get the number of cards and add the card name
+ cardString += QString::number(card->getNumber());
+ // Add a space between card num and name
+ cardString += "%20";
+ // Add card name
+ cardString += card->getName();
- void operator()(const InnerDecklistNode *node, const DecklistCardNode *card) const
- {
- // Get the card name
- CardInfoPtr dbCard = CardDatabaseManager::getInstance()->getCard(card->getName());
- if (!dbCard || dbCard->getIsToken()) {
- // If it's a token, we don't care about the card.
- return;
- }
-
- // Check if it's a sideboard card.
- if (node->getName() == DECK_ZONE_SIDE) {
- // Get the number of cards and add the card name
- sideBoardCards += QString::number(card->getNumber());
- // Add a space between card num and name
- sideBoardCards += "%20";
- // Add card name
- sideBoardCards += card->getName();
- // Add a return at the end of the card
- sideBoardCards += "%0A";
- } else // If it's a mainboard card, do the same thing, but for the mainboard card string
- {
- mainBoardCards += QString::number(card->getNumber());
- mainBoardCards += "%20";
- mainBoardCards += card->getName();
- if (!card->getCardSetShortName().isNull()) {
- mainBoardCards += "%20";
- mainBoardCards += "(" + card->getCardSetShortName() + ")";
- }
- if (!card->getCardCollectorNumber().isNull()) {
- mainBoardCards += "%20";
- mainBoardCards += card->getCardCollectorNumber();
- }
- mainBoardCards += "%0A";
- }
+ if (!card->getCardSetShortName().isNull()) {
+ cardString += "%20";
+ cardString += "(" + card->getCardSetShortName() + ")";
}
-};
+ if (!card->getCardCollectorNumber().isNull()) {
+ cardString += "%20";
+ cardString += card->getCardCollectorNumber();
+ }
+
+ // Add a return at the end of the card
+ cardString += "%0A";
+
+ return cardString;
+}
/**
* Export deck to decklist function, called to format the deck in a way to be sent to a server
@@ -298,8 +277,25 @@ QString DeckLoader::exportDeckToDecklist(DecklistWebsite website)
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
// Create two strings to pass to function
QString mainBoardCards, sideBoardCards;
- // Set up the struct to call.
- FormatDeckListForExport formatDeckListForExport(mainBoardCards, sideBoardCards);
+
+ // Set up the function to call
+ auto formatDeckListForExport = [&mainBoardCards, &sideBoardCards](const auto *node, const auto *card) {
+ // Get the card name
+ CardInfoPtr dbCard = CardDatabaseManager::getInstance()->getCard(card->getName());
+ if (!dbCard || dbCard->getIsToken()) {
+ // If it's a token, we don't care about the card.
+ return;
+ }
+
+ // Check if it's a sideboard card.
+ if (node->getName() == DECK_ZONE_SIDE) {
+ sideBoardCards += toDecklistExportString(card);
+ } else {
+ // If it's a mainboard card, do the same thing, but for the mainboard card string
+ mainBoardCards += toDecklistExportString(card);
+ }
+ };
+
// call our struct function for each card in the deck
forEachCard(formatDeckListForExport);
// Remove the extra return at the end of the last cards
@@ -316,17 +312,12 @@ QString DeckLoader::exportDeckToDecklist(DecklistWebsite website)
return deckString;
}
-// This struct is here to support the forEachCard function call, defined in decklist.
-// It requires a function to be called for each card, and it will set the providerId.
-struct SetProviderId
+/**
+ * Sets the providerId on each card in the decklist based on its set name and collector number.
+ */
+void DeckLoader::resolveSetNameAndNumberToProviderID()
{
- // Main operator for struct, allowing the foreachcard to work.
- SetProviderId()
- {
- }
-
- void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
- {
+ auto setProviderId = [](const auto node, const auto card) {
Q_UNUSED(node);
// Retrieve the providerId based on setName and collectorNumber
QString providerId =
@@ -336,50 +327,23 @@ struct SetProviderId
// Set the providerId on the card
card->setCardProviderId(providerId);
- }
-};
+ };
-/**
- * This function iterates through each card in the decklist and sets the providerId
- * on each card based on its set name and collector number.
- */
-void DeckLoader::resolveSetNameAndNumberToProviderID()
-{
- // Set up the struct to call.
- SetProviderId setProviderId;
-
- // Call the forEachCard method for each card in the deck
forEachCard(setProviderId);
}
-// This struct is here to support the forEachCard function call, defined in decklist.
-// It requires a function to be called for each card, and it will set the providerId.
-struct ClearSetNameAndNumber
-{
- // Main operator for struct, allowing the foreachcard to work.
- ClearSetNameAndNumber()
- {
- }
-
- void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
- {
- Q_UNUSED(node);
- // Set the providerId on the card
- card->setCardSetShortName(nullptr);
- card->setCardCollectorNumber(nullptr);
- }
-};
-
/**
- * This function iterates through each card in the decklist and sets the providerId
- * on each card based on its set name and collector number.
+ * Clears the set name and numbers on each card in the decklist.
*/
void DeckLoader::clearSetNamesAndNumbers()
{
- // Set up the struct to call.
- ClearSetNameAndNumber clearSetNameAndNumber;
+ auto clearSetNameAndNumber = [](const auto node, auto card) {
+ Q_UNUSED(node)
+ // Set the providerId on the card
+ card->setCardSetShortName(nullptr);
+ card->setCardCollectorNumber(nullptr);
+ };
- // Call the forEachCard method for each card in the deck
forEachCard(clearSetNameAndNumber);
}
diff --git a/cockatrice/src/deck/deck_stats_interface.cpp b/cockatrice/src/deck/deck_stats_interface.cpp
index dc2ab14df..7cfd69d40 100644
--- a/cockatrice/src/deck/deck_stats_interface.cpp
+++ b/cockatrice/src/deck/deck_stats_interface.cpp
@@ -67,26 +67,15 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
manager->post(request, data);
}
-struct CopyIfNotAToken
+void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
{
- CardDatabase &cardDatabase;
- DeckList &destination;
-
- CopyIfNotAToken(CardDatabase &_cardDatabase, DeckList &_destination)
- : cardDatabase(_cardDatabase), destination(_destination){};
-
- void operator()(const InnerDecklistNode *node, const DecklistCardNode *card) const
- {
+ auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.getCard(card->getName());
if (dbCard && !dbCard->getIsToken()) {
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName());
addedCard->setNumber(card->getNumber());
}
- }
-};
+ };
-void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
-{
- CopyIfNotAToken copyIfNotAToken(cardDatabase, destination);
source.forEachCard(copyIfNotAToken);
}
diff --git a/common/decklist.cpp b/common/decklist.cpp
index 789f57910..6f27d2895 100644
--- a/common/decklist.cpp
+++ b/common/decklist.cpp
@@ -262,21 +262,6 @@ bool AbstractDecklistCardNode::compareName(AbstractDecklistNode *other) const
}
}
-class InnerDecklistNode::compareFunctor
-{
-private:
- Qt::SortOrder order;
-
-public:
- explicit compareFunctor(Qt::SortOrder _order) : order(_order)
- {
- }
- inline bool operator()(QPair a, QPair b) const
- {
- return (order == Qt::AscendingOrder) ? (b.second->compare(a.second)) : (a.second->compare(b.second));
- }
-};
-
bool InnerDecklistNode::readElement(QXmlStreamReader *xml)
{
while (!xml->atEnd()) {
@@ -347,7 +332,10 @@ QVector> InnerDecklistNode::sort(Qt::SortOrder order)
}
// Sort temporary list
- compareFunctor cmp(order);
+ auto cmp = [order](const auto &a, const auto &b) {
+ return (order == Qt::AscendingOrder) ? (b.second->compare(a.second)) : (a.second->compare(b.second));
+ };
+
std::sort(tempList.begin(), tempList.end(), cmp);
// Map old indexes to new indexes and
@@ -762,20 +750,9 @@ bool DeckList::loadFromFile_Plain(QIODevice *device)
return loadFromStream_Plain(in, false);
}
-struct WriteToStream
+bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards)
{
- QTextStream &stream;
- bool prefixSideboardCards;
- bool slashTappedOutSplitCards;
-
- WriteToStream(QTextStream &_stream, bool _prefixSideboardCards, bool _slashTappedOutSplitCards)
- : stream(_stream), prefixSideboardCards(_prefixSideboardCards),
- slashTappedOutSplitCards(_slashTappedOutSplitCards)
- {
- }
-
- void operator()(const InnerDecklistNode *node, const DecklistCardNode *card)
- {
+ auto writeToStream = [&stream, prefixSideboardCards, slashTappedOutSplitCards](const auto node, const auto card) {
if (prefixSideboardCards && node->getName() == DECK_ZONE_SIDE) {
stream << "SB: ";
}
@@ -784,12 +761,8 @@ struct WriteToStream
} else {
stream << QString("%1 %2\n").arg(card->getNumber()).arg(card->getName().replace("//", "/"));
}
- }
-};
+ };
-bool DeckList::saveToStream_Plain(QTextStream &out, bool prefixSideboardCards, bool slashTappedOutSplitCards)
-{
- WriteToStream writeToStream(out, prefixSideboardCards, slashTappedOutSplitCards);
forEachCard(writeToStream);
return true;
}
@@ -994,3 +967,19 @@ void DeckList::refreshDeckHash()
cachedDeckHash = QString();
emit deckHashChanged();
}
+
+/**
+ * Calls a given function on each card in the deck.
+ */
+void DeckList::forEachCard(const std::function &func)
+{
+ // Support for this is only possible if the internal structure
+ // doesn't get more complicated.
+ for (int i = 0; i < root->size(); i++) {
+ InnerDecklistNode *node = dynamic_cast(root->at(i));
+ for (int j = 0; j < node->size(); j++) {
+ DecklistCardNode *card = dynamic_cast(node->at(j));
+ func(node, card);
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/decklist.h b/common/decklist.h
index de839ad23..989c3e7fe 100644
--- a/common/decklist.h
+++ b/common/decklist.h
@@ -381,23 +381,7 @@ public:
QString getDeckHash() const;
void refreshDeckHash();
- /**
- * Calls a given function object for each card in the deck. It must
- * take a InnerDecklistNode* as its first argument and a
- * DecklistCardNode* as its second.
- */
- template void forEachCard(Callback &callback)
- {
- // Support for this is only possible if the internal structure
- // doesn't get more complicated.
- for (int i = 0; i < root->size(); i++) {
- InnerDecklistNode *node = dynamic_cast(root->at(i));
- for (int j = 0; j < node->size(); j++) {
- DecklistCardNode *card = dynamic_cast(node->at(j));
- callback(node, card);
- }
- }
- }
+ void forEachCard(const std::function &func);
};
#endif
\ No newline at end of file
diff --git a/tests/loading_from_clipboard/clipboard_testing.cpp b/tests/loading_from_clipboard/clipboard_testing.cpp
index ad8db3dbf..b2021bde5 100644
--- a/tests/loading_from_clipboard/clipboard_testing.cpp
+++ b/tests/loading_from_clipboard/clipboard_testing.cpp
@@ -2,17 +2,6 @@
#include
-void Result::operator()(const InnerDecklistNode *innerDecklistNode, const DecklistCardNode *card)
-{
- if (innerDecklistNode->getName() == DECK_ZONE_MAIN) {
- mainboard.append({card->getName().toStdString(), card->getNumber()});
- } else if (innerDecklistNode->getName() == DECK_ZONE_SIDE) {
- sideboard.append({card->getName().toStdString(), card->getNumber()});
- } else {
- FAIL();
- }
-}
-
void testEmpty(const QString &clipboard)
{
QString cp(clipboard);
@@ -33,9 +22,22 @@ void testDeck(const QString &clipboard, const Result &result)
ASSERT_EQ(result.name, deckList.getName().toStdString());
ASSERT_EQ(result.comments, deckList.getComments().toStdString());
- Result decklistBuilder;
- deckList.forEachCard(decklistBuilder);
+ CardRows mainboard;
+ CardRows sideboard;
- ASSERT_EQ(result.mainboard, decklistBuilder.mainboard);
- ASSERT_EQ(result.sideboard, decklistBuilder.sideboard);
+ auto extractCards = [&mainboard, &sideboard](const InnerDecklistNode *innerDecklistNode,
+ const DecklistCardNode *card) {
+ if (innerDecklistNode->getName() == DECK_ZONE_MAIN) {
+ mainboard.append({card->getName().toStdString(), card->getNumber()});
+ } else if (innerDecklistNode->getName() == DECK_ZONE_SIDE) {
+ sideboard.append({card->getName().toStdString(), card->getNumber()});
+ } else {
+ FAIL();
+ }
+ };
+
+ deckList.forEachCard(extractCards);
+
+ ASSERT_EQ(result.mainboard, mainboard);
+ ASSERT_EQ(result.sideboard, sideboard);
}
diff --git a/tests/loading_from_clipboard/clipboard_testing.h b/tests/loading_from_clipboard/clipboard_testing.h
index 272801126..00d73b636 100644
--- a/tests/loading_from_clipboard/clipboard_testing.h
+++ b/tests/loading_from_clipboard/clipboard_testing.h
@@ -5,25 +5,20 @@
#include "gtest/gtest.h"
+// using std types because qt types aren't understood by gtest (without this you'll get less nice errors)
+using CardRows = QVector>;
+
struct Result
{
- // using std types because qt types aren't understood by gtest (without this you'll get less nice errors)
- using CardRows = QVector>;
std::string name;
std::string comments;
CardRows mainboard;
CardRows sideboard;
- Result()
- {
- }
-
Result(std::string _name, std::string _comments, CardRows _mainboard, CardRows _sideboard)
: name(_name), comments(_comments), mainboard(_mainboard), sideboard(_sideboard)
{
}
-
- void operator()(const InnerDecklistNode *innerDecklistNode, const DecklistCardNode *card);
};
void testEmpty(const QString &clipboard);
From 574ea01e084c9a49232a0773b4ead9ef7184abd7 Mon Sep 17 00:00:00 2001
From: lilyhuang-github <112970249+lilyhuang-github@users.noreply.github.com>
Date: Sun, 20 Apr 2025 00:08:00 -0400
Subject: [PATCH 07/56] update handling of keywords: AND, OR, NOT in card
search (#5788)
* update hnadling of keywords: AND, OR, NOT in card search
* added and
* update test
* update test
* update OR to not be [oO][rR] and just look for OR
* keyword testing
* adjusted new test
* implement test case for cards with keyword in name
* implement test case to cards with keyword in name
* format
* update test case
* change test cas
* update truth test case
* changed test card search from real cards to fake and added cards
* Update tests/carddatabase/data/cards.xml
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* Update tests/carddatabase/filter_string_test.cpp
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* Update tests/carddatabase/filter_string_test.cpp
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* update formatting
* update cardatabase_test to include +2 cards
* update test case +1 set + 1 type
---------
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
---
cockatrice/src/game/filters/filter_string.cpp | 6 ++---
tests/carddatabase/carddatabase_test.cpp | 6 ++---
tests/carddatabase/data/cards.xml | 26 +++++++++++++++++++
tests/carddatabase/filter_string_test.cpp | 15 ++++++++---
4 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/cockatrice/src/game/filters/filter_string.cpp b/cockatrice/src/game/filters/filter_string.cpp
index 7edfb0d41..01a7b6be9 100644
--- a/cockatrice/src/game/filters/filter_string.cpp
+++ b/cockatrice/src/game/filters/filter_string.cpp
@@ -10,15 +10,15 @@
peg::parser search(R"(
Start <- QueryPartList
~ws <- [ ]+
-QueryPartList <- ComplexQueryPart ( ws ("and" ws)? ComplexQueryPart)* ws*
+QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
-ComplexQueryPart <- SomewhatComplexQueryPart ws $or<[oO][rR]> ws ComplexQueryPart / SomewhatComplexQueryPart
+ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQuery / ToughnessQuery / ColorQuery / TypeQuery / OracleQuery / FieldQuery / GenericQuery
-NotQuery <- ('not' ws/'-') SomewhatComplexQueryPart
+NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
SetQuery <- ('e'/'set') [:] FlexStringValue
OracleQuery <- 'o' [:] RegexString
diff --git a/tests/carddatabase/carddatabase_test.cpp b/tests/carddatabase/carddatabase_test.cpp
index 752143f67..4818cd22e 100644
--- a/tests/carddatabase/carddatabase_test.cpp
+++ b/tests/carddatabase/carddatabase_test.cpp
@@ -18,9 +18,9 @@ TEST(CardDatabaseTest, LoadXml)
// load dummy cards and test result
db->loadCardDatabases();
- ASSERT_EQ(6, db->getCardList().size()) << "Wrong card count after load";
- ASSERT_EQ(3, db->getSetList().size()) << "Wrong sets count after load";
- ASSERT_EQ(2, db->getAllMainCardTypes().size()) << "Wrong types count after load";
+ ASSERT_EQ(8, db->getCardList().size()) << "Wrong card count after load";
+ ASSERT_EQ(4, db->getSetList().size()) << "Wrong sets count after load";
+ ASSERT_EQ(3, db->getAllMainCardTypes().size()) << "Wrong types count after load";
ASSERT_EQ(Ok, db->getLoadStatus()) << "Wrong status after load";
// ensure the card database is empty after clear()
diff --git a/tests/carddatabase/data/cards.xml b/tests/carddatabase/data/cards.xml
index 24ede9dff..e687689ec 100644
--- a/tests/carddatabase/data/cards.xml
+++ b/tests/carddatabase/data/cards.xml
@@ -31,5 +31,31 @@
4/4
+
+ Not Dead
+ Not a Card
+ 0
+ Dead!
+
+ 333
+ B
+ B
+ 1
+ Instant
+
+
+
+ Truth
+ Not a Card
+ 0
+ Truth!
+
+ 444
+ U
+ 2U
+ 2
+ Instant
+
+
diff --git a/tests/carddatabase/filter_string_test.cpp b/tests/carddatabase/filter_string_test.cpp
index 4fa139514..b29660159 100644
--- a/tests/carddatabase/filter_string_test.cpp
+++ b/tests/carddatabase/filter_string_test.cpp
@@ -19,11 +19,14 @@ protected:
void SetUp() override
{
cat = CardDatabaseManager::getInstance()->getCardBySimpleName("Cat");
+ notDeadAfterAll = CardDatabaseManager::getInstance()->getCardBySimpleName("Not Dead");
+ truth = CardDatabaseManager::getInstance()->getCardBySimpleName("Truth");
}
-
// void TearDown() override {}
CardData cat;
+ CardData notDeadAfterAll;
+ CardData truth;
};
QUERY(Empty, cat, "", true)
@@ -31,14 +34,18 @@ QUERY(Typing, cat, "t", true)
QUERY(NonMatchingType, cat, "t:kithkin", false)
QUERY(MatchingType, cat, "t:creature", true)
-QUERY(Not1, cat, "not t:kithkin", true)
-QUERY(Not2, cat, "not t:creature", false)
+QUERY(Not1, cat, "NOT t:kithkin", true)
+QUERY(Not2, cat, "NOT t:creature", false)
+QUERY(NonKeyword1, cat, "not t:kithkin", false)
+QUERY(NonKeyword2, cat, "t:bat or t:creature", false)
+QUERY(NonKeyword3, notDeadAfterAll, "not dead", true)
+QUERY(NonKeyword4, truth, "truth or trail", false)
QUERY(Case, cat, "t:cReAtUrE", true)
QUERY(And, cat, "t:creature t:creature", true)
QUERY(And2, cat, "t:creature t:sorcery", false)
-QUERY(Or, cat, "t:bat or t:creature", true)
+QUERY(Or, cat, "t:bat OR t:creature", true)
QUERY(Cmc1, cat, "cmc=2", true)
QUERY(Cmc2, cat, "cmc>3", false)
From aff4ffdf830b0d91da9e5cb19b9f0f93d49010d4 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:09:25 +0200
Subject: [PATCH 08/56] [GDE] Disable add tag button until text is entered.
(#5855)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Disable add tag button until text is entered.
* Reduce capture scope.
---------
Co-authored-by: Lukas Brübach
---
.../deck_preview/deck_preview_tag_dialog.cpp | 79 ++++++++++---------
.../deck_preview/deck_preview_tag_dialog.h | 14 ++--
2 files changed, 50 insertions(+), 43 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
index 815545aab..4d844f6f8 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp
@@ -11,7 +11,7 @@
#include
DeckPreviewTagDialog::DeckPreviewTagDialog(const QStringList &knownTags, const QStringList &activeTags, QWidget *parent)
- : QDialog(parent), activeTags_(activeTags)
+ : QDialog(parent), activeTags(activeTags)
{
resize(400, 500);
@@ -100,13 +100,13 @@ DeckPreviewTagDialog::DeckPreviewTagDialog(const QStringList &knownTags, const Q
combinedTags.removeDuplicates();
// Main layout
- auto *mainLayout = new QVBoxLayout(this);
+ mainLayout = new QVBoxLayout(this);
// Filter bar
- filterInput_ = new QLineEdit(this);
- mainLayout->addWidget(filterInput_);
+ filterInput = new QLineEdit(this);
+ mainLayout->addWidget(filterInput);
- connect(filterInput_, &QLineEdit::textChanged, this, &DeckPreviewTagDialog::filterTags);
+ connect(filterInput, &QLineEdit::textChanged, this, &DeckPreviewTagDialog::filterTags);
// Instruction label
instructionLabel = new QLabel(this);
@@ -114,31 +114,34 @@ DeckPreviewTagDialog::DeckPreviewTagDialog(const QStringList &knownTags, const Q
mainLayout->addWidget(instructionLabel);
// Tag list view
- tagListView_ = new QListWidget(this);
- mainLayout->addWidget(tagListView_);
+ tagListView = new QListWidget(this);
+ mainLayout->addWidget(tagListView);
// Populate combined tags
for (const auto &tag : combinedTags) {
- auto *item = new QListWidgetItem(tagListView_);
+ auto *item = new QListWidgetItem(tagListView);
auto *tagWidget = new DeckPreviewTagItemWidget(tag, activeTags.contains(tag), this);
- tagListView_->addItem(item);
- tagListView_->setItemWidget(item, tagWidget);
+ tagListView->addItem(item);
+ tagListView->setItemWidget(item, tagWidget);
connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged);
}
// Add tag input layout
- auto *addTagLayout = new QHBoxLayout();
- newTagInput_ = new QLineEdit(this);
- addTagButton_ = new QPushButton(this);
- addTagLayout->addWidget(newTagInput_);
- addTagLayout->addWidget(addTagButton_);
+ addTagLayout = new QHBoxLayout(this);
+ newTagInput = new QLineEdit(this);
+ addTagButton = new QPushButton(this);
+ addTagButton->setEnabled(false);
+ addTagLayout->addWidget(newTagInput);
+ addTagLayout->addWidget(addTagButton);
mainLayout->addLayout(addTagLayout);
- connect(addTagButton_, &QPushButton::clicked, this, &DeckPreviewTagDialog::addTag);
+ connect(addTagButton, &QPushButton::clicked, this, &DeckPreviewTagDialog::addTag);
+ connect(newTagInput, &QLineEdit::textChanged, this,
+ [this](const QString &text) { addTagButton->setEnabled(!text.trimmed().isEmpty()); });
// OK and Cancel buttons
- auto *buttonLayout = new QHBoxLayout();
+ buttonLayout = new QHBoxLayout(this);
okButton = new QPushButton(this);
cancelButton = new QPushButton(this);
buttonLayout->addStretch();
@@ -155,30 +158,30 @@ void DeckPreviewTagDialog::retranslateUi()
{
setWindowTitle(tr("Deck Tags Manager"));
instructionLabel->setText(tr("Manage your deck tags. Check or uncheck tags as needed, or add new ones:"));
- newTagInput_->setPlaceholderText(tr("Add a new tag (e.g., Aggro️)"));
- addTagButton_->setText(tr("Add Tag"));
- filterInput_->setPlaceholderText(tr("Filter tags..."));
+ newTagInput->setPlaceholderText(tr("Add a new tag (e.g., Aggro️)"));
+ addTagButton->setText(tr("Add Tag"));
+ filterInput->setPlaceholderText(tr("Filter tags..."));
okButton->setText(tr("OK"));
cancelButton->setText(tr("Cancel"));
}
QStringList DeckPreviewTagDialog::getActiveTags() const
{
- return activeTags_;
+ return activeTags;
}
void DeckPreviewTagDialog::addTag()
{
- QString newTag = newTagInput_->text().trimmed();
+ QString newTag = newTagInput->text().trimmed();
if (newTag.isEmpty()) {
QMessageBox::warning(this, tr("Invalid Input"), tr("Tag name cannot be empty!"));
return;
}
// Prevent duplicate tags
- for (int i = 0; i < tagListView_->count(); ++i) {
- auto *item = tagListView_->item(i);
- auto *tagWidget = qobject_cast(tagListView_->itemWidget(item));
+ for (int i = 0; i < tagListView->count(); ++i) {
+ auto *item = tagListView->item(i);
+ auto *tagWidget = qobject_cast(tagListView->itemWidget(item));
if (tagWidget && tagWidget->checkBox()->text() == newTag) {
QMessageBox::warning(this, tr("Duplicate Tag"), tr("This tag already exists."));
return;
@@ -186,23 +189,23 @@ void DeckPreviewTagDialog::addTag()
}
// Add the new tag
- auto *item = new QListWidgetItem(tagListView_);
+ auto *item = new QListWidgetItem(tagListView);
auto *tagWidget = new DeckPreviewTagItemWidget(newTag, true, this);
- tagListView_->addItem(item);
- tagListView_->setItemWidget(item, tagWidget);
- activeTags_.append(newTag);
+ tagListView->addItem(item);
+ tagListView->setItemWidget(item, tagWidget);
+ activeTags.append(newTag);
connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged);
// Clear the input field
- newTagInput_->clear();
+ newTagInput->clear();
}
void DeckPreviewTagDialog::filterTags(const QString &text)
{
- for (int i = 0; i < tagListView_->count(); ++i) {
- auto *item = tagListView_->item(i);
- auto *tagWidget = qobject_cast(tagListView_->itemWidget(item));
+ for (int i = 0; i < tagListView->count(); ++i) {
+ auto *item = tagListView->item(i);
+ auto *tagWidget = qobject_cast(tagListView->itemWidget(item));
if (tagWidget) {
bool matches = tagWidget->checkBox()->text().contains(text, Qt::CaseInsensitive);
item->setHidden(!matches);
@@ -212,12 +215,12 @@ void DeckPreviewTagDialog::filterTags(const QString &text)
void DeckPreviewTagDialog::onCheckboxStateChanged()
{
- activeTags_.clear();
- for (int i = 0; i < tagListView_->count(); ++i) {
- auto *item = tagListView_->item(i);
- auto *tagWidget = qobject_cast(tagListView_->itemWidget(item));
+ activeTags.clear();
+ for (int i = 0; i < tagListView->count(); ++i) {
+ auto *item = tagListView->item(i);
+ auto *tagWidget = qobject_cast(tagListView->itemWidget(item));
if (tagWidget && tagWidget->checkBox()->isChecked()) {
- activeTags_.append(tagWidget->checkBox()->text());
+ activeTags.append(tagWidget->checkBox()->text());
}
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h
index 8b528d445..9d6b5792b 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
class DeckPreviewTagDialog : public QDialog
{
@@ -26,14 +27,17 @@ private slots:
void retranslateUi();
private:
+ QVBoxLayout *mainLayout;
QLabel *instructionLabel;
- QListWidget *tagListView_;
- QLineEdit *filterInput_;
- QLineEdit *newTagInput_;
- QPushButton *addTagButton_;
+ QListWidget *tagListView;
+ QLineEdit *filterInput;
+ QHBoxLayout *addTagLayout;
+ QLineEdit *newTagInput;
+ QPushButton *addTagButton;
+ QHBoxLayout *buttonLayout;
QPushButton *okButton;
QPushButton *cancelButton;
- QStringList activeTags_;
+ QStringList activeTags;
};
#endif // DECK_PREVIEW_TAG_DIALOG_H
From 39f87a5e78ba383269a96825e50bd273b8f24c0b Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sat, 19 Apr 2025 21:10:32 -0700
Subject: [PATCH 09/56] VDS: Optimize refreshTags in
VisualDeckStorageTagFilterWidget (#5856)
* make methods const
* remove redundant calls to gatherAllTags
* make methods private
* use QSet instead of QStringList
---
.../visual_deck_storage_tag_filter_widget.cpp | 20 ++++++++++---------
.../visual_deck_storage_tag_filter_widget.h | 18 +++++++++--------
2 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
index 983ab13bd..25cb5a1e5 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
@@ -64,13 +64,13 @@ void VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList allTags = gatherAllTags();
+ removeTagsNotInList(allTags);
+ addTagsIfNotPresent(allTags);
sortTags();
}
-void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QStringList &tags)
+void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QSet &tags)
{
// Iterate through all DeckPreviewTagDisplayWidgets
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
@@ -83,7 +83,7 @@ void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QStringList &ta
}
}
-void VisualDeckStorageTagFilterWidget::addTagsIfNotPresent(const QStringList &tags)
+void VisualDeckStorageTagFilterWidget::addTagsIfNotPresent(const QSet &tags)
{
for (const QString &tag : tags) {
addTagIfNotPresent(tag);
@@ -136,20 +136,22 @@ void VisualDeckStorageTagFilterWidget::sortTags()
}
}
-QStringList VisualDeckStorageTagFilterWidget::gatherAllTags()
+QSet VisualDeckStorageTagFilterWidget::gatherAllTags() const
{
- QStringList allTags;
+ QSet allTags;
QList deckWidgets = parent->findChildren();
for (DeckPreviewWidget *widget : deckWidgets) {
if (widget->checkVisibility()) {
- allTags << widget->deckLoader->getTags();
+ for (const QString &tag : widget->deckLoader->getTags()) {
+ allTags.insert(tag);
+ }
}
}
return allTags;
}
-QStringList VisualDeckStorageTagFilterWidget::getAllKnownTags()
+QStringList VisualDeckStorageTagFilterWidget::getAllKnownTags() const
{
QStringList allTags;
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h
index a8726790e..3198e9769 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h
@@ -10,16 +10,18 @@ class VisualDeckStorageTagFilterWidget : public QWidget
{
Q_OBJECT
-public:
- explicit VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent);
- QStringList gatherAllTags();
- void filterDecksBySelectedTags(const QList &deckPreviews) const;
- void removeTagsNotInList(const QStringList &tags);
- void addTagsIfNotPresent(const QStringList &tags);
+ VisualDeckStorageWidget *parent;
+
+ QSet gatherAllTags() const;
+ void removeTagsNotInList(const QSet &tags);
+ void addTagsIfNotPresent(const QSet &tags);
void addTagIfNotPresent(const QString &tag);
void sortTags();
- QStringList getAllKnownTags();
- VisualDeckStorageWidget *parent;
+
+public:
+ explicit VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent);
+ QStringList getAllKnownTags() const;
+ void filterDecksBySelectedTags(const QList &deckPreviews) const;
public slots:
void refreshTags();
From 81a911dc112ff09cd287784c7446ed0aaf4dccc1 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:11:32 +0200
Subject: [PATCH 10/56] Add the option to hide banner card and tags in deck
editor. (#5857)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../deck_editor_deck_dock_widget.cpp | 39 +++++++++++++++++++
.../deck_editor_deck_dock_widget.h | 5 +++
cockatrice/src/settings/cache_settings.cpp | 17 ++++++++
cockatrice/src/settings/cache_settings.h | 14 +++++++
dbconverter/src/mocks.cpp | 7 ++++
tests/carddatabase/mocks.cpp | 7 ++++
6 files changed, 89 insertions(+)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index 0dd1b513f..9adf8e095 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -58,6 +58,28 @@ void DeckEditorDeckDockWidget::createDeckDock()
nameEdit->setObjectName("nameEdit");
nameLabel->setBuddy(nameEdit);
connect(nameEdit, &LineEditUnfocusable::textChanged, this, &DeckEditorDeckDockWidget::updateName);
+
+ quickSettingsWidget = new SettingsButtonWidget(this);
+
+ showBannerCardCheckBox = new QCheckBox();
+ showBannerCardCheckBox->setObjectName("showBannerCardCheckBox");
+ showBannerCardCheckBox->setChecked(SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
+ connect(showBannerCardCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setDeckEditorBannerCardComboBoxVisible);
+ connect(&SettingsCache::instance(), &SettingsCache::deckEditorBannerCardComboBoxVisibleChanged, this,
+ &DeckEditorDeckDockWidget::updateShowBannerCardComboBox);
+
+ showTagsWidgetCheckBox = new QCheckBox();
+ showTagsWidgetCheckBox->setObjectName("showTagsWidgetCheckBox");
+ showTagsWidgetCheckBox->setChecked(SettingsCache::instance().getDeckEditorTagsWidgetVisible());
+ connect(showTagsWidgetCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setDeckEditorTagsWidgetVisible);
+ connect(&SettingsCache::instance(), &SettingsCache::deckEditorTagsWidgetVisibleChanged, this,
+ &DeckEditorDeckDockWidget::updateShowTagsWidget);
+
+ quickSettingsWidget->addSettingsWidget(showBannerCardCheckBox);
+ quickSettingsWidget->addSettingsWidget(showTagsWidgetCheckBox);
+
commentsLabel = new QLabel();
commentsLabel->setObjectName("commentsLabel");
commentsEdit = new QTextEdit;
@@ -69,6 +91,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
bannerCardLabel = new QLabel();
bannerCardLabel->setObjectName("bannerCardLabel");
bannerCardLabel->setText(tr("Banner Card"));
+ bannerCardLabel->setHidden(SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
bannerCardComboBox = new QComboBox(this);
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
// Delay the update to avoid race conditions
@@ -76,8 +99,10 @@ void DeckEditorDeckDockWidget::createDeckDock()
});
connect(bannerCardComboBox, QOverload::of(&QComboBox::currentIndexChanged), this,
&DeckEditorDeckDockWidget::setBannerCard);
+ bannerCardComboBox->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckModel->getDeckList());
+ deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible());
aIncrement = new QAction(QString(), this);
aIncrement->setIcon(QPixmap("theme:icons/increment"));
@@ -109,6 +134,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
upperLayout->addWidget(nameLabel, 0, 0);
upperLayout->addWidget(nameEdit, 0, 1);
+ upperLayout->addWidget(quickSettingsWidget, 0, 2);
upperLayout->addWidget(commentsLabel, 1, 0);
upperLayout->addWidget(commentsEdit, 1, 1);
@@ -291,6 +317,17 @@ void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
emit deckChanged();
}
+void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
+{
+ bannerCardLabel->setHidden(!visible);
+ bannerCardComboBox->setHidden(!visible);
+}
+
+void DeckEditorDeckDockWidget::updateShowTagsWidget(const bool visible)
+{
+ deckTagsDisplayWidget->setHidden(!visible);
+}
+
/**
* Sets the currently active deck for this tab
* @param _deck The deck. Takes ownership of the object
@@ -526,6 +563,8 @@ void DeckEditorDeckDockWidget::retranslateUi()
setWindowTitle(tr("Deck"));
nameLabel->setText(tr("Deck &name:"));
+ showBannerCardCheckBox->setText(tr("Show banner card selection menu"));
+ showTagsWidgetCheckBox->setText(tr("Show tags selection menu"));
commentsLabel->setText(tr("&Comments:"));
hashLabel1->setText(tr("Hash:"));
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
index 89899b4bf..0a9ebcd65 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
@@ -57,6 +57,9 @@ private:
KeySignals deckViewKeySignals;
QLabel *nameLabel;
LineEditUnfocusable *nameEdit;
+ SettingsButtonWidget *quickSettingsWidget;
+ QCheckBox *showBannerCardCheckBox;
+ QCheckBox *showTagsWidgetCheckBox;
QLabel *commentsLabel;
QTextEdit *commentsEdit;
QLabel *bannerCardLabel;
@@ -77,6 +80,8 @@ private slots:
void setBannerCard(int);
void updateHash();
void refreshShortcuts();
+ void updateShowBannerCardComboBox(bool visible);
+ void updateShowTagsWidget(bool visible);
};
#endif // DECK_EDITOR_DECK_DOCK_WIDGET_H
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index 096ab23b8..fd4fafe87 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -263,6 +263,9 @@ SettingsCache::SettingsCache()
includeRebalancedCards = settings->value("cards/includerebalancedcards", true).toBool();
printingSelectorNavigationButtonsVisible =
settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
+ deckEditorBannerCardComboBoxVisible =
+ settings->value("interface/deckeditorbannercardcomboboxvisible", true).toBool();
+ deckEditorTagsWidgetVisible = settings->value("interface/deckeditortagswidgetvisible", true).toBool();
visualDeckStorageCardSize = settings->value("interface/visualdeckstoragecardsize", 100).toInt();
visualDeckStorageSortingOrder = settings->value("interface/visualdeckstoragesortingorder", 0).toInt();
visualDeckStorageShowFolders = settings->value("interface/visualdeckstorageshowfolders", true).toBool();
@@ -681,6 +684,20 @@ void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED
emit printingSelectorNavigationButtonsVisibleChanged();
}
+void SettingsCache::setDeckEditorBannerCardComboBoxVisible(QT_STATE_CHANGED_T _deckEditorBannerCardComboBoxVisible)
+{
+ deckEditorBannerCardComboBoxVisible = _deckEditorBannerCardComboBoxVisible;
+ settings->setValue("interface/deckeditorbannercardcomboboxvisible", deckEditorBannerCardComboBoxVisible);
+ emit deckEditorBannerCardComboBoxVisibleChanged(deckEditorBannerCardComboBoxVisible);
+}
+
+void SettingsCache::setDeckEditorTagsWidgetVisible(QT_STATE_CHANGED_T _deckEditorTagsWidgetVisible)
+{
+ deckEditorTagsWidgetVisible = _deckEditorTagsWidgetVisible;
+ settings->setValue("interface/deckeditortagswidgetvisible", deckEditorTagsWidgetVisible);
+ emit deckEditorTagsWidgetVisibleChanged(deckEditorTagsWidgetVisible);
+}
+
void SettingsCache::setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder)
{
visualDeckStorageSortingOrder = _visualDeckStorageSortingOrder;
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index 82625d9f7..64f8cc58a 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -61,6 +61,8 @@ signals:
void printingSelectorCardSizeChanged();
void includeRebalancedCardsChanged(bool _includeRebalancedCards);
void printingSelectorNavigationButtonsVisibleChanged();
+ void deckEditorBannerCardComboBoxVisibleChanged(bool _visible);
+ void deckEditorTagsWidgetVisibleChanged(bool _visible);
void visualDeckStorageShowTagFilterChanged(bool _visible);
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
@@ -134,6 +136,8 @@ private:
int printingSelectorCardSize;
bool includeRebalancedCards;
bool printingSelectorNavigationButtonsVisible;
+ bool deckEditorBannerCardComboBoxVisible;
+ bool deckEditorTagsWidgetVisible;
int visualDeckStorageSortingOrder;
bool visualDeckStorageShowFolders;
bool visualDeckStorageShowBannerCardComboBox;
@@ -420,6 +424,14 @@ public:
{
return printingSelectorNavigationButtonsVisible;
}
+ bool getDeckEditorBannerCardComboBoxVisible() const
+ {
+ return deckEditorBannerCardComboBoxVisible;
+ }
+ bool getDeckEditorTagsWidgetVisible() const
+ {
+ return deckEditorTagsWidgetVisible;
+ }
int getVisualDeckStorageSortingOrder() const
{
return visualDeckStorageSortingOrder;
@@ -800,6 +812,8 @@ public slots:
void setPrintingSelectorCardSize(int _printingSelectorCardSize);
void setIncludeRebalancedCards(bool _includeRebalancedCards);
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
+ void setDeckEditorBannerCardComboBoxVisible(QT_STATE_CHANGED_T _deckEditorBannerCardComboBoxVisible);
+ void setDeckEditorTagsWidgetVisible(QT_STATE_CHANGED_T _deckEditorTagsWidgetVisible);
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
void setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value);
void setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 53260e1fd..c4e716f48 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -208,6 +208,13 @@ void SettingsCache::setIncludeRebalancedCards(bool /* _includeRebalancedCards */
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
{
}
+void SettingsCache::setDeckEditorBannerCardComboBoxVisible(
+ QT_STATE_CHANGED_T /* _deckEditorBannerCardComboBoxVisible */)
+{
+}
+void SettingsCache::setDeckEditorTagsWidgetVisible(QT_STATE_CHANGED_T /* _deckEditorTagsWidgetVisible */)
+{
+}
void SettingsCache::setVisualDeckStorageSortingOrder(int /* _visualDeckStorageSortingOrder */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index c5cf99b68..35df750d3 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -212,6 +212,13 @@ void SettingsCache::setIncludeRebalancedCards(bool /* _includeRebalancedCards */
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T /* _navigationButtonsVisible */)
{
}
+void SettingsCache::setDeckEditorBannerCardComboBoxVisible(
+ QT_STATE_CHANGED_T /* _deckEditorBannerCardComboBoxVisible */)
+{
+}
+void SettingsCache::setDeckEditorTagsWidgetVisible(QT_STATE_CHANGED_T /* _deckEditorTagsWidgetVisible */)
+{
+}
void SettingsCache::setVisualDeckStorageSortingOrder(int /* _visualDeckStorageSortingOrder */)
{
}
From f98aad57d39a41131f4023d3af3906d5cc31f5d8 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:11:52 +0200
Subject: [PATCH 11/56] Add filter connection after toggling buttons and emit
on end. (#5858)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../visual_database_display_set_filter_widget.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
index 795c83d68..d4383f9e6 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
@@ -64,13 +64,13 @@ void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
setButtons[shortName] = button;
// Connect toggle signal
- connect(button, &QPushButton::toggled, this,
- [this, shortName](bool checked) { handleSetToggled(shortName, checked); });
if (setsActivated < setsToPreactivate) {
setsActivated++;
activeSets[shortName] = true;
button->setChecked(true);
}
+ connect(button, &QPushButton::toggled, this,
+ [this, shortName](bool checked) { handleSetToggled(shortName, checked); });
}
updateSetFilter();
updateSetButtonsVisibility(); // Ensure visibility is updated initially
From 82be0a8898dae86543e09e0244e3250427e1be99 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:12:16 +0200
Subject: [PATCH 12/56] Propagate display updates to found widgets. (#5860)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../card_group_display_widgets/card_group_display_widget.cpp | 2 +-
.../client/ui/widgets/cards/deck_card_zone_display_widget.cpp | 2 ++
.../ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp | 1 +
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
index 71569e92a..7e2caaccc 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
@@ -26,7 +26,7 @@ CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
banner = new BannerWidget(this, cardGroupCategory, Qt::Orientation::Vertical, bannerOpacity);
layout->addWidget(banner);
- updateCardDisplays();
+ CardGroupDisplayWidget::updateCardDisplays();
}
void CardGroupDisplayWidget::updateCardDisplays()
diff --git a/cockatrice/src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp b/cockatrice/src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp
index b074241fe..c5da91a2a 100644
--- a/cockatrice/src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp
@@ -93,6 +93,8 @@ void DeckCardZoneDisplayWidget::addCardGroupIfItDoesNotExist()
for (CardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
if (cardGroupDisplayWidget->cardGroupCategory == cardGroup) {
found = true;
+ cardGroupDisplayWidget->updateCardDisplays();
+ break;
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
index cf9c95071..5029d4a2d 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
@@ -227,6 +227,7 @@ void VisualDeckEditorWidget::addZoneIfDoesNotExist()
for (DeckCardZoneDisplayWidget *displayWidget : cardZoneDisplayWidgets) {
if (displayWidget->zoneName == zone) {
found = true;
+ displayWidget->displayCards();
break;
}
}
From 55bff6b52f8d010e543d1fa98ab6b1e5bf3d7854 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:12:30 +0200
Subject: [PATCH 13/56] Make sample hand flow widget a scrollbar one until we
figure out why non-scrollbar ones don't resize correctly. (#5861)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../visual_deck_editor_sample_hand_widget.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
index f6b73b0d5..7868627e2 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
@@ -16,7 +16,7 @@ VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *pare
connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay()));
layout->addWidget(resetButton);
- flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
+ flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
layout->addWidget(flowWidget);
for (CardInfoPtr card : getRandomCards(7)) {
From 795149e7760f8b0f1a5c7bcdbaa47a1eb0960715 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:12:46 +0200
Subject: [PATCH 14/56] Don't force size unnecessarily, correctly parent
scrollArea. (#5862)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../widgets/visual_deck_editor/visual_deck_editor_widget.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
index 5029d4a2d..0914a472e 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
@@ -29,7 +29,6 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_
connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorWidget::decklistDataChanged);
// The Main Widget and Main Layout, which contain a single Widget: The Scroll Area
- setMinimumSize(0, 0);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
mainLayout = new QVBoxLayout(this);
setLayout(mainLayout);
@@ -162,7 +161,7 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_
groupAndSortLayout->addWidget(sortCriteriaButton);
groupAndSortLayout->addWidget(displayTypeButton);
- scrollArea = new QScrollArea();
+ scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setMinimumSize(0, 0);
From acd9a163f0fe08a4b3bc5e384ed21ccc38b143f8 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:15:28 +0200
Subject: [PATCH 15/56] [VDD] Saner and more performant color filtering, allow
deleting specific filter from filterTree (#5863)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Saner and more performant color filtering.
* Update visual_database_display_color_filter_widget.cpp
---------
Co-authored-by: Lukas Brübach
Co-authored-by: Zach H
---
.../additional_info/mana_symbol_widget.cpp | 11 +-
.../additional_info/mana_symbol_widget.h | 6 +-
...l_database_display_color_filter_widget.cpp | 269 ++++++++++--------
...ual_database_display_color_filter_widget.h | 8 +-
cockatrice/src/game/filters/filter_tree.cpp | 25 ++
cockatrice/src/game/filters/filter_tree.h | 1 +
.../src/game/filters/filter_tree_model.cpp | 7 +
.../src/game/filters/filter_tree_model.h | 1 +
8 files changed, 198 insertions(+), 130 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
index dd4d1c1f6..e42e93444 100644
--- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
@@ -20,12 +20,17 @@ ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isAct
&ManaSymbolWidget::updateOpacity);
}
+void ManaSymbolWidget::toggleSymbol()
+{
+ setColorActive(!isActive);
+ emit colorToggled(getSymbolChar(), isActive);
+}
+
void ManaSymbolWidget::setColorActive(bool active)
{
if (isActive != active) {
isActive = active;
updateOpacity();
- emit colorToggled(getSymbolChar(), isActive);
}
}
@@ -46,9 +51,7 @@ void ManaSymbolWidget::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event);
if (mayBeToggled) {
- isActive = !isActive;
- updateOpacity();
- emit colorToggled(getSymbolChar(), isActive);
+ toggleSymbol();
}
}
diff --git a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h
index 6ecf54b34..02aaf6087 100644
--- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h
+++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h
@@ -11,9 +11,13 @@ class ManaSymbolWidget : public QLabel
public:
ManaSymbolWidget(QWidget *parent, QString symbol, bool isActive = true, bool mayBeToggled = false);
+ void toggleSymbol();
void setColorActive(bool active);
void updateOpacity();
- bool isColorActive() const;
+ bool isColorActive() const
+ {
+ return isActive;
+ };
QString getSymbol() const
{
return symbol;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
index e7dfd6f43..681282fc4 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
@@ -27,9 +27,6 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q
layout->addWidget(manaSymbol);
- // Initialize the activeColors map
- activeColors[color] = false;
-
// Connect the color toggled signal
connect(manaSymbol, &ManaSymbolWidget::colorToggled, this,
&VisualDatabaseDisplayColorFilterWidget::handleColorToggled);
@@ -41,16 +38,8 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q
// Connect the button's toggled signal
connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplayColorFilterWidget::updateFilterMode);
- connect(this, &VisualDatabaseDisplayColorFilterWidget::activeColorsChanged, this,
- &VisualDatabaseDisplayColorFilterWidget::updateColorFilter);
- connect(this, &VisualDatabaseDisplayColorFilterWidget::filterModeChanged, this,
- &VisualDatabaseDisplayColorFilterWidget::updateColorFilter);
- connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() {
- if (blockSync) {
- return; // Skip sync if we're blocking it
- }
- QTimer::singleShot(100, this, &VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel);
- });
+ connect(filterModel, &FilterTreeModel::layoutChanged, this,
+ [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel); });
// Call retranslateUi to set the initial text
retranslateUi();
@@ -73,91 +62,88 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
{
- activeColors[color] = active;
- emit activeColorsChanged(); // Notify listeners that the active colors have changed
+ if (active) {
+ addFilter(color);
+ } else {
+ removeFilter(color);
+ }
}
-void VisualDatabaseDisplayColorFilterWidget::updateColorFilter()
+void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
{
- blockSync = true;
+ QString colorString = color;
+ QString typeStr;
- // Clear previous filters
- filterModel->blockSignals(true);
- filterModel->filterTree()->blockSignals(true);
- filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
+ // Remove previous filters
- QSet selectedColors;
- QSet excludedColors;
+ QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
+ QList matchingFilters;
- // Collect active colors in the selected and excluded sets
- for (const auto &color : activeColors.keys()) {
- if (activeColors[color]) {
- selectedColors.insert(color); // Include this color
- } else {
- excludedColors.insert(color); // Exclude this color
+ for (const CardFilter *filter : allColorFilters) {
+ if (filter->term() == color) {
+ matchingFilters.append(filter);
}
}
+ for (const CardFilter *filter : matchingFilters) {
+ filterModel->removeFilter(filter);
+ }
+
+ // Add actual filter
+
switch (currentMode) {
case FilterMode::ExactMatch:
- // Exact Match Mode: Only selected colors are allowed
- if (!selectedColors.isEmpty()) {
- // Require all selected colors (TypeAnd)
- for (const auto &color : selectedColors) {
- QString colorString = color;
- filterModel->addFilter(
- new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
- }
-
- // Exclude all other colors
- QStringList allPossibleColors = {"W", "U", "B", "R", "G"};
- for (const auto &color : allPossibleColors) {
- if (!selectedColors.contains(color)) {
- QString colorString = color;
- filterModel->addFilter(
- new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
- }
- }
- }
+ filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
break;
case FilterMode::Includes:
- // Includes Mode: Just include selected colors without restrictions
- for (const auto &color : selectedColors) {
- QString colorString = color;
- filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr,
- CardFilter::Attr::AttrColor)); // OR for selected colors
- }
+ filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
break;
case FilterMode::IncludeExclude:
- // Include/Exclude Mode: Include selected colors and exclude unselected colors
- for (const auto &color : selectedColors) {
- QString colorString = color;
- filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr,
- CardFilter::Attr::AttrColor)); // OR for selected colors
- }
- for (const auto &color : excludedColors) {
- QString colorString = color;
- filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAndNot,
- CardFilter::Attr::AttrColor)); // AND NOT for excluded colors
- }
+ filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
break;
}
+}
- filterModel->blockSignals(false);
- filterModel->filterTree()->blockSignals(false);
+void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
+{
+ QString colorString = color;
- emit filterModel->filterTree()->changed();
- emit filterModel->layoutChanged();
+ // Remove inclusion filters
+ QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
+ QList matchingFilters;
- blockSync = false;
+ for (const CardFilter *filter : allColorFilters) {
+ if (filter->term() == color) {
+ matchingFilters.append(filter);
+ }
+ }
+
+ for (const CardFilter *filter : matchingFilters) {
+ filterModel->removeFilter(filter);
+ }
+
+ // Add exclusion filters if the mode demands it
+ switch (currentMode) {
+ case FilterMode::ExactMatch:
+ filterModel->addFilter(
+ new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
+ break;
+
+ case FilterMode::IncludeExclude:
+ filterModel->addFilter(
+ new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
+ break;
+
+ case FilterMode::Includes:
+ // No exclusion in Includes mode
+ break;
+ }
}
void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
{
- blockSync = true;
-
switch (currentMode) {
case FilterMode::ExactMatch:
currentMode = FilterMode::Includes; // Switch to Includes
@@ -170,59 +156,100 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
break;
}
- retranslateUi(); // Update button text based on the mode
- emit filterModeChanged(currentMode); // Signal mode change
- updateColorFilter(); // Reapply the filter based on the new mode
+ filterModel->blockSignals(true);
+ filterModel->filterTree()->blockSignals(true);
- blockSync = false;
-}
-
-void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
-{
- blockSync = true;
- QSet currentFilters;
-
- // Get current filters of type color
- for (const auto &filter : filterModel->getFiltersOfType(CardFilter::Attr::AttrColor)) {
- if (filter->type() == CardFilter::Type::TypeAnd || filter->type() == CardFilter::Type::TypeOr) {
- currentFilters.insert(filter->term());
- }
- }
-
- QSet activeFilterList;
-
- // Iterate over the activeColors map and collect the active colors as strings
- for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) {
- if (it.value()) { // Only add active colors
- activeFilterList.insert(QString(it.key()));
- }
- }
-
- // Check if the filters in the model match the active filters
- if (currentFilters == activeFilterList) {
- return;
- }
-
- // Remove filters that are in the UI but not in the model
- for (const auto &color : activeFilterList) {
- if (!currentFilters.contains(color)) {
- activeColors[color[0]] = false; // Disable the color
- }
- }
-
- // Add filters that are in the model but not in the UI
- for (const auto &color : currentFilters) {
- if (!activeFilterList.contains(color)) {
- activeColors[color[0]] = true; // Enable the color
- }
- }
+ filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
QList manaSymbolWidgets = findChildren();
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
- manaSymbolWidget->setColorActive(activeColors[manaSymbolWidget->getSymbolChar()]);
+ handleColorToggled(manaSymbolWidget->getSymbolChar(), manaSymbolWidget->isColorActive());
}
- updateColorFilter();
- blockSync = false;
-}
\ No newline at end of file
+ filterModel->blockSignals(false);
+ filterModel->filterTree()->blockSignals(false);
+
+ emit filterModel->filterTree()->changed();
+ emit filterModel->layoutChanged();
+
+ retranslateUi(); // Update button text based on the mode
+ emit filterModeChanged(currentMode); // Signal mode change
+}
+
+void VisualDatabaseDisplayColorFilterWidget::setManaSymbolActive(QChar color, bool active)
+{
+ QList manaSymbolWidgets = findChildren();
+
+ for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
+ if (manaSymbolWidget->getSymbolChar() == color) {
+ manaSymbolWidget->setColorActive(active);
+ }
+ }
+}
+
+QList VisualDatabaseDisplayColorFilterWidget::getActiveColors()
+{
+ QList activeColors;
+ QList manaSymbolWidgets = findChildren();
+
+ for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
+ if (manaSymbolWidget->isColorActive()) {
+ activeColors.append(manaSymbolWidget->getSymbolChar());
+ }
+ }
+
+ return activeColors;
+}
+
+void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
+{
+ QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
+
+ QList manaSymbolWidgets = findChildren();
+
+ for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
+ bool found = false;
+ for (const CardFilter *filter : allColorFilters) {
+ if (manaSymbolWidget->getSymbolChar() == filter->term()) {
+ switch (currentMode) {
+ case FilterMode::ExactMatch:
+ switch (filter->type()) {
+ case CardFilter::Type::TypeAnd:
+ setManaSymbolActive(filter->term().at(0), true);
+ break;
+ default:
+ setManaSymbolActive(filter->term().at(0), false);
+ break;
+ }
+ break;
+ case FilterMode::Includes:
+ switch (filter->type()) {
+ case CardFilter::Type::TypeOr:
+ setManaSymbolActive(filter->term().at(0), true);
+ break;
+ default:
+ setManaSymbolActive(filter->term().at(0), false);
+ break;
+ }
+ break;
+ case FilterMode::IncludeExclude:
+ switch (filter->type()) {
+ case CardFilter::Type::TypeOr:
+ setManaSymbolActive(filter->term().at(0), true);
+ break;
+ default:
+ setManaSymbolActive(filter->term().at(0), false);
+ break;
+ }
+ break;
+ }
+ found = true;
+ }
+ }
+
+ if (!found) {
+ setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false);
+ }
+ }
+}
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h
index 191d00eee..3936c8843 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h
@@ -43,21 +43,21 @@ public:
signals:
void filterModeChanged(FilterMode filterMode);
- void activeColorsChanged();
private slots:
void handleColorToggled(QChar color, bool active);
- void updateColorFilter();
+ void addFilter(QChar color);
+ void removeFilter(QChar color);
void updateFilterMode();
+ void setManaSymbolActive(QChar color, bool active);
+ QList getActiveColors();
void syncWithFilterModel();
private:
FilterTreeModel *filterModel;
QHBoxLayout *layout;
QPushButton *toggleButton;
- QMap activeColors;
FilterMode currentMode = FilterMode::Includes; // Default mode
- bool blockSync = false;
};
#endif // VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H
diff --git a/cockatrice/src/game/filters/filter_tree.cpp b/cockatrice/src/game/filters/filter_tree.cpp
index 170fb35d8..4e65fc06e 100644
--- a/cockatrice/src/game/filters/filter_tree.cpp
+++ b/cockatrice/src/game/filters/filter_tree.cpp
@@ -531,6 +531,31 @@ void FilterTree::removeFiltersByAttr(CardFilter::Attr filterType)
}
}
+void FilterTree::removeFilter(const CardFilter *toRemove)
+{
+ for (int i = childNodes.size() - 1; i >= 0; --i) {
+ auto *logicMap = dynamic_cast(childNodes.at(i));
+ if (!logicMap || logicMap->attr != toRemove->attr())
+ continue;
+
+ FilterItemList *typeList = logicMap->typeList(toRemove->type());
+ if (!typeList)
+ continue;
+
+ int termIdx = typeList->termIndex(toRemove->term());
+ if (termIdx != -1) {
+ typeList->deleteAt(termIdx);
+ emit typeList->nodeChanged();
+ if (typeList->childCount() == 0) {
+ int logicIndex = logicMap->childIndex(typeList);
+ if (logicIndex != -1) {
+ logicMap->deleteAt(logicIndex);
+ }
+ }
+ }
+ }
+}
+
void FilterTree::clear()
{
while (childCount() > 0) {
diff --git a/cockatrice/src/game/filters/filter_tree.h b/cockatrice/src/game/filters/filter_tree.h
index 895e1c1f7..394e98e7b 100644
--- a/cockatrice/src/game/filters/filter_tree.h
+++ b/cockatrice/src/game/filters/filter_tree.h
@@ -270,6 +270,7 @@ public:
bool acceptsCard(CardInfoPtr info) const;
void removeFiltersByAttr(CardFilter::Attr filterType);
+ void removeFilter(const CardFilter *toRemove);
void clear();
};
diff --git a/cockatrice/src/game/filters/filter_tree_model.cpp b/cockatrice/src/game/filters/filter_tree_model.cpp
index ec98f7c98..c4ce3aa35 100644
--- a/cockatrice/src/game/filters/filter_tree_model.cpp
+++ b/cockatrice/src/game/filters/filter_tree_model.cpp
@@ -78,6 +78,13 @@ void FilterTreeModel::addFilter(const CardFilter *f)
emit layoutChanged();
}
+void FilterTreeModel::removeFilter(const CardFilter *f)
+{
+ emit layoutAboutToBeChanged();
+ fTree->removeFilter(f);
+ emit layoutChanged();
+}
+
void FilterTreeModel::clearFiltersOfType(CardFilter::Attr filterType)
{
emit layoutAboutToBeChanged();
diff --git a/cockatrice/src/game/filters/filter_tree_model.h b/cockatrice/src/game/filters/filter_tree_model.h
index 4e98aa02a..89547e7a2 100644
--- a/cockatrice/src/game/filters/filter_tree_model.h
+++ b/cockatrice/src/game/filters/filter_tree_model.h
@@ -17,6 +17,7 @@ private:
public slots:
void addFilter(const CardFilter *f);
+ void removeFilter(const CardFilter *f);
void clearFiltersOfType(CardFilter::Attr filterType);
QList getFiltersOfType(CardFilter::Attr filterType) const;
QList allFilters() const;
From dcbb8bab7553ddf350410806e72eac1c11184641 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 06:17:25 +0200
Subject: [PATCH 16/56] [VDD] Defer filter tree assignment (#5864)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* RetranslateUi instead of updating filter mode.
* Defer setting the filter tree on the database display model until AFTER all the filter widgets are initialized.
* Update visual_database_display_set_filter_widget.cpp
---------
Co-authored-by: Lukas Brübach
Co-authored-by: Zach H
---
.../visual_database_display_set_filter_widget.cpp | 13 +++++++++----
.../visual_database_display_set_filter_widget.h | 1 +
.../visual_database_display_widget.cpp | 7 ++++---
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
index d4383f9e6..4914d927e 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
@@ -36,8 +36,13 @@ VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidg
connect(filterModel, &FilterTreeModel::layoutChanged, this,
[this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel); });
- createSetButtons(); // Populate buttons initially
- updateFilterMode(false); // Initialize toggle button text
+ createSetButtons(); // Populate buttons initially
+ retranslateUi();
+}
+
+void VisualDatabaseDisplaySetFilterWidget::retranslateUi()
+{
+ toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
}
void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
@@ -190,6 +195,6 @@ void VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel()
void VisualDatabaseDisplaySetFilterWidget::updateFilterMode(bool checked)
{
exactMatchMode = checked;
- toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
updateSetFilter();
-}
\ No newline at end of file
+ retranslateUi();
+}
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h
index 41da57ef8..2e63b3fdf 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplaySetFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplaySetFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createSetButtons();
void updateSetButtonsVisibility();
void handleSetToggled(const QString &setShortName, bool active);
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
index 18369224b..9d82463be 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
@@ -62,9 +62,6 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
filterModel = new FilterTreeModel();
filterModel->setObjectName("filterModel");
- databaseDisplayModel->setFilterTree(filterModel->filterTree());
-
- connect(filterModel, &FilterTreeModel::layoutChanged, this, &VisualDatabaseDisplayWidget::searchModelChanged);
searchKeySignals.setObjectName("searchKeySignals");
connect(searchEdit, &QLineEdit::textChanged, this, &VisualDatabaseDisplayWidget::updateSearch);
@@ -144,6 +141,10 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
connect(debounceTimer, &QTimer::timeout, this, &VisualDatabaseDisplayWidget::searchModelChanged);
+ databaseDisplayModel->setFilterTree(filterModel->filterTree());
+
+ connect(filterModel, &FilterTreeModel::layoutChanged, this, &VisualDatabaseDisplayWidget::searchModelChanged);
+
loadCardsTimer = new QTimer(this);
loadCardsTimer->setSingleShot(true); // Ensure it only fires once after the timeout
From 6b39f6f6fa6ad7cd0c30b8293f0e2e0d2c826452 Mon Sep 17 00:00:00 2001
From: ebbit1q
Date: Sun, 20 Apr 2025 16:36:38 +0200
Subject: [PATCH 17/56] fix indenting in test cards.xml (#5866)
---
tests/carddatabase/data/cards.xml | 52 +++++++++++++++----------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/tests/carddatabase/data/cards.xml b/tests/carddatabase/data/cards.xml
index e687689ec..f235ab4f9 100644
--- a/tests/carddatabase/data/cards.xml
+++ b/tests/carddatabase/data/cards.xml
@@ -31,31 +31,31 @@
4/4
-
- Not Dead
- Not a Card
- 0
- Dead!
-
- 333
- B
- B
- 1
- Instant
-
-
-
- Truth
- Not a Card
- 0
- Truth!
-
- 444
- U
- 2U
- 2
- Instant
-
-
+
+ Not Dead
+ Not a Card
+ 0
+ Dead!
+
+ 333
+ B
+ B
+ 1
+ Instant
+
+
+
+ Truth
+ Not a Card
+ 0
+ Truth!
+
+ 444
+ U
+ 2U
+ 2
+ Instant
+
+
From 44ac782978426defc998e0aa4ba3c159d0eaa3d1 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 20 Apr 2025 07:37:52 -0700
Subject: [PATCH 18/56] Move card_item and related to src/game/board (#5867)
* move files
* update includes
* update cmake
---
cockatrice/CMakeLists.txt | 10 +++++-----
cockatrice/src/client/tabs/tab_game.cpp | 2 +-
.../ui/widgets/cards/card_info_display_widget.cpp | 2 +-
.../client/ui/widgets/cards/card_info_frame_widget.cpp | 2 +-
.../ui/widgets/cards/card_info_picture_widget.cpp | 2 +-
.../client/ui/widgets/cards/card_info_text_widget.cpp | 2 +-
.../game/{cards => board}/abstract_card_drag_item.cpp | 0
.../game/{cards => board}/abstract_card_drag_item.h | 0
.../src/game/{cards => board}/abstract_card_item.cpp | 4 ++--
.../src/game/{cards => board}/abstract_card_item.h | 4 ++--
cockatrice/src/game/board/arrow_item.cpp | 2 +-
.../src/game/{cards => board}/card_drag_item.cpp | 0
cockatrice/src/game/{cards => board}/card_drag_item.h | 0
cockatrice/src/game/{cards => board}/card_item.cpp | 4 ++--
cockatrice/src/game/{cards => board}/card_item.h | 0
cockatrice/src/game/{cards => board}/card_list.cpp | 2 +-
cockatrice/src/game/{cards => board}/card_list.h | 0
cockatrice/src/game/deckview/deck_view.h | 2 +-
cockatrice/src/game/game_scene.cpp | 2 +-
cockatrice/src/game/player/player.cpp | 4 ++--
cockatrice/src/game/zones/card_zone.cpp | 2 +-
cockatrice/src/game/zones/card_zone.h | 2 +-
cockatrice/src/game/zones/hand_zone.cpp | 4 ++--
cockatrice/src/game/zones/pile_zone.cpp | 4 ++--
cockatrice/src/game/zones/select_zone.cpp | 2 +-
cockatrice/src/game/zones/stack_zone.cpp | 4 ++--
cockatrice/src/game/zones/table_zone.cpp | 4 ++--
cockatrice/src/game/zones/table_zone.h | 2 +-
cockatrice/src/game/zones/view_zone.cpp | 4 ++--
cockatrice/src/game/zones/view_zone_widget.cpp | 2 +-
cockatrice/src/server/message_log_widget.cpp | 2 +-
31 files changed, 38 insertions(+), 38 deletions(-)
rename cockatrice/src/game/{cards => board}/abstract_card_drag_item.cpp (100%)
rename cockatrice/src/game/{cards => board}/abstract_card_drag_item.h (100%)
rename cockatrice/src/game/{cards => board}/abstract_card_item.cpp (99%)
rename cockatrice/src/game/{cards => board}/abstract_card_item.h (98%)
rename cockatrice/src/game/{cards => board}/card_drag_item.cpp (100%)
rename cockatrice/src/game/{cards => board}/card_drag_item.h (100%)
rename cockatrice/src/game/{cards => board}/card_item.cpp (99%)
rename cockatrice/src/game/{cards => board}/card_item.h (100%)
rename cockatrice/src/game/{cards => board}/card_list.cpp (99%)
rename cockatrice/src/game/{cards => board}/card_list.h (100%)
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 110c99697..2b9a10113 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -168,13 +168,16 @@ set(cockatrice_SOURCES
src/dialogs/dlg_tip_of_the_day.cpp
src/dialogs/dlg_update.cpp
src/dialogs/dlg_view_log.cpp
+ src/game/board/abstract_card_drag_item.cpp
+ src/game/board/abstract_card_item.cpp
src/game/board/abstract_counter.cpp
src/game/board/abstract_graphics_item.cpp
src/game/board/arrow_item.cpp
src/game/board/arrow_target.cpp
+ src/game/board/card_drag_item.cpp
+ src/game/board/card_item.cpp
+ src/game/board/card_list.cpp
src/game/board/counter_general.cpp
- src/game/cards/abstract_card_drag_item.cpp
- src/game/cards/abstract_card_item.cpp
src/game/cards/card_completer_proxy_model.cpp
src/game/cards/card_database.cpp
src/game/cards/card_database_manager.cpp
@@ -182,10 +185,7 @@ set(cockatrice_SOURCES
src/game/cards/card_database_parser/card_database_parser.cpp
src/game/cards/card_database_parser/cockatrice_xml_3.cpp
src/game/cards/card_database_parser/cockatrice_xml_4.cpp
- src/game/cards/card_drag_item.cpp
src/game/cards/card_info.cpp
- src/game/cards/card_item.cpp
- src/game/cards/card_list.cpp
src/game/cards/card_search_model.cpp
src/game/deckview/deck_view.cpp
src/game/deckview/deck_view_container.cpp
diff --git a/cockatrice/src/client/tabs/tab_game.cpp b/cockatrice/src/client/tabs/tab_game.cpp
index e01153d00..999b5b164 100644
--- a/cockatrice/src/client/tabs/tab_game.cpp
+++ b/cockatrice/src/client/tabs/tab_game.cpp
@@ -3,9 +3,9 @@
#include "../../client/ui/widgets/cards/card_info_frame_widget.h"
#include "../../dialogs/dlg_create_game.h"
#include "../../game/board/arrow_item.h"
+#include "../../game/board/card_item.h"
#include "../../game/cards/card_database.h"
#include "../../game/cards/card_database_manager.h"
-#include "../../game/cards/card_item.h"
#include "../../game/deckview/deck_view_container.h"
#include "../../game/game_scene.h"
#include "../../game/game_view.h"
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_display_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_display_widget.cpp
index d967c8477..ab6a9eb31 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_display_widget.cpp
@@ -1,7 +1,7 @@
#include "card_info_display_widget.h"
+#include "../../../../game/board/card_item.h"
#include "../../../../game/cards/card_database_manager.h"
-#include "../../../../game/cards/card_item.h"
#include "../../../../main.h"
#include "card_info_picture_widget.h"
#include "card_info_text_widget.h"
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_frame_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_frame_widget.cpp
index 4d85f38a0..08eafbf87 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_frame_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_frame_widget.cpp
@@ -1,7 +1,7 @@
#include "card_info_frame_widget.h"
+#include "../../../../game/board/card_item.h"
#include "../../../../game/cards/card_database_manager.h"
-#include "../../../../game/cards/card_item.h"
#include "../../../../settings/cache_settings.h"
#include "card_info_display_widget.h"
#include "card_info_picture_widget.h"
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
index 4d76989b1..4ee3de5eb 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
@@ -1,7 +1,7 @@
#include "card_info_picture_widget.h"
+#include "../../../../game/board/card_item.h"
#include "../../../../game/cards/card_database_manager.h"
-#include "../../../../game/cards/card_item.h"
#include "../../../../settings/cache_settings.h"
#include "../../../tabs/tab_supervisor.h"
#include "../../picture_loader/picture_loader.h"
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_text_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_text_widget.cpp
index 82944205f..5201bea2c 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_text_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_text_widget.cpp
@@ -1,6 +1,6 @@
#include "card_info_text_widget.h"
-#include "../../../../game/cards/card_item.h"
+#include "../../../../game/board/card_item.h"
#include "../../../../game/game_specific_terms.h"
#include
diff --git a/cockatrice/src/game/cards/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp
similarity index 100%
rename from cockatrice/src/game/cards/abstract_card_drag_item.cpp
rename to cockatrice/src/game/board/abstract_card_drag_item.cpp
diff --git a/cockatrice/src/game/cards/abstract_card_drag_item.h b/cockatrice/src/game/board/abstract_card_drag_item.h
similarity index 100%
rename from cockatrice/src/game/cards/abstract_card_drag_item.h
rename to cockatrice/src/game/board/abstract_card_drag_item.h
diff --git a/cockatrice/src/game/cards/abstract_card_item.cpp b/cockatrice/src/game/board/abstract_card_item.cpp
similarity index 99%
rename from cockatrice/src/game/cards/abstract_card_item.cpp
rename to cockatrice/src/game/board/abstract_card_item.cpp
index dc00aae66..0623afb07 100644
--- a/cockatrice/src/game/cards/abstract_card_item.cpp
+++ b/cockatrice/src/game/board/abstract_card_item.cpp
@@ -2,9 +2,9 @@
#include "../../client/ui/picture_loader/picture_loader.h"
#include "../../settings/cache_settings.h"
+#include "../cards/card_database.h"
+#include "../cards/card_database_manager.h"
#include "../game_scene.h"
-#include "card_database.h"
-#include "card_database_manager.h"
#include
#include
diff --git a/cockatrice/src/game/cards/abstract_card_item.h b/cockatrice/src/game/board/abstract_card_item.h
similarity index 98%
rename from cockatrice/src/game/cards/abstract_card_item.h
rename to cockatrice/src/game/board/abstract_card_item.h
index 48f890701..94de7596a 100644
--- a/cockatrice/src/game/cards/abstract_card_item.h
+++ b/cockatrice/src/game/board/abstract_card_item.h
@@ -1,8 +1,8 @@
#ifndef ABSTRACTCARDITEM_H
#define ABSTRACTCARDITEM_H
-#include "../board/arrow_target.h"
-#include "card_info.h"
+#include "../cards/card_info.h"
+#include "arrow_target.h"
class Player;
diff --git a/cockatrice/src/game/board/arrow_item.cpp b/cockatrice/src/game/board/arrow_item.cpp
index 2be8fbdd8..4caebdda0 100644
--- a/cockatrice/src/game/board/arrow_item.cpp
+++ b/cockatrice/src/game/board/arrow_item.cpp
@@ -3,10 +3,10 @@
#include "../../settings/cache_settings.h"
#include "../cards/card_info.h"
-#include "../cards/card_item.h"
#include "../player/player.h"
#include "../player/player_target.h"
#include "../zones/card_zone.h"
+#include "card_item.h"
#include "color.h"
#include "pb/command_attach_card.pb.h"
#include "pb/command_create_arrow.pb.h"
diff --git a/cockatrice/src/game/cards/card_drag_item.cpp b/cockatrice/src/game/board/card_drag_item.cpp
similarity index 100%
rename from cockatrice/src/game/cards/card_drag_item.cpp
rename to cockatrice/src/game/board/card_drag_item.cpp
diff --git a/cockatrice/src/game/cards/card_drag_item.h b/cockatrice/src/game/board/card_drag_item.h
similarity index 100%
rename from cockatrice/src/game/cards/card_drag_item.h
rename to cockatrice/src/game/board/card_drag_item.h
diff --git a/cockatrice/src/game/cards/card_item.cpp b/cockatrice/src/game/board/card_item.cpp
similarity index 99%
rename from cockatrice/src/game/cards/card_item.cpp
rename to cockatrice/src/game/board/card_item.cpp
index 40fa8d119..e9a345e86 100644
--- a/cockatrice/src/game/cards/card_item.cpp
+++ b/cockatrice/src/game/board/card_item.cpp
@@ -2,14 +2,14 @@
#include "../../client/tabs/tab_game.h"
#include "../../settings/cache_settings.h"
-#include "../board/arrow_item.h"
+#include "../cards/card_info.h"
#include "../game_scene.h"
#include "../player/player.h"
#include "../zones/card_zone.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
+#include "arrow_item.h"
#include "card_drag_item.h"
-#include "card_info.h"
#include "pb/serverinfo_card.pb.h"
#include
diff --git a/cockatrice/src/game/cards/card_item.h b/cockatrice/src/game/board/card_item.h
similarity index 100%
rename from cockatrice/src/game/cards/card_item.h
rename to cockatrice/src/game/board/card_item.h
diff --git a/cockatrice/src/game/cards/card_list.cpp b/cockatrice/src/game/board/card_list.cpp
similarity index 99%
rename from cockatrice/src/game/cards/card_list.cpp
rename to cockatrice/src/game/board/card_list.cpp
index 0eda14626..0355bf6bd 100644
--- a/cockatrice/src/game/cards/card_list.cpp
+++ b/cockatrice/src/game/board/card_list.cpp
@@ -1,6 +1,6 @@
#include "card_list.h"
-#include "card_info.h"
+#include "../cards/card_info.h"
#include "card_item.h"
#include
diff --git a/cockatrice/src/game/cards/card_list.h b/cockatrice/src/game/board/card_list.h
similarity index 100%
rename from cockatrice/src/game/cards/card_list.h
rename to cockatrice/src/game/board/card_list.h
diff --git a/cockatrice/src/game/deckview/deck_view.h b/cockatrice/src/game/deckview/deck_view.h
index 777298714..6fa47766f 100644
--- a/cockatrice/src/game/deckview/deck_view.h
+++ b/cockatrice/src/game/deckview/deck_view.h
@@ -1,7 +1,7 @@
#ifndef DECKVIEW_H
#define DECKVIEW_H
-#include "../../game/cards/abstract_card_drag_item.h"
+#include "../board/abstract_card_drag_item.h"
#include "pb/move_card_to_zone.pb.h"
#include
diff --git a/cockatrice/src/game/game_scene.cpp b/cockatrice/src/game/game_scene.cpp
index afd6cc815..ba54d5b0c 100644
--- a/cockatrice/src/game/game_scene.cpp
+++ b/cockatrice/src/game/game_scene.cpp
@@ -2,7 +2,7 @@
#include "../client/ui/phases_toolbar.h"
#include "../settings/cache_settings.h"
-#include "cards/card_item.h"
+#include "board/card_item.h"
#include "player/player.h"
#include "zones/view_zone.h"
#include "zones/view_zone_widget.h"
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index 26f34e977..e4d319633 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -9,11 +9,11 @@
#include "../../main.h"
#include "../../settings/cache_settings.h"
#include "../board/arrow_item.h"
+#include "../board/card_item.h"
+#include "../board/card_list.h"
#include "../board/counter_general.h"
#include "../cards/card_database.h"
#include "../cards/card_database_manager.h"
-#include "../cards/card_item.h"
-#include "../cards/card_list.h"
#include "../game_scene.h"
#include "../hand_counter.h"
#include "../zones/card_zone.h"
diff --git a/cockatrice/src/game/zones/card_zone.cpp b/cockatrice/src/game/zones/card_zone.cpp
index 7516923b0..24eaa4f52 100644
--- a/cockatrice/src/game/zones/card_zone.cpp
+++ b/cockatrice/src/game/zones/card_zone.cpp
@@ -1,7 +1,7 @@
#include "card_zone.h"
+#include "../board/card_item.h"
#include "../cards/card_database_manager.h"
-#include "../cards/card_item.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
#include "pb/serverinfo_user.pb.h"
diff --git a/cockatrice/src/game/zones/card_zone.h b/cockatrice/src/game/zones/card_zone.h
index 91cad179c..2b9114a6d 100644
--- a/cockatrice/src/game/zones/card_zone.h
+++ b/cockatrice/src/game/zones/card_zone.h
@@ -3,7 +3,7 @@
#include "../../client/translation.h"
#include "../board/abstract_graphics_item.h"
-#include "../cards/card_list.h"
+#include "../board/card_list.h"
#include
#include
diff --git a/cockatrice/src/game/zones/hand_zone.cpp b/cockatrice/src/game/zones/hand_zone.cpp
index 31f0515d4..1bc029432 100644
--- a/cockatrice/src/game/zones/hand_zone.cpp
+++ b/cockatrice/src/game/zones/hand_zone.cpp
@@ -2,8 +2,8 @@
#include "../../client/ui/theme_manager.h"
#include "../../settings/cache_settings.h"
-#include "../cards/card_drag_item.h"
-#include "../cards/card_item.h"
+#include "../board/card_drag_item.h"
+#include "../board/card_item.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
diff --git a/cockatrice/src/game/zones/pile_zone.cpp b/cockatrice/src/game/zones/pile_zone.cpp
index ba23560c9..a26499781 100644
--- a/cockatrice/src/game/zones/pile_zone.cpp
+++ b/cockatrice/src/game/zones/pile_zone.cpp
@@ -1,7 +1,7 @@
#include "pile_zone.h"
-#include "../cards/card_drag_item.h"
-#include "../cards/card_item.h"
+#include "../board/card_drag_item.h"
+#include "../board/card_item.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
#include "view_zone.h"
diff --git a/cockatrice/src/game/zones/select_zone.cpp b/cockatrice/src/game/zones/select_zone.cpp
index 949b3fba2..bb6c40683 100644
--- a/cockatrice/src/game/zones/select_zone.cpp
+++ b/cockatrice/src/game/zones/select_zone.cpp
@@ -1,7 +1,7 @@
#include "select_zone.h"
#include "../../settings/cache_settings.h"
-#include "../cards/card_item.h"
+#include "../board/card_item.h"
#include "../game_scene.h"
#include
diff --git a/cockatrice/src/game/zones/stack_zone.cpp b/cockatrice/src/game/zones/stack_zone.cpp
index b597a9e81..324ef55fb 100644
--- a/cockatrice/src/game/zones/stack_zone.cpp
+++ b/cockatrice/src/game/zones/stack_zone.cpp
@@ -3,8 +3,8 @@
#include "../../client/ui/theme_manager.h"
#include "../../settings/cache_settings.h"
#include "../board/arrow_item.h"
-#include "../cards/card_drag_item.h"
-#include "../cards/card_item.h"
+#include "../board/card_drag_item.h"
+#include "../board/card_item.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp
index 02a06ed2e..e214b2e09 100644
--- a/cockatrice/src/game/zones/table_zone.cpp
+++ b/cockatrice/src/game/zones/table_zone.cpp
@@ -3,9 +3,9 @@
#include "../../client/ui/theme_manager.h"
#include "../../settings/cache_settings.h"
#include "../board/arrow_item.h"
-#include "../cards/card_drag_item.h"
+#include "../board/card_drag_item.h"
+#include "../board/card_item.h"
#include "../cards/card_info.h"
-#include "../cards/card_item.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
#include "pb/command_set_card_attr.pb.h"
diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h
index 271276967..f3fbdccb6 100644
--- a/cockatrice/src/game/zones/table_zone.h
+++ b/cockatrice/src/game/zones/table_zone.h
@@ -1,7 +1,7 @@
#ifndef TABLEZONE_H
#define TABLEZONE_H
-#include "../cards/abstract_card_item.h"
+#include "../board/abstract_card_item.h"
#include "select_zone.h"
/*
diff --git a/cockatrice/src/game/zones/view_zone.cpp b/cockatrice/src/game/zones/view_zone.cpp
index 9aec01db3..1c35b6613 100644
--- a/cockatrice/src/game/zones/view_zone.cpp
+++ b/cockatrice/src/game/zones/view_zone.cpp
@@ -1,9 +1,9 @@
#include "view_zone.h"
#include "../../server/pending_command.h"
-#include "../cards/card_drag_item.h"
+#include "../board/card_drag_item.h"
+#include "../board/card_item.h"
#include "../cards/card_info.h"
-#include "../cards/card_item.h"
#include "../player/player.h"
#include "pb/command_dump_zone.pb.h"
#include "pb/command_move_card.pb.h"
diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp
index 85a91afdf..1721831ac 100644
--- a/cockatrice/src/game/zones/view_zone_widget.cpp
+++ b/cockatrice/src/game/zones/view_zone_widget.cpp
@@ -2,7 +2,7 @@
#include "../../client/ui/pixel_map_generator.h"
#include "../../settings/cache_settings.h"
-#include "../cards/card_item.h"
+#include "../board/card_item.h"
#include "../filters/syntax_help.h"
#include "../game_scene.h"
#include "../player/player.h"
diff --git a/cockatrice/src/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 2c0174673..7ee275377 100644
--- a/cockatrice/src/server/message_log_widget.cpp
+++ b/cockatrice/src/server/message_log_widget.cpp
@@ -2,7 +2,7 @@
#include "../client/sound_engine.h"
#include "../client/translate_counter_name.h"
-#include "../game/cards/card_item.h"
+#include "../game/board/card_item.h"
#include "../game/phase.h"
#include "../game/player/player.h"
#include "../game/zones/card_zone.h"
From 873e0d346ebd22c656eadfc30305588e022945cc Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 20 Apr 2025 16:39:20 +0200
Subject: [PATCH 19/56] Make a setting for filtering to the most recent sets.
(#5865)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
...ual_database_display_set_filter_widget.cpp | 102 +++++++++++++++---
...isual_database_display_set_filter_widget.h | 17 +++
cockatrice/src/settings/cache_settings.cpp | 20 ++++
cockatrice/src/settings/cache_settings.h | 14 +++
dbconverter/src/mocks.cpp | 6 ++
tests/carddatabase/mocks.cpp | 6 ++
6 files changed, 150 insertions(+), 15 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
index 4914d927e..a79ef9ff6 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
@@ -3,12 +3,44 @@
#include "../../../../game/cards/card_database_manager.h"
#include "../../../../game/filters/filter_tree.h"
#include "../../../../game/filters/filter_tree_model.h"
+#include "../../../../settings/cache_settings.h"
#include
#include
#include
#include
+VisualDatabaseDisplayRecentSetFilterSettingsWidget::VisualDatabaseDisplayRecentSetFilterSettingsWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ layout = new QHBoxLayout(this);
+ setLayout(layout);
+
+ filterToMostRecentSetsCheckBox = new QCheckBox(this);
+ filterToMostRecentSetsCheckBox->setChecked(
+ SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsEnabled());
+ connect(filterToMostRecentSetsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled);
+
+ filterToMostRecentSetsAmount = new QSpinBox(this);
+ filterToMostRecentSetsAmount->setMinimum(1);
+ filterToMostRecentSetsAmount->setMaximum(100);
+ filterToMostRecentSetsAmount->setValue(
+ SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsAmount());
+ connect(filterToMostRecentSetsAmount, QOverload::of(&QSpinBox::valueChanged), &SettingsCache::instance(),
+ &SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount);
+
+ layout->addWidget(filterToMostRecentSetsCheckBox);
+ layout->addWidget(filterToMostRecentSetsAmount);
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayRecentSetFilterSettingsWidget::retranslateUi()
+{
+ filterToMostRecentSetsCheckBox->setText(tr("Filter to most recent sets"));
+}
+
VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidget *parent,
FilterTreeModel *_filterModel)
: QWidget(parent), filterModel(_filterModel)
@@ -19,6 +51,14 @@ VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidg
layout = new QVBoxLayout(this);
setLayout(layout);
+ recentSetsSettingsWidget = new VisualDatabaseDisplayRecentSetFilterSettingsWidget(this);
+ layout->addWidget(recentSetsSettingsWidget);
+
+ connect(&SettingsCache::instance(), &SettingsCache::visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged, this,
+ &VisualDatabaseDisplaySetFilterWidget::filterToRecentSets);
+ connect(&SettingsCache::instance(), &SettingsCache::visualDatabaseDisplayFilterToMostRecentSetsAmountChanged, this,
+ &VisualDatabaseDisplaySetFilterWidget::filterToRecentSets);
+
searchBox = new QLineEdit(this);
searchBox->setPlaceholderText(tr("Search sets..."));
layout->addWidget(searchBox);
@@ -47,18 +87,15 @@ void VisualDatabaseDisplaySetFilterWidget::retranslateUi()
void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
{
- SetList shared_pointerses = CardDatabaseManager::getInstance()->getSetList();
+ SetList allSets = CardDatabaseManager::getInstance()->getSetList();
// Sort by release date
- std::sort(shared_pointerses.begin(), shared_pointerses.end(),
+ std::sort(allSets.begin(), allSets.end(),
[](const auto &a, const auto &b) { return a->getReleaseDate() > b->getReleaseDate(); });
- int setsToPreactivate = 10;
- int setsActivated = 0;
-
- for (const auto &shared_pointer : shared_pointerses) {
- QString shortName = shared_pointer->getShortName();
- QString longName = shared_pointer->getLongName();
+ for (const auto &set : allSets) {
+ QString shortName = set->getShortName();
+ QString longName = set->getLongName();
auto *button = new QPushButton(longName + " (" + shortName + ")", flowWidget);
button->setCheckable(true);
@@ -69,16 +106,49 @@ void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
setButtons[shortName] = button;
// Connect toggle signal
- if (setsActivated < setsToPreactivate) {
- setsActivated++;
- activeSets[shortName] = true;
- button->setChecked(true);
- }
connect(button, &QPushButton::toggled, this,
[this, shortName](bool checked) { handleSetToggled(shortName, checked); });
}
- updateSetFilter();
- updateSetButtonsVisibility(); // Ensure visibility is updated initially
+
+ filterToRecentSets();
+}
+
+void VisualDatabaseDisplaySetFilterWidget::filterToRecentSets()
+{
+ if (SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsEnabled()) {
+ for (auto set : activeSets.keys()) {
+ activeSets[set] = false;
+ }
+
+ SetList allSets = CardDatabaseManager::getInstance()->getSetList();
+
+ // Sort by release date
+ std::sort(allSets.begin(), allSets.end(),
+ [](const auto &a, const auto &b) { return a->getReleaseDate() > b->getReleaseDate(); });
+
+ int setsToPreactivate = SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsAmount();
+ int setsActivated = 0;
+
+ for (const auto &set : allSets) {
+ QString shortName = set->getShortName();
+ QString longName = set->getLongName();
+
+ auto button = setButtons[shortName];
+
+ if (setsActivated < setsToPreactivate) {
+ setsActivated++;
+ activeSets[shortName] = true;
+ button->blockSignals(true);
+ button->setChecked(true);
+ button->blockSignals(false);
+ } else {
+ break;
+ }
+ }
+
+ updateSetFilter();
+ updateSetButtonsVisibility();
+ }
}
void VisualDatabaseDisplaySetFilterWidget::updateSetButtonsVisibility()
@@ -188,7 +258,9 @@ void VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel()
for (const auto &key : setButtons.keys()) {
bool active = selectedSets.contains(key);
activeSets[key] = active;
+ setButtons[key]->blockSignals(true);
setButtons[key]->setChecked(active);
+ setButtons[key]->blockSignals(false);
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h
index 2e63b3fdf..9079850ca 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h
@@ -4,13 +4,28 @@
#include "../../../../game/filters/filter_tree_model.h"
#include "../general/layout_containers/flow_widget.h"
+#include
#include
#include
#include
+#include
#include
#include
#include
+class VisualDatabaseDisplayRecentSetFilterSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ VisualDatabaseDisplayRecentSetFilterSettingsWidget(QWidget *parent);
+ void retranslateUi();
+
+private:
+ QHBoxLayout *layout;
+ QCheckBox *filterToMostRecentSetsCheckBox;
+ QSpinBox *filterToMostRecentSetsAmount;
+};
+
class VisualDatabaseDisplaySetFilterWidget : public QWidget
{
Q_OBJECT
@@ -18,6 +33,7 @@ public:
explicit VisualDatabaseDisplaySetFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
void retranslateUi();
void createSetButtons();
+ void filterToRecentSets();
void updateSetButtonsVisibility();
void handleSetToggled(const QString &setShortName, bool active);
@@ -29,6 +45,7 @@ private:
FilterTreeModel *filterModel;
QMap allMainCardTypesWithCount;
QVBoxLayout *layout;
+ VisualDatabaseDisplayRecentSetFilterSettingsWidget *recentSetsSettingsWidget;
QLineEdit *searchBox;
FlowWidget *flowWidget;
QPushButton *toggleButton; // Mode switch button
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index fd4fafe87..ba25590f3 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -285,6 +285,10 @@ SettingsCache::SettingsCache()
visualDeckStorageInGame = settings->value("interface/visualdeckstorageingame", true).toBool();
visualDeckStorageSelectionAnimation =
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
+ visualDatabaseDisplayFilterToMostRecentSetsEnabled =
+ settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
+ visualDatabaseDisplayFilterToMostRecentSetsAmount =
+ settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
horizontalHand = settings->value("hand/horizontal", true).toBool();
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
@@ -787,6 +791,22 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled)
+{
+ visualDatabaseDisplayFilterToMostRecentSetsEnabled = _enabled;
+ settings->setValue("interface/visualdatabasedisplayfiltertomostrecentsetsenabled",
+ visualDatabaseDisplayFilterToMostRecentSetsEnabled);
+ emit visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(visualDatabaseDisplayFilterToMostRecentSetsEnabled);
+}
+
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount)
+{
+ visualDatabaseDisplayFilterToMostRecentSetsAmount = _amount;
+ settings->setValue("interface/visualdatabasedisplayfiltertomostrecentsetsamount",
+ visualDatabaseDisplayFilterToMostRecentSetsAmount);
+ emit visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(visualDatabaseDisplayFilterToMostRecentSetsAmount);
+}
+
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
{
horizontalHand = static_cast(_horizontalHand);
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index 64f8cc58a..78993ce4a 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -71,6 +71,8 @@ signals:
void visualDeckStorageUnusedColorIdentitiesOpacityChanged(bool value);
void visualDeckStorageInGameChanged(bool enabled);
void visualDeckStorageSelectionAnimationChanged(bool enabled);
+ void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
+ void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@@ -151,6 +153,8 @@ private:
bool visualDeckStorageAlwaysConvert;
bool visualDeckStorageInGame;
bool visualDeckStorageSelectionAnimation;
+ bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
+ int visualDatabaseDisplayFilterToMostRecentSetsAmount;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@@ -484,6 +488,14 @@ public:
{
return visualDeckStorageSelectionAnimation;
}
+ bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
+ {
+ return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
+ }
+ int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
+ {
+ return visualDatabaseDisplayFilterToMostRecentSetsAmount;
+ }
bool getHorizontalHand() const
{
return horizontalHand;
@@ -827,6 +839,8 @@ public slots:
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
+ void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
+ void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index c4e716f48..93048d3cf 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -256,6 +256,12 @@ void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T /* value */)
void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T /* _enabled */)
+{
+}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index 35df750d3..a2ca73fb1 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -260,6 +260,12 @@ void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T /* value */)
void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T /* _enabled */)
+{
+}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
From a1499854f9ced7c75306c06b1425bc4363f5d962 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 20 Apr 2025 18:48:13 -0700
Subject: [PATCH 20/56] Make OracleImporter not extend CardDatabase (#5868)
* Move TOKENS_SETNAME to CardSet
* make OracleImporter no longer extend CardDatabase
---
cockatrice/src/dialogs/dlg_edit_tokens.cpp | 2 +-
cockatrice/src/game/cards/card_database.cpp | 11 ++++-------
cockatrice/src/game/cards/card_database.h | 2 --
.../src/game/cards/card_database_model.cpp | 2 +-
cockatrice/src/game/cards/card_info.cpp | 2 ++
cockatrice/src/game/cards/card_info.h | 2 ++
oracle/src/oracleimporter.cpp | 9 +++++----
oracle/src/oracleimporter.h | 19 +++++++++++++++++--
8 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_edit_tokens.cpp b/cockatrice/src/dialogs/dlg_edit_tokens.cpp
index 1248ee403..e51bbf369 100644
--- a/cockatrice/src/dialogs/dlg_edit_tokens.cpp
+++ b/cockatrice/src/dialogs/dlg_edit_tokens.cpp
@@ -161,7 +161,7 @@ void DlgEditTokens::actAddToken()
}
}
- QString setName = CardDatabase::TOKENS_SETNAME;
+ QString setName = CardSet::TOKENS_SETNAME;
CardInfoPerSetMap sets;
sets[setName].append(CardInfoPerSet(databaseModel->getDatabase()->getSet(setName)));
CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList(),
diff --git a/cockatrice/src/game/cards/card_database.cpp b/cockatrice/src/game/cards/card_database.cpp
index bb307b543..396a32a10 100644
--- a/cockatrice/src/game/cards/card_database.cpp
+++ b/cockatrice/src/game/cards/card_database.cpp
@@ -16,8 +16,6 @@
#include
#include
-const char *CardDatabase::TOKENS_SETNAME = "TK";
-
CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
{
qRegisterMetaType("CardInfoPtr");
@@ -560,16 +558,15 @@ void CardDatabase::notifyEnabledSetsChanged()
bool CardDatabase::saveCustomTokensToFile()
{
- QString fileName =
- SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml";
+ QString fileName = SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardSet::TOKENS_SETNAME + ".xml";
SetNameMap tmpSets;
- CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME);
- tmpSets.insert(CardDatabase::TOKENS_SETNAME, customTokensSet);
+ CardSetPtr customTokensSet = getSet(CardSet::TOKENS_SETNAME);
+ tmpSets.insert(CardSet::TOKENS_SETNAME, customTokensSet);
CardNameMap tmpCards;
for (const CardInfoPtr &card : cards) {
- if (card->getSets().contains(CardDatabase::TOKENS_SETNAME)) {
+ if (card->getSets().contains(CardSet::TOKENS_SETNAME)) {
tmpCards.insert(card->getName(), card);
}
}
diff --git a/cockatrice/src/game/cards/card_database.h b/cockatrice/src/game/cards/card_database.h
index 2de5999ee..7e4a1f2c7 100644
--- a/cockatrice/src/game/cards/card_database.h
+++ b/cockatrice/src/game/cards/card_database.h
@@ -61,8 +61,6 @@ private:
*removeCardMutex = new QBasicMutex();
public:
- static const char *TOKENS_SETNAME;
-
explicit CardDatabase(QObject *parent = nullptr);
~CardDatabase() override;
void clear();
diff --git a/cockatrice/src/game/cards/card_database_model.cpp b/cockatrice/src/game/cards/card_database_model.cpp
index 31ff98263..93bb7f02a 100644
--- a/cockatrice/src/game/cards/card_database_model.cpp
+++ b/cockatrice/src/game/cards/card_database_model.cpp
@@ -387,7 +387,7 @@ TokenEditModel::TokenEditModel(QObject *parent) : CardDatabaseDisplayModel(paren
bool TokenEditModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
{
CardInfoPtr info = static_cast(sourceModel())->getCard(sourceRow);
- return info->getIsToken() && info->getSets().contains(CardDatabase::TOKENS_SETNAME) && rowMatchesCardName(info);
+ return info->getIsToken() && info->getSets().contains(CardSet::TOKENS_SETNAME) && rowMatchesCardName(info);
}
int TokenEditModel::rowCount(const QModelIndex &parent) const
diff --git a/cockatrice/src/game/cards/card_info.cpp b/cockatrice/src/game/cards/card_info.cpp
index 344345b41..4bd2c0c9c 100644
--- a/cockatrice/src/game/cards/card_info.cpp
+++ b/cockatrice/src/game/cards/card_info.cpp
@@ -11,6 +11,8 @@
#include
#include
+const char *CardSet::TOKENS_SETNAME = "TK";
+
CardSet::CardSet(const QString &_shortName,
const QString &_longName,
const QString &_setType,
diff --git a/cockatrice/src/game/cards/card_info.h b/cockatrice/src/game/cards/card_info.h
index 76397588f..bdbebcd72 100644
--- a/cockatrice/src/game/cards/card_info.h
+++ b/cockatrice/src/game/cards/card_info.h
@@ -43,6 +43,8 @@ public:
PriorityLowest = 100,
};
+ static const char *TOKENS_SETNAME;
+
private:
QString shortName, longName;
unsigned int sortKey;
diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp
index de81cee3f..22edebac2 100644
--- a/oracle/src/oracleimporter.cpp
+++ b/oracle/src/oracleimporter.cpp
@@ -19,7 +19,7 @@ SplitCardPart::SplitCardPart(const QString &_name,
const QRegularExpression OracleImporter::formatRegex = QRegularExpression("^format-");
-OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent) : CardDatabase(parent), dataDir(_dataDir)
+OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent) : QObject(parent), dataDir(_dataDir)
{
}
@@ -463,8 +463,8 @@ int OracleImporter::startImport()
{
int setCards = 0, setIndex = 0;
// add an empty set for tokens
- CardSetPtr tokenSet = CardSet::newInstance(TOKENS_SETNAME, tr("Dummy set containing tokens"), "Tokens");
- sets.insert(TOKENS_SETNAME, tokenSet);
+ CardSetPtr tokenSet = CardSet::newInstance(CardSet::TOKENS_SETNAME, tr("Dummy set containing tokens"), "Tokens");
+ sets.insert(CardSet::TOKENS_SETNAME, tokenSet);
for (const SetToDownload &curSetToParse : allSets) {
CardSetPtr newSet =
@@ -494,6 +494,7 @@ bool OracleImporter::saveToFile(const QString &fileName, const QString &sourceUr
void OracleImporter::clear()
{
- CardDatabase::clear();
+ sets.clear();
+ cards.clear();
allSets.clear();
}
diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h
index 1231d1a81..b50c56d50 100644
--- a/oracle/src/oracleimporter.h
+++ b/oracle/src/oracleimporter.h
@@ -4,7 +4,7 @@
#include
#include
#include
-#include
+#include
#include
// many users prefer not to see these sets with non english arts
@@ -117,13 +117,24 @@ private:
CardInfoPerSet setInfo;
};
-class OracleImporter : public CardDatabase
+class OracleImporter : public QObject
{
Q_OBJECT
private:
const QStringList mainCardTypes = {"Planeswalker", "Creature", "Land", "Sorcery",
"Instant", "Artifact", "Enchantment"};
static const QRegularExpression formatRegex;
+
+ /**
+ * The cards, indexed by name.
+ */
+ CardNameMap cards;
+
+ /**
+ * The sets, indexed by short name.
+ */
+ SetNameMap sets;
+
QList allSets;
QVariantMap setsMap;
QString dataDir;
@@ -146,6 +157,10 @@ public:
int startImport();
bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion);
int importCardsFromSet(const CardSetPtr ¤tSet, const QList &cards);
+ const CardNameMap &getCardList() const
+ {
+ return cards;
+ }
QList &getSets()
{
return allSets;
From ca73033aeaf9db7d9191ce8bcafd6aff9b14cfb4 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 20 Apr 2025 20:53:37 -0700
Subject: [PATCH 21/56] Refactor files in oracle to new Qt Slot/Signal syntax
(#5869)
* Refactor files in oracle to new Qt Slot/Signal syntax
* fix build failure
---
oracle/src/oraclewizard.cpp | 19 +++++++++----------
oracle/src/pagetemplates.cpp | 6 +++---
2 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp
index c1c366948..785835cf4 100644
--- a/oracle/src/oraclewizard.cpp
+++ b/oracle/src/oraclewizard.cpp
@@ -58,7 +58,7 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent)
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
settings = new QSettings(SettingsCache::instance().getSettingsPath() + "global.ini", QSettings::IniFormat, this);
- connect(&SettingsCache::instance(), SIGNAL(langChanged()), this, SLOT(updateLanguage()));
+ connect(&SettingsCache::instance(), &SettingsCache::langChanged, this, &OracleWizard::updateLanguage);
importer = new OracleImporter(SettingsCache::instance().getDataPath(), this);
@@ -158,7 +158,7 @@ IntroPage::IntroPage(QWidget *parent) : OracleWizardPage(parent)
languageBox->setCurrentIndex(index);
}
- connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
+ connect(languageBox, qOverload(&QComboBox::currentIndexChanged), this, &IntroPage::languageBoxChanged);
auto *layout = new QGridLayout(this);
layout->addWidget(label, 0, 0, 1, 2);
@@ -226,10 +226,10 @@ LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent)
urlRadioButton->setChecked(true);
urlButton = new QPushButton(this);
- connect(urlButton, SIGNAL(clicked()), this, SLOT(actRestoreDefaultUrl()));
+ connect(urlButton, &QPushButton::clicked, this, &LoadSetsPage::actRestoreDefaultUrl);
fileButton = new QPushButton(this);
- connect(fileButton, SIGNAL(clicked()), this, SLOT(actLoadSetsFile()));
+ connect(fileButton, &QPushButton::clicked, this, &LoadSetsPage::actLoadSetsFile);
auto *layout = new QGridLayout(this);
layout->addWidget(urlRadioButton, 0, 0);
@@ -241,7 +241,7 @@ LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent)
layout->addWidget(progressLabel, 4, 0);
layout->addWidget(progressBar, 4, 1);
- connect(&watcher, SIGNAL(finished()), this, SLOT(importFinished()));
+ connect(&watcher, &QFutureWatcher::finished, this, &LoadSetsPage::importFinished);
setLayout(layout);
}
@@ -387,8 +387,8 @@ void LoadSetsPage::downloadSetsFile(const QUrl &url)
auto *reply = wizard()->nam->get(QNetworkRequest(url));
- connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile()));
- connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressSetsFile(qint64, qint64)));
+ connect(reply, &QNetworkReply::finished, this, &LoadSetsPage::actDownloadFinishedSetsFile);
+ connect(reply, &QNetworkReply::downloadProgress, this, &LoadSetsPage::actDownloadProgressSetsFile);
}
void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total)
@@ -598,7 +598,7 @@ SaveSetsPage::SaveSetsPage(QWidget *parent) : OracleWizardPage(parent)
void SaveSetsPage::cleanupPage()
{
wizard()->importer->clear();
- disconnect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), nullptr, nullptr);
+ disconnect(wizard()->importer, &OracleImporter::setIndexChanged, nullptr, nullptr);
}
void SaveSetsPage::initializePage()
@@ -611,8 +611,7 @@ void SaveSetsPage::initializePage()
return;
}
messageLog->show();
- connect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), this,
- SLOT(updateTotalProgress(int, int, const QString &)));
+ connect(wizard()->importer, &OracleImporter::setIndexChanged, this, &SaveSetsPage::updateTotalProgress);
if (!wizard()->importer->startImport()) {
QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
diff --git a/oracle/src/pagetemplates.cpp b/oracle/src/pagetemplates.cpp
index b4d8d358b..858fd8022 100644
--- a/oracle/src/pagetemplates.cpp
+++ b/oracle/src/pagetemplates.cpp
@@ -23,7 +23,7 @@ SimpleDownloadFilePage::SimpleDownloadFilePage(QWidget *parent) : OracleWizardPa
progressBar = new QProgressBar(this);
urlButton = new QPushButton(this);
- connect(urlButton, SIGNAL(clicked()), this, SLOT(actRestoreDefaultUrl()));
+ connect(urlButton, &QPushButton::clicked, this, &SimpleDownloadFilePage::actRestoreDefaultUrl);
defaultPathCheckBox = new QCheckBox(this);
@@ -91,8 +91,8 @@ void SimpleDownloadFilePage::downloadFile(QUrl url)
{
QNetworkReply *reply = wizard()->nam->get(QNetworkRequest(url));
- connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinished()));
- connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgress(qint64, qint64)));
+ connect(reply, &QNetworkReply::finished, this, &SimpleDownloadFilePage::actDownloadFinished);
+ connect(reply, &QNetworkReply::downloadProgress, this, &SimpleDownloadFilePage::actDownloadProgress);
}
void SimpleDownloadFilePage::actDownloadProgress(qint64 received, qint64 total)
From f7152befec40f2f5e3912de61cf7cc266dbe7e14 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 21 Apr 2025 13:28:45 -0700
Subject: [PATCH 22/56] Refactor: clean up MessageLogWidget (#5870)
* use constants instead of static methods
* make static methods static
* remove unused variables
---
cockatrice/src/server/message_log_widget.cpp | 93 ++++++--------------
cockatrice/src/server/message_log_widget.h | 14 +--
2 files changed, 30 insertions(+), 77 deletions(-)
diff --git a/cockatrice/src/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 7ee275377..7590e044b 100644
--- a/cockatrice/src/server/message_log_widget.cpp
+++ b/cockatrice/src/server/message_log_widget.cpp
@@ -12,74 +12,39 @@
#include
-const QString &MessageLogWidget::tableConstant() const
-{
- static const QString constant("table");
- return constant;
-}
+static const QString TABLE_ZONE_NAME = "table";
+static const QString GRAVE_ZONE_NAME = "grave";
+static const QString EXILE_ZONE_NAME = "rfg";
+static const QString HAND_ZONE_NAME = "hand";
+static const QString DECK_ZONE_NAME = "deck";
+static const QString SIDEBOARD_ZONE_NAME = "sb";
+static const QString STACK_ZONE_NAME = "stack";
-const QString &MessageLogWidget::graveyardConstant() const
-{
- static const QString constant("grave");
- return constant;
-}
-
-const QString &MessageLogWidget::exileConstant() const
-{
- static const QString constant("rfg");
- return constant;
-}
-
-const QString &MessageLogWidget::handConstant() const
-{
- static const QString constant("hand");
- return constant;
-}
-
-const QString &MessageLogWidget::deckConstant() const
-{
- static const QString constant("deck");
- return constant;
-}
-
-const QString &MessageLogWidget::sideboardConstant() const
-{
- static const QString constant("sb");
- return constant;
-}
-
-const QString &MessageLogWidget::stackConstant() const
-{
- static const QString constant("stack");
- return constant;
-}
-
-QString MessageLogWidget::sanitizeHtml(QString dirty) const
+static QString sanitizeHtml(QString dirty)
{
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
}
-QString MessageLogWidget::cardLink(const QString cardName) const
+static QString cardLink(const QString &cardName)
{
return QString("%2").arg(cardName).arg(cardName);
}
-QPair
-MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position, bool ownerChange) const
+QPair MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position, bool ownerChange)
{
bool cardNameContainsStartZone = false;
QString fromStr;
QString zoneName = zone->getName();
- if (zoneName == tableConstant()) {
+ if (zoneName == TABLE_ZONE_NAME) {
fromStr = tr(" from play");
- } else if (zoneName == graveyardConstant()) {
+ } else if (zoneName == GRAVE_ZONE_NAME) {
fromStr = tr(" from their graveyard");
- } else if (zoneName == exileConstant()) {
+ } else if (zoneName == EXILE_ZONE_NAME) {
fromStr = tr(" from exile");
- } else if (zoneName == handConstant()) {
+ } else if (zoneName == HAND_ZONE_NAME) {
fromStr = tr(" from their hand");
- } else if (zoneName == deckConstant()) {
+ } else if (zoneName == DECK_ZONE_NAME) {
if (position == 0) {
if (cardName.isEmpty()) {
if (ownerChange) {
@@ -117,16 +82,16 @@ MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position, boo
fromStr = tr(" from their library");
}
}
- } else if (zoneName == sideboardConstant()) {
+ } else if (zoneName == SIDEBOARD_ZONE_NAME) {
fromStr = tr(" from sideboard");
- } else if (zoneName == stackConstant()) {
+ } else if (zoneName == STACK_ZONE_NAME) {
fromStr = tr(" from the stack");
}
if (!cardNameContainsStartZone) {
cardName.clear();
}
- return QPair(cardName, fromStr);
+ return {cardName, fromStr};
}
void MessageLogWidget::containerProcessingDone()
@@ -291,9 +256,9 @@ void MessageLogWidget::logMoveCard(Player *player,
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
// do not log if moved within the same zone
- if ((startZoneName == tableConstant() && targetZoneName == tableConstant() && !ownerChanged) ||
- (startZoneName == handConstant() && targetZoneName == handConstant()) ||
- (startZoneName == exileConstant() && targetZoneName == exileConstant())) {
+ if ((startZoneName == TABLE_ZONE_NAME && targetZoneName == TABLE_ZONE_NAME && !ownerChanged) ||
+ (startZoneName == HAND_ZONE_NAME && targetZoneName == HAND_ZONE_NAME) ||
+ (startZoneName == EXILE_ZONE_NAME && targetZoneName == EXILE_ZONE_NAME)) {
return;
}
@@ -322,20 +287,20 @@ void MessageLogWidget::logMoveCard(Player *player,
QString finalStr;
bool usesNewX = false;
- if (targetZoneName == tableConstant()) {
+ if (targetZoneName == TABLE_ZONE_NAME) {
soundEngine->playSound("play_card");
if (card->getFaceDown()) {
finalStr = tr("%1 puts %2 into play%3 face down.");
} else {
finalStr = tr("%1 puts %2 into play%3.");
}
- } else if (targetZoneName == graveyardConstant()) {
+ } else if (targetZoneName == GRAVE_ZONE_NAME) {
finalStr = tr("%1 puts %2%3 into their graveyard.");
- } else if (targetZoneName == exileConstant()) {
+ } else if (targetZoneName == EXILE_ZONE_NAME) {
finalStr = tr("%1 exiles %2%3.");
- } else if (targetZoneName == handConstant()) {
+ } else if (targetZoneName == HAND_ZONE_NAME) {
finalStr = tr("%1 moves %2%3 to their hand.");
- } else if (targetZoneName == deckConstant()) {
+ } else if (targetZoneName == DECK_ZONE_NAME) {
if (newX == -1) {
finalStr = tr("%1 puts %2%3 into their library.");
} else if (newX >= targetZone->getCards().size()) {
@@ -347,9 +312,9 @@ void MessageLogWidget::logMoveCard(Player *player,
usesNewX = true;
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
}
- } else if (targetZoneName == sideboardConstant()) {
+ } else if (targetZoneName == SIDEBOARD_ZONE_NAME) {
finalStr = tr("%1 moves %2%3 to sideboard.");
- } else if (targetZoneName == stackConstant()) {
+ } else if (targetZoneName == STACK_ZONE_NAME) {
soundEngine->playSound("play_card");
finalStr = tr("%1 plays %2%3.");
}
@@ -845,6 +810,6 @@ void MessageLogWidget::connectToPlayer(Player *player)
}
MessageLogWidget::MessageLogWidget(TabSupervisor *_tabSupervisor, TabGame *_game, QWidget *parent)
- : ChatView(_tabSupervisor, _game, true, parent), mulliganNumber(0), currentContext(MessageContext_None)
+ : ChatView(_tabSupervisor, _game, true, parent), currentContext(MessageContext_None)
{
}
diff --git a/cockatrice/src/server/message_log_widget.h b/cockatrice/src/server/message_log_widget.h
index ef66f21e7..f6780b729 100644
--- a/cockatrice/src/server/message_log_widget.h
+++ b/cockatrice/src/server/message_log_widget.h
@@ -21,22 +21,10 @@ private:
MessageContext_Mulligan
};
- int mulliganNumber;
- Player *mulliganPlayer;
MessageContext currentContext;
QString messagePrefix, messageSuffix;
- const QString &tableConstant() const;
- const QString &graveyardConstant() const;
- const QString &exileConstant() const;
- const QString &handConstant() const;
- const QString &deckConstant() const;
- const QString &sideboardConstant() const;
- const QString &stackConstant() const;
-
- QString sanitizeHtml(QString dirty) const;
- QString cardLink(QString cardName) const;
- QPair getFromStr(CardZone *zone, QString cardName, int position, bool ownerChange) const;
+ static QPair getFromStr(CardZone *zone, QString cardName, int position, bool ownerChange);
public slots:
void containerProcessingDone();
From ffe02e59c7a9ef2cc306ba66346e54017b3a089f Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 21 Apr 2025 13:29:42 -0700
Subject: [PATCH 23/56] Refactor: clean up OracleImporter (#5871)
* remove unused dataDir variable
* inline setsMap
* join declaration and assignment
* make the protected methods static
* make getSetPriority static
* inline mainCardTypes list and make the method static
* pass by const ref when able
* rename param to match
---
oracle/src/oracleimporter.cpp | 83 +++++++++++++++++------------------
oracle/src/oracleimporter.h | 29 ++++--------
oracle/src/oraclewizard.cpp | 2 +-
3 files changed, 51 insertions(+), 63 deletions(-)
diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp
index 22edebac2..7138f80af 100644
--- a/oracle/src/oracleimporter.cpp
+++ b/oracle/src/oracleimporter.cpp
@@ -12,18 +12,18 @@
SplitCardPart::SplitCardPart(const QString &_name,
const QString &_text,
const QVariantHash &_properties,
- const CardInfoPerSet _setInfo)
+ const CardInfoPerSet &_setInfo)
: name(_name), text(_text), properties(_properties), setInfo(_setInfo)
{
}
const QRegularExpression OracleImporter::formatRegex = QRegularExpression("^format-");
-OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent) : QObject(parent), dataDir(_dataDir)
+OracleImporter::OracleImporter(QObject *parent) : QObject(parent)
{
}
-CardSet::Priority OracleImporter::getSetPriority(QString &setType, QString &shortName)
+static CardSet::Priority getSetPriority(const QString &setType, const QString &shortName)
{
if (!setTypePriorities.contains(setType.toLower())) {
qDebug() << "warning: Set type" << setType << "unrecognized for prioritization";
@@ -40,30 +40,22 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
QList newSetList;
bool ok;
- setsMap = QtJson::Json::parse(QString(data), ok).toMap().value("data").toMap();
+ auto setsMap = QtJson::Json::parse(QString(data), ok).toMap().value("data").toMap();
if (!ok) {
qDebug() << "error: QtJson::Json::parse()";
return false;
}
QListIterator it(setsMap.values());
- QVariantMap map;
-
- QString shortName;
- QString longName;
- QList setCards;
- QString setType;
- QDate releaseDate;
- CardSet::Priority priority;
while (it.hasNext()) {
- map = it.next().toMap();
- shortName = map.value("code").toString().toUpper();
- longName = map.value("name").toString();
- setCards = map.value("cards").toList();
- setType = map.value("type").toString();
- releaseDate = map.value("releaseDate").toDate();
- priority = getSetPriority(setType, shortName);
+ QVariantMap map = it.next().toMap();
+ QString shortName = map.value("code").toString().toUpper();
+ QString longName = map.value("name").toString();
+ QList setCards = map.value("cards").toList();
+ QString setType = map.value("type").toString();
+ QDate releaseDate = map.value("releaseDate").toDate();
+ CardSet::Priority priority = getSetPriority(setType, shortName);
// capitalize set type
if (setType.length() > 0) {
// basic grammar for words that aren't capitalized, like in "From the Vault"
@@ -93,13 +85,16 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
return true;
}
-QString OracleImporter::getMainCardType(const QStringList &typeList)
+static QString getMainCardType(const QStringList &typeList)
{
if (typeList.isEmpty()) {
return {};
}
- for (const auto &type : mainCardTypes) {
+ static const QStringList typePriority = {"Planeswalker", "Creature", "Land", "Sorcery",
+ "Instant", "Artifact", "Enchantment"};
+
+ for (const auto &type : typePriority) {
if (typeList.contains(type)) {
return type;
}
@@ -108,12 +103,33 @@ QString OracleImporter::getMainCardType(const QStringList &typeList)
return typeList.first();
}
+/**
+ * Sorts and deduplicates the color chars in the string by WUBRG order.
+ *
+ * @param colors The string containing the color chars. Will be modified in-place
+ */
+static void sortAndReduceColors(QString &colors)
+{
+ // sort
+ static const QHash colorOrder{{'W', 0}, {'U', 1}, {'B', 2}, {'R', 3}, {'G', 4}};
+ std::sort(colors.begin(), colors.end(),
+ [](const QChar a, const QChar b) { return colorOrder.value(a, INT_MAX) < colorOrder.value(b, INT_MAX); });
+ // reduce
+ QChar lastChar = '\0';
+ for (int i = 0; i < colors.size(); ++i) {
+ if (colors.at(i) == lastChar)
+ colors.remove(i, 1);
+ else
+ lastChar = colors.at(i);
+ }
+}
+
CardInfoPtr OracleImporter::addCard(QString name,
- QString text,
+ const QString &text,
bool isToken,
QVariantHash properties,
- QList &relatedCards,
- CardInfoPerSet setInfo)
+ const QList &relatedCards,
+ const CardInfoPerSet &setInfo)
{
// Workaround for card name weirdness
name = name.replace("Æ", "AE");
@@ -197,7 +213,7 @@ CardInfoPtr OracleImporter::addCard(QString name,
return newCard;
}
-QString OracleImporter::getStringPropertyFromMap(const QVariantMap &card, const QString &propertyName)
+static QString getStringPropertyFromMap(const QVariantMap &card, const QString &propertyName)
{
return card.contains(propertyName) ? card.value(propertyName).toString() : QString("");
}
@@ -442,23 +458,6 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
return numCards;
}
-void OracleImporter::sortAndReduceColors(QString &colors)
-{
- // sort
- const QHash colorOrder{{'W', 0}, {'U', 1}, {'B', 2}, {'R', 3}, {'G', 4}};
- std::sort(colors.begin(), colors.end(), [&colorOrder](const QChar a, const QChar b) {
- return colorOrder.value(a, INT_MAX) < colorOrder.value(b, INT_MAX);
- });
- // reduce
- QChar lastChar = '\0';
- for (int i = 0; i < colors.size(); ++i) {
- if (colors.at(i) == lastChar)
- colors.remove(i, 1);
- else
- lastChar = colors.at(i);
- }
-}
-
int OracleImporter::startImport()
{
int setCards = 0, setIndex = 0;
diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h
index b50c56d50..314723706 100644
--- a/oracle/src/oracleimporter.h
+++ b/oracle/src/oracleimporter.h
@@ -92,7 +92,10 @@ public:
class SplitCardPart
{
public:
- SplitCardPart(const QString &_name, const QString &_text, const QVariantHash &_properties, CardInfoPerSet setInfo);
+ SplitCardPart(const QString &_name,
+ const QString &_text,
+ const QVariantHash &_properties,
+ const CardInfoPerSet &setInfo);
inline const QString &getName() const
{
return name;
@@ -121,8 +124,6 @@ class OracleImporter : public QObject
{
Q_OBJECT
private:
- const QStringList mainCardTypes = {"Planeswalker", "Creature", "Land", "Sorcery",
- "Instant", "Artifact", "Enchantment"};
static const QRegularExpression formatRegex;
/**
@@ -136,27 +137,23 @@ private:
SetNameMap sets;
QList allSets;
- QVariantMap setsMap;
- QString dataDir;
- QString getMainCardType(const QStringList &typeList);
CardInfoPtr addCard(QString name,
- QString text,
+ const QString &text,
bool isToken,
QVariantHash properties,
- QList &relatedCards,
- CardInfoPerSet setInfo);
+ const QList &relatedCards,
+ const CardInfoPerSet &setInfo);
signals:
void setIndexChanged(int cardsImported, int setIndex, const QString &setName);
void dataReadProgress(int bytesRead, int totalBytes);
public:
- explicit OracleImporter(const QString &_dataDir, QObject *parent = nullptr);
- CardSet::Priority getSetPriority(QString &setType, QString &shortName);
+ explicit OracleImporter(QObject *parent = nullptr);
bool readSetsFromByteArray(const QByteArray &data);
int startImport();
bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion);
- int importCardsFromSet(const CardSetPtr ¤tSet, const QList &cards);
+ int importCardsFromSet(const CardSetPtr ¤tSet, const QList &cardsList);
const CardNameMap &getCardList() const
{
return cards;
@@ -165,15 +162,7 @@ public:
{
return allSets;
}
- const QString &getDataDir() const
- {
- return dataDir;
- }
void clear();
-
-protected:
- inline QString getStringPropertyFromMap(const QVariantMap &card, const QString &propertyName);
- void sortAndReduceColors(QString &colors);
};
#endif
diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp
index 785835cf4..bea87dde2 100644
--- a/oracle/src/oraclewizard.cpp
+++ b/oracle/src/oraclewizard.cpp
@@ -60,7 +60,7 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent)
settings = new QSettings(SettingsCache::instance().getSettingsPath() + "global.ini", QSettings::IniFormat, this);
connect(&SettingsCache::instance(), &SettingsCache::langChanged, this, &OracleWizard::updateLanguage);
- importer = new OracleImporter(SettingsCache::instance().getDataPath(), this);
+ importer = new OracleImporter(this);
nam = new QNetworkAccessManager(this);
From bcaa6c6b8a8f5bd54647bd462e045ba90a3ca9b0 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 21 Apr 2025 13:30:40 -0700
Subject: [PATCH 24/56] Refactor files in common to new Qt Slot/Signal syntax
(#5872)
---
common/server.cpp | 10 +++++-----
common/server_game.cpp | 2 +-
common/server_protocolhandler.cpp | 2 +-
common/server_room.cpp | 7 ++++---
4 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/common/server.cpp b/common/server.cpp
index a8223c599..4b0120ea1 100644
--- a/common/server.cpp
+++ b/common/server.cpp
@@ -51,8 +51,7 @@ Server::Server(QObject *parent) : QObject(parent), nextLocalGameId(0), tcpUserCo
qRegisterMetaType("IslMessage");
qRegisterMetaType("Command_JoinGame");
- connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)),
- Qt::QueuedConnection);
+ connect(this, &Server::sigSendIslMessage, this, &Server::doSendIslMessage, Qt::QueuedConnection);
}
void Server::prepareDestroy()
@@ -67,7 +66,7 @@ void Server::prepareDestroy()
void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface)
{
- connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64)));
+ connect(this, &Server::endSession, _databaseInterface, &Server_DatabaseInterface::endSession);
databaseInterfaces.insert(QThread::currentThread(), _databaseInterface);
}
@@ -568,8 +567,9 @@ void Server::addRoom(Server_Room *newRoom)
QWriteLocker locker(&roomsLock);
qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName();
rooms.insert(newRoom->getId(), newRoom);
- connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)),
- Qt::QueuedConnection);
+ connect(
+ newRoom, &Server_Room::roomInfoChanged, this, [this](auto roomInfo) { broadcastRoomUpdate(roomInfo); },
+ Qt::QueuedConnection);
}
int Server::getUsersCount() const
diff --git a/common/server_game.cpp b/common/server_game.cpp
index 17ab01dda..9387ccd37 100644
--- a/common/server_game.cpp
+++ b/common/server_game.cpp
@@ -87,7 +87,7 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo,
if (room->getServer()->getGameShouldPing()) {
pingClock = new QTimer(this);
- connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout()));
+ connect(pingClock, &QTimer::timeout, this, &Server_Game::pingClockTimeout);
pingClock->start(1000);
}
}
diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp
index 045b84487..075b3901e 100644
--- a/common/server_protocolhandler.cpp
+++ b/common/server_protocolhandler.cpp
@@ -36,7 +36,7 @@ Server_ProtocolHandler::Server_ProtocolHandler(Server *_server,
idleClientWarningSent(false), timeRunning(0), lastDataReceived(0), lastActionReceived(0)
{
- connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
+ connect(server, &Server::pingClockTimeout, this, &Server_ProtocolHandler::pingClockTimeout);
}
Server_ProtocolHandler::~Server_ProtocolHandler()
diff --git a/common/server_room.cpp b/common/server_room.cpp
index 77f720cb5..654666edf 100644
--- a/common/server_room.cpp
+++ b/common/server_room.cpp
@@ -31,8 +31,9 @@ Server_Room::Server_Room(int _id,
permissionLevel(_permissionLevel), privilegeLevel(_privilegeLevel), autoJoin(_autoJoin),
joinMessage(_joinMessage), gameTypes(_gameTypes), gamesLock(QReadWriteLock::Recursive)
{
- connect(this, SIGNAL(gameListChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)),
- Qt::QueuedConnection);
+ connect(
+ this, &Server_Room::gameListChanged, this, [this](auto gameInfo) { broadcastGameListUpdate(gameInfo); },
+ Qt::QueuedConnection);
}
Server_Room::~Server_Room()
@@ -352,7 +353,7 @@ void Server_Room::addGame(Server_Game *game)
roomInfo.set_room_id(id);
gamesLock.lockForWrite();
- connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)));
+ connect(game, &Server_Game::gameInfoChanged, this, [this](auto gameInfo) { broadcastGameListUpdate(gameInfo); });
game->gameMutex.lock();
games.insert(game->getGameId(), game);
From 95a86703b3fab84a09bca1ebff8621b14f9d0a96 Mon Sep 17 00:00:00 2001
From: "transifex-integration[bot]"
<43880903+transifex-integration[bot]@users.noreply.github.com>
Date: Thu, 24 Apr 2025 22:39:35 -0400
Subject: [PATCH 25/56] Updates for project Cockatrice and language it (#5876)
* Translate cockatrice/cockatrice_en@source.ts in it
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'it'.
* Translate cockatrice/cockatrice_en@source.ts in it
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'it'.
---------
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
---
cockatrice/translations/cockatrice_it.ts | 33 ++++++++++++------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/cockatrice/translations/cockatrice_it.ts b/cockatrice/translations/cockatrice_it.ts
index f310b5842..7cdce9896 100644
--- a/cockatrice/translations/cockatrice_it.ts
+++ b/cockatrice/translations/cockatrice_it.ts
@@ -203,7 +203,7 @@ Controlla se la cartella è valida e prova ancora.
Minimum overlap percentage of cards on the stack and in vertical hand
- Sovrapposizione % minima delle carte in pila e nella mano verticale
+ Sovrapposizione % minima delle carte in pila e nella mano verticale:
@@ -2770,13 +2770,13 @@ Per favore, visitate la pagina di download per aggiornare manualmente.
Released
- Rilasciato
+ Data di rilascioChangelog
- Cambiamenti della versione
+ Changelog
@@ -2789,13 +2789,14 @@ Per favore, visitate la pagina di download per aggiornare manualmente.
Unfortunately there are no download packages available for your operating system.
You may have to build from source yourself.
-
+ Purtroppo l'aggiornamento automatico non è riuscito a trovare una versione compatibile.
+Dovrai scaricare la nuova versione manualmente.Please check the <a href="%1">releases page</a> on our Github and download the build for your system.Please check the download page manually and visit the wiki for instructions on compiling.
-
+ Per favore, controlla la <a href="%1">pagina delle release</a> sul nostro Github e scarica la versione giusta per il tuo sistema.
@@ -3668,7 +3669,7 @@ La tua versione è la %1, la versione online è la %2.
Start &local game...
- Inizia &partita in locale...
+ Inizia partita in &locale...
@@ -3688,7 +3689,7 @@ La tua versione è la %1, la versione online è la %2.
&Restore password...
- &Recupera password...
+ Recupera &password...
@@ -3713,7 +3714,7 @@ La tua versione è la %1, la versione online è la %2.
C&ard Database
- &Database delle carte
+ &Database carte
@@ -3916,7 +3917,7 @@ Scopri metodi alternativi per visualizzare i set o disabilitare set ed effetti n
An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.
-
+ Si è verificato un errore nel cercare di scrivere al processo. Ad esempio, il processo potrebbe non essere in esecuzione, o potrebbe aver chiuso il suo canale di input.
@@ -5850,7 +5851,7 @@ Il database delle carte verrà ricaricato.
Time started
- Inizio tempo
+ Inizio
@@ -7122,7 +7123,7 @@ Più informazioni inserisci, più specifici saranno i risultati.
Deck Editor
- Editor dei mazzi
+ &Editor dei mazzi
@@ -7142,12 +7143,12 @@ Più informazioni inserisci, più specifici saranno i risultati.
Deck Storage
- Archivio mazzi
+ &Archivio mazziGame Replays
- Replay partite
+ &Replay partite
@@ -8299,12 +8300,12 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u
Analyze Deck (deckstats.net)Analyze Deck
- Analizza Mazzo (deckstats.net)
+ Analizza mazzo (deckstats.net)Analyze Deck (tappedout.net)
- Analizza Mazzo (tappedout.net)
+ Analizza mazzo (tappedout.net)
@@ -8496,7 +8497,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u
Set Red Counters...
- Imposta Contatore Rosso...
+ Imposta Segnalino Rosso...
From 6fd1e9a4c4e2322f8bc4aa0778ddbaedf38867cb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 24 Apr 2025 22:42:18 -0400
Subject: [PATCH 26/56] Bump serialize-javascript from 6.0.0 to 6.0.2 in
/webclient (#5878)
Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) from 6.0.0 to 6.0.2.
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)
---
updated-dependencies:
- dependency-name: serialize-javascript
dependency-version: 6.0.2
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
webclient/package-lock.json | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/webclient/package-lock.json b/webclient/package-lock.json
index f5c2ea22e..fa93ceb06 100644
--- a/webclient/package-lock.json
+++ b/webclient/package-lock.json
@@ -17962,9 +17962,10 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+ "license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
}
@@ -32825,9 +32826,9 @@
}
},
"serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"requires": {
"randombytes": "^2.1.0"
}
From 1409dcc2e860b27d9b19f324e90f83fa8986e687 Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Sun, 27 Apr 2025 01:55:54 +0200
Subject: [PATCH 27/56] Remove `isView` flag from CardZone (#5728)
* Remove `isView` flag from CardZone
This flag is used for two purposes:
1. It is used as a check for casting to a zone to a `ZoneViewZone`;
2. Non-view zones are added to the player's zones on construction
This patch removes the `isView` flag and instead:
1. We directly cast zones to `ZoneViewZone` using a dynamic (qobject)
cast and use the result of the cast instead of the `isView` flag to
detect if we are a view zone or not;
2. The player records its own zones when they are created, simplifying
control flow.
* Review
---
cockatrice/src/game/board/card_item.cpp | 9 +++----
cockatrice/src/game/player/player.cpp | 32 +++++++++--------------
cockatrice/src/game/player/player.h | 7 ++++-
cockatrice/src/game/zones/card_zone.cpp | 11 +++-----
cockatrice/src/game/zones/card_zone.h | 8 +-----
cockatrice/src/game/zones/select_zone.cpp | 5 ++--
cockatrice/src/game/zones/select_zone.h | 3 +--
cockatrice/src/game/zones/view_zone.cpp | 2 +-
8 files changed, 30 insertions(+), 47 deletions(-)
diff --git a/cockatrice/src/game/board/card_item.cpp b/cockatrice/src/game/board/card_item.cpp
index e9a345e86..55df7a477 100644
--- a/cockatrice/src/game/board/card_item.cpp
+++ b/cockatrice/src/game/board/card_item.cpp
@@ -336,8 +336,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
2 * QApplication::startDragDistance())
return;
- if (zone->getIsView()) {
- const ZoneViewZone *view = static_cast(zone);
+ if (const ZoneViewZone *view = qobject_cast(zone)) {
if (view->getRevealZone() && !view->getWriteableRevealZone())
return;
} else if (!owner->getLocalOrJudge())
@@ -394,10 +393,8 @@ void CardItem::playCard(bool faceDown)
*/
static bool isUnwritableRevealZone(CardZone *zone)
{
- if (zone && zone->getIsView()) {
- if (auto *view = static_cast(zone)) {
- return view->getRevealZone() && !view->getWriteableRevealZone();
- }
+ if (auto *view = qobject_cast(zone)) {
+ return view->getRevealZone() && !view->getWriteableRevealZone();
}
return false;
}
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index e4d319633..c893e27af 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -124,7 +124,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0;
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
- auto *_deck = new PileZone(this, "deck", true, false, playerArea);
+ auto *_deck = addZone(new PileZone(this, "deck", true, false, playerArea));
QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
_deck->setPos(base);
@@ -135,22 +135,23 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
handCounter->setPos(base + QPointF(0, h + 10));
qreal h2 = handCounter->boundingRect().height();
- PileZone *grave = new PileZone(this, "grave", false, true, playerArea);
+ PileZone *grave = addZone(new PileZone(this, "grave", false, true, playerArea));
grave->setPos(base + QPointF(0, h + h2 + 10));
- PileZone *rfg = new PileZone(this, "rfg", false, true, playerArea);
+ PileZone *rfg = addZone(new PileZone(this, "rfg", false, true, playerArea));
rfg->setPos(base + QPointF(0, 2 * h + h2 + 10));
- PileZone *sb = new PileZone(this, "sb", false, false, playerArea);
+ PileZone *sb = addZone(new PileZone(this, "sb", false, false, playerArea));
sb->setVisible(false);
- table = new TableZone(this, this);
+ table = addZone(new TableZone(this, this));
connect(table, &TableZone::sizeChanged, this, &Player::updateBoundingRect);
- stack = new StackZone(this, (int)table->boundingRect().height(), this);
+ stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this));
- hand = new HandZone(this, _local || _judge || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()),
- (int)table->boundingRect().height(), this);
+ hand = addZone(new HandZone(this,
+ _local || _judge || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()),
+ (int)table->boundingRect().height(), this));
connect(hand, &HandZone::cardCountChanged, handCounter, &HandCounter::updateNumber);
connect(handCounter, &HandCounter::showContextMenu, hand, &HandZone::showContextMenu);
@@ -2889,11 +2890,6 @@ void Player::deleteCard(CardItem *card)
}
}
-void Player::addZone(CardZone *zone)
-{
- zones.insert(zone->getName(), zone);
-}
-
AbstractCounter *Player::addCounter(const ServerInfo_Counter &counter)
{
return addCounter(counter.id(), QString::fromStdString(counter.name()),
@@ -3692,9 +3688,8 @@ void Player::actCardCounterTrigger()
*/
static bool isUnwritableRevealZone(CardZone *zone)
{
- if (zone && zone->getIsView()) {
- auto *view = static_cast(zone);
- return view && view->getRevealZone() && !view->getWriteableRevealZone();
+ if (auto *view = qobject_cast(zone)) {
+ return view->getRevealZone() && !view->getWriteableRevealZone();
}
return false;
}
@@ -3784,8 +3779,7 @@ void Player::updateCardMenu(const CardItem *card)
bool revealedCard = false;
bool writeableCard = getLocalOrJudge();
- if (card->getZone() && card->getZone()->getIsView()) {
- auto *view = dynamic_cast(card->getZone());
+ if (auto *view = qobject_cast(card->getZone())) {
if (view->getRevealZone()) {
if (view->getWriteableRevealZone()) {
writeableCard = true;
@@ -3955,7 +3949,7 @@ void Player::updateCardMenu(const CardItem *card)
cardMenu->addSeparator();
cardMenu->addAction(aSelectAll);
- if (card->getZone()->getIsView()) {
+ if (qobject_cast(card->getZone())) {
cardMenu->addAction(aSelectColumn);
}
diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h
index 76365d50d..027a7658b 100644
--- a/cockatrice/src/game/player/player.h
+++ b/cockatrice/src/game/player/player.h
@@ -409,7 +409,12 @@ public:
void playCardToTable(const CardItem *c, bool faceDown);
void addCard(CardItem *c);
void deleteCard(CardItem *c);
- void addZone(CardZone *z);
+
+ template T *addZone(T *zone)
+ {
+ zones.insert(zone->getName(), zone);
+ return zone;
+ }
AbstractCounter *addCounter(const ServerInfo_Counter &counter);
AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value);
diff --git a/cockatrice/src/game/zones/card_zone.cpp b/cockatrice/src/game/zones/card_zone.cpp
index 24eaa4f52..05b4c35b9 100644
--- a/cockatrice/src/game/zones/card_zone.cpp
+++ b/cockatrice/src/game/zones/card_zone.cpp
@@ -19,21 +19,16 @@
* @param _isShufflable whether it makes sense to shuffle this zone by default after viewing it
* @param _contentsKnown whether the cards in the zone are known to the client
* @param parent the parent graphics object.
- * @param _isView whether this zone is a view of another zone. Modifications to a view should modify the original
*/
CardZone::CardZone(Player *_p,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
- QGraphicsItem *parent,
- bool _isView)
+ QGraphicsItem *parent)
: AbstractGraphicsItem(parent), player(_p), name(_name), cards(_contentsKnown), views{}, menu(nullptr),
- doubleClickAction(0), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable), isView(_isView)
+ doubleClickAction(0), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable)
{
- if (!isView)
- player->addZone(this);
-
// If we join a game before the card db finishes loading, the cards might have the wrong printings.
// Force refresh all cards in the zone when db finishes loading to fix that.
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
@@ -236,4 +231,4 @@ void CardZone::moveAllToZone()
QPointF CardZone::closestGridPoint(const QPointF &point)
{
return point;
-}
\ No newline at end of file
+}
diff --git a/cockatrice/src/game/zones/card_zone.h b/cockatrice/src/game/zones/card_zone.h
index 2b9114a6d..8ce31e885 100644
--- a/cockatrice/src/game/zones/card_zone.h
+++ b/cockatrice/src/game/zones/card_zone.h
@@ -35,7 +35,6 @@ protected:
QAction *doubleClickAction;
bool hasCardAttr;
bool isShufflable;
- bool isView;
bool alwaysRevealTopCard;
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
@@ -65,8 +64,7 @@ public:
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
- QGraphicsItem *parent = nullptr,
- bool _isView = false);
+ QGraphicsItem *parent = nullptr);
void retranslateUi();
void clearContents();
bool getHasCardAttr() const
@@ -115,10 +113,6 @@ public:
}
virtual void reorganizeCards() = 0;
virtual QPointF closestGridPoint(const QPointF &point);
- bool getIsView() const
- {
- return isView;
- }
bool getAlwaysRevealTopCard() const
{
return alwaysRevealTopCard;
diff --git a/cockatrice/src/game/zones/select_zone.cpp b/cockatrice/src/game/zones/select_zone.cpp
index bb6c40683..b26aa23ff 100644
--- a/cockatrice/src/game/zones/select_zone.cpp
+++ b/cockatrice/src/game/zones/select_zone.cpp
@@ -37,9 +37,8 @@ SelectZone::SelectZone(Player *_player,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
- QGraphicsItem *parent,
- bool isView)
- : CardZone(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent, isView)
+ QGraphicsItem *parent)
+ : CardZone(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
{
}
diff --git a/cockatrice/src/game/zones/select_zone.h b/cockatrice/src/game/zones/select_zone.h
index c8c88b450..6aa56a1c6 100644
--- a/cockatrice/src/game/zones/select_zone.h
+++ b/cockatrice/src/game/zones/select_zone.h
@@ -26,8 +26,7 @@ public:
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
- QGraphicsItem *parent = nullptr,
- bool isView = false);
+ QGraphicsItem *parent = nullptr);
};
qreal divideCardSpaceInZone(qreal index, int cardCount, qreal totalHeight, qreal cardHeight, bool reverse = false);
diff --git a/cockatrice/src/game/zones/view_zone.cpp b/cockatrice/src/game/zones/view_zone.cpp
index 1c35b6613..fd9387064 100644
--- a/cockatrice/src/game/zones/view_zone.cpp
+++ b/cockatrice/src/game/zones/view_zone.cpp
@@ -30,7 +30,7 @@ ZoneViewZone::ZoneViewZone(Player *_p,
bool _writeableRevealZone,
QGraphicsItem *parent,
bool _isReversed)
- : SelectZone(_p, _origZone->getName(), false, false, true, parent, true), bRect(QRectF()), minRows(0),
+ : SelectZone(_p, _origZone->getName(), false, false, true, parent), bRect(QRectF()), minRows(0),
numberCards(_numberCards), origZone(_origZone), revealZone(_revealZone),
writeableRevealZone(_writeableRevealZone), groupBy(CardList::NoSort), sortBy(CardList::NoSort),
isReversed(_isReversed)
From 42ce9f4d8954578dba4eb41ceaec2cbd8d67d910 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sat, 26 Apr 2025 16:59:59 -0700
Subject: [PATCH 28/56] Allow tokens on the stack (#5886)
---
common/server_player.cpp | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/common/server_player.cpp b/common/server_player.cpp
index 60ebfa3c0..eb8a9977b 100644
--- a/common/server_player.cpp
+++ b/common/server_player.cpp
@@ -417,6 +417,29 @@ static Event_AttachCard makeAttachCardEvent(Server_Card *attachedCard, Server_Ca
return event;
}
+/**
+ * Determines whether moving the card from startZone to targetZone should cause the card to be destroyed.
+ */
+static bool
+shouldDestroyOnMove(const Server_Card *card, const Server_CardZone *startZone, const Server_CardZone *targetZone)
+{
+ if (!card->getDestroyOnZoneChange()) {
+ return false;
+ }
+
+ if (startZone->getName() == targetZone->getName()) {
+ return false;
+ }
+
+ // Allow tokens on the stack
+ if ((startZone->getName() == "table" || startZone->getName() == "stack") &&
+ (targetZone->getName() == "table" || targetZone->getName() == "stack")) {
+ return false;
+ }
+
+ return true;
+}
+
Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges,
Server_CardZone *startzone,
const QList &_cards,
@@ -523,7 +546,7 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges,
}
}
- if (card->getDestroyOnZoneChange() && (startzone->getName() != targetzone->getName())) {
+ if (shouldDestroyOnMove(card, startzone, targetzone)) {
Event_DestroyCard event;
event.set_zone_name(startzone->getName().toStdString());
event.set_card_id(static_cast(card->getId()));
From e3465be8c118c7f4013229471b57dd2c082c8159 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 27 Apr 2025 21:27:22 -0700
Subject: [PATCH 29/56] Allow cards to transform directly on stack (#5888)
---
cockatrice/src/game/player/player.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index c893e27af..ebbbb5291 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -2066,6 +2066,8 @@ void Player::createCard(const CardItem *sourceCard,
break;
case CardRelation::TransformInto:
+ // allow cards to directly transform on stack
+ cmd.set_zone(sourceCard->getZone()->getName() == "stack" ? "stack" : "table");
// Transform card zone changes are handled server-side
cmd.set_target_zone(sourceCard->getZone()->getName().toStdString());
cmd.set_target_card_id(sourceCard->getId());
From bb8213deb58bfce779b6bf6a6bc90de94dfdd759 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 27 Apr 2025 21:30:23 -0700
Subject: [PATCH 30/56] Support creating face-down tokens (#5800)
* add new fields to proto
* update token dlg
* send facedown in command
* update server to get it to work
* disable certain edits when face down
* update client event processing
* log face-down token creation
* Don't support colors on face-down tokens
The other client doesn't know about the color, so it causes a desync
* Update wording
Co-authored-by: Basile Clement
* Allow annotations on face-down tokens
---------
Co-authored-by: Basile Clement
---
cockatrice/src/dialogs/dlg_create_token.cpp | 22 ++++++-
cockatrice/src/dialogs/dlg_create_token.h | 3 +
cockatrice/src/game/player/player.cpp | 8 ++-
cockatrice/src/game/player/player.h | 2 +-
cockatrice/src/server/message_log_widget.cpp | 14 +++--
cockatrice/src/server/message_log_widget.h | 2 +-
common/pb/command_create_token.proto | 1 +
common/pb/event_create_token.proto | 1 +
common/server_player.cpp | 62 +++++++++++++++++---
common/server_player.h | 1 +
10 files changed, 97 insertions(+), 19 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_create_token.cpp b/cockatrice/src/dialogs/dlg_create_token.cpp
index 7b3db2773..14adaa48a 100644
--- a/cockatrice/src/dialogs/dlg_create_token.cpp
+++ b/cockatrice/src/dialogs/dlg_create_token.cpp
@@ -63,6 +63,9 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
destroyCheckBox = new QCheckBox(tr("&Destroy token when it leaves the table"));
destroyCheckBox->setChecked(true);
+ faceDownCheckBox = new QCheckBox(tr("Create face-down (Only hides name)"));
+ connect(faceDownCheckBox, &QCheckBox::toggled, this, &DlgCreateToken::faceDownCheckBoxToggled);
+
QGridLayout *grid = new QGridLayout;
grid->addWidget(nameLabel, 0, 0);
grid->addWidget(nameEdit, 0, 1);
@@ -73,6 +76,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
grid->addWidget(annotationLabel, 3, 0);
grid->addWidget(annotationEdit, 3, 1);
grid->addWidget(destroyCheckBox, 4, 0, 1, 2);
+ grid->addWidget(faceDownCheckBox, 5, 0, 1, 2);
QGroupBox *tokenDataGroupBox = new QGroupBox(tr("Token data"));
tokenDataGroupBox->setLayout(grid);
@@ -155,6 +159,21 @@ void DlgCreateToken::closeEvent(QCloseEvent *event)
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
}
+void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
+{
+ if (checked) {
+ colorEdit->setCurrentIndex(6);
+ colorEdit->setEnabled(false);
+ ptEdit->clear();
+ ptEdit->clearFocus();
+ ptEdit->setEnabled(false);
+ } else {
+ colorEdit->setEnabled(true);
+ ptEdit->setEnabled(true);
+ annotationEdit->setEnabled(true);
+ }
+}
+
void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex & /*previous*/)
{
const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current);
@@ -230,5 +249,6 @@ TokenInfo DlgCreateToken::getTokenInfo() const
.color = colorEdit->itemData(colorEdit->currentIndex()).toString(),
.pt = ptEdit->text(),
.annotation = annotationEdit->text(),
- .destroy = destroyCheckBox->isChecked()};
+ .destroy = destroyCheckBox->isChecked(),
+ .faceDown = faceDownCheckBox->isChecked()};
}
diff --git a/cockatrice/src/dialogs/dlg_create_token.h b/cockatrice/src/dialogs/dlg_create_token.h
index 373e094f1..cd1b48c81 100644
--- a/cockatrice/src/dialogs/dlg_create_token.h
+++ b/cockatrice/src/dialogs/dlg_create_token.h
@@ -24,6 +24,7 @@ struct TokenInfo
QString pt;
QString annotation;
bool destroy = true;
+ bool faceDown = false;
};
class DlgCreateToken : public QDialog
@@ -36,6 +37,7 @@ public:
protected:
void closeEvent(QCloseEvent *event) override;
private slots:
+ void faceDownCheckBoxToggled(bool checked);
void tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous);
void updateSearch(const QString &search);
void actChooseTokenFromAll(bool checked);
@@ -51,6 +53,7 @@ private:
QComboBox *colorEdit;
QLineEdit *nameEdit, *ptEdit, *annotationEdit;
QCheckBox *destroyCheckBox;
+ QCheckBox *faceDownCheckBox;
QRadioButton *chooseTokenFromAllRadioButton, *chooseTokenFromDeckRadioButton;
CardInfoPictureWidget *pic;
QTreeView *chooseTokenView;
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index ebbbb5291..160d8d336 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -1855,6 +1855,7 @@ void Player::actCreateAnotherToken()
cmd.set_pt(lastTokenInfo.pt.toStdString());
cmd.set_annotation(lastTokenInfo.annotation.toStdString());
cmd.set_destroy_on_zone_change(lastTokenInfo.destroy);
+ cmd.set_face_down(lastTokenInfo.faceDown);
cmd.set_x(-1);
cmd.set_y(lastTokenTableRow);
@@ -2233,10 +2234,10 @@ void Player::eventCreateToken(const Event_CreateToken &event)
CardItem *card = new CardItem(this, nullptr, QString::fromStdString(event.card_name()),
QString::fromStdString(event.card_provider_id()), event.card_id());
- // use db PT if not provided in event
+ // use db PT if not provided in event and not face-down
if (!QString::fromStdString(event.pt()).isEmpty()) {
card->setPT(QString::fromStdString(event.pt()));
- } else {
+ } else if (!event.face_down()) {
CardInfoPtr dbCard = card->getInfo();
if (dbCard) {
card->setPT(dbCard->getPowTough());
@@ -2245,8 +2246,9 @@ void Player::eventCreateToken(const Event_CreateToken &event)
card->setColor(QString::fromStdString(event.color()));
card->setAnnotation(QString::fromStdString(event.annotation()));
card->setDestroyOnZoneChange(event.destroy_on_zone_change());
+ card->setFaceDown(event.face_down());
- emit logCreateToken(this, card->getName(), card->getPT());
+ emit logCreateToken(this, card->getName(), card->getPT(), card->getFaceDown());
zone->addCard(card, true, event.x(), event.y());
}
diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h
index 027a7658b..ea5278572 100644
--- a/cockatrice/src/game/player/player.h
+++ b/cockatrice/src/game/player/player.h
@@ -128,7 +128,7 @@ signals:
Player *targetPlayer,
QString targetCard,
bool _playerTarget);
- void logCreateToken(Player *player, QString cardName, QString pt);
+ void logCreateToken(Player *player, QString cardName, QString pt, bool faceDown);
void logDrawCards(Player *player, int number, bool deckIsEmpty);
void logUndoDraw(Player *player, QString cardName);
void logMoveCard(Player *player, CardItem *card, CardZone *startZone, int oldX, CardZone *targetZone, int newX);
diff --git a/cockatrice/src/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 7590e044b..0d21be045 100644
--- a/cockatrice/src/server/message_log_widget.cpp
+++ b/cockatrice/src/server/message_log_widget.cpp
@@ -214,12 +214,16 @@ void MessageLogWidget::logCreateArrow(Player *player,
}
}
-void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt)
+void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt, bool faceDown)
{
- appendHtmlServerMessage(tr("%1 creates token: %2%3.")
- .arg(sanitizeHtml(player->getName()))
- .arg(cardLink(std::move(cardName)))
- .arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt))));
+ if (faceDown) {
+ appendHtmlServerMessage(tr("%1 creates a face down token.").arg(sanitizeHtml(player->getName())));
+ } else {
+ appendHtmlServerMessage(tr("%1 creates token: %2%3.")
+ .arg(sanitizeHtml(player->getName()))
+ .arg(cardLink(std::move(cardName)))
+ .arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt))));
+ }
}
void MessageLogWidget::logDeckSelect(Player *player, QString deckHash, int sideboardSize)
diff --git a/cockatrice/src/server/message_log_widget.h b/cockatrice/src/server/message_log_widget.h
index f6780b729..21b03dee9 100644
--- a/cockatrice/src/server/message_log_widget.h
+++ b/cockatrice/src/server/message_log_widget.h
@@ -41,7 +41,7 @@ public slots:
Player *targetPlayer,
QString targetCard,
bool playerTarget);
- void logCreateToken(Player *player, QString cardName, QString pt);
+ void logCreateToken(Player *player, QString cardName, QString pt, bool faceDown);
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
void logDestroyCard(Player *player, QString cardName);
void logDrawCards(Player *player, int number, bool deckIsEmpty);
diff --git a/common/pb/command_create_token.proto b/common/pb/command_create_token.proto
index 671ce3fe3..4b7d11098 100644
--- a/common/pb/command_create_token.proto
+++ b/common/pb/command_create_token.proto
@@ -27,4 +27,5 @@ message Command_CreateToken {
optional TargetMode target_mode = 11;
optional string card_provider_id = 12;
+ optional bool face_down = 13;
}
diff --git a/common/pb/event_create_token.proto b/common/pb/event_create_token.proto
index bc88a744c..6947b6048 100644
--- a/common/pb/event_create_token.proto
+++ b/common/pb/event_create_token.proto
@@ -15,4 +15,5 @@ message Event_CreateToken {
optional sint32 x = 8;
optional sint32 y = 9;
optional string card_provider_id = 10;
+ optional bool face_down = 11;
}
diff --git a/common/server_player.cpp b/common/server_player.cpp
index eb8a9977b..01f6947fa 100644
--- a/common/server_player.cpp
+++ b/common/server_player.cpp
@@ -386,13 +386,23 @@ void Server_Player::revealTopCardIfNeeded(Server_CardZone *zone, GameEventStorag
}
}
-static Event_CreateToken makeCreateTokenEvent(Server_CardZone *zone, Server_Card *card, int xCoord, int yCoord)
+/**
+ * Creates the create token event.
+ * By default, will set event's name and color fields to empty if the token is face-down
+ */
+static Event_CreateToken
+makeCreateTokenEvent(Server_CardZone *zone, Server_Card *card, int xCoord, int yCoord, bool revealFacedownInfo = false)
{
Event_CreateToken event;
event.set_zone_name(zone->getName().toStdString());
event.set_card_id(card->getId());
- event.set_card_name(card->getName().toStdString());
- event.set_card_provider_id(card->getProviderId().toStdString());
+ event.set_face_down(card->getFaceDown());
+
+ if (!card->getFaceDown() || revealFacedownInfo) {
+ event.set_card_name(card->getName().toStdString());
+ event.set_card_provider_id(card->getProviderId().toStdString());
+ }
+
event.set_color(card->getColor().toStdString());
event.set_pt(card->getPT().toStdString());
event.set_annotation(card->getAnnotation().toStdString());
@@ -401,7 +411,6 @@ static Event_CreateToken makeCreateTokenEvent(Server_CardZone *zone, Server_Card
event.set_y(yCoord);
return event;
}
-
static Event_AttachCard makeAttachCardEvent(Server_Card *attachedCard, Server_Card *parentCard = nullptr)
{
Event_AttachCard event;
@@ -1494,7 +1503,8 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
const QString cardName = nameFromStdString(cmd.card_name());
const QString cardProviderId = nameFromStdString(cmd.card_provider_id());
if (zone->hasCoords()) {
- xCoord = zone->getFreeGridColumn(xCoord, yCoord, cardName, false);
+ bool dontStackSameName = cmd.face_down();
+ xCoord = zone->getFreeGridColumn(xCoord, yCoord, cardName, dontStackSameName);
}
if (xCoord < 0) {
xCoord = 0;
@@ -1505,13 +1515,17 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
auto *card = new Server_Card(cardName, cardProviderId, newCardId(), xCoord, yCoord);
card->moveToThread(thread());
- card->setPT(nameFromStdString(cmd.pt()));
- card->setColor(nameFromStdString(cmd.color()));
+ // Client should already prevent face-down tokens from having attributes; this just an extra server-side check
+ if (!cmd.face_down()) {
+ card->setColor(nameFromStdString(cmd.color()));
+ card->setPT(nameFromStdString(cmd.pt()));
+ }
card->setAnnotation(nameFromStdString(cmd.annotation()));
card->setDestroyOnZoneChange(cmd.destroy_on_zone_change());
+ card->setFaceDown(cmd.face_down());
zone->insertCard(card, xCoord, yCoord);
- ges.enqueueGameEvent(makeCreateTokenEvent(zone, card, xCoord, yCoord), playerId);
+ sendCreateTokenEvents(zone, card, xCoord, yCoord, ges);
// check if the token is a replacement for an existing card
if (!targetCard) {
@@ -1642,6 +1656,38 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer
return Response::RespOk;
}
+/**
+ * Creates and sends the events required to properly communicate the given token creation.
+ * Primarily written to handle creating face-down tokens.
+ */
+void Server_Player::sendCreateTokenEvents(Server_CardZone *zone,
+ Server_Card *card,
+ int xCoord,
+ int yCoord,
+ GameEventStorage &ges)
+{
+ // Token is not face-down; things are easy
+ if (!card->getFaceDown()) {
+ ges.enqueueGameEvent(makeCreateTokenEvent(zone, card, xCoord, yCoord), playerId);
+ return;
+ }
+
+ // Token is face-down. We have to send different info to each player
+ auto eventOthers = makeCreateTokenEvent(zone, card, xCoord, yCoord, false);
+ ges.enqueueGameEvent(eventOthers, playerId, GameEventStorageItem::SendToOthers);
+
+ auto eventPrivate = makeCreateTokenEvent(zone, card, xCoord, yCoord, true);
+ ges.enqueueGameEvent(eventPrivate, playerId, GameEventStorageItem::SendToPrivate, playerId);
+
+ // Event_CreateToken didn't use to have face_down field; send attribute event afterward for backwards compatibility
+ Event_SetCardAttr event;
+ event.set_zone_name(zone->getName().toStdString());
+ event.set_card_id(card->getId());
+ event.set_attribute(AttrFaceDown);
+ event.set_attr_value("1");
+ ges.enqueueGameEvent(event, playerId);
+}
+
Response::ResponseCode
Server_Player::cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges)
{
diff --git a/common/server_player.h b/common/server_player.h
index ffa12f8b0..b9d414482 100644
--- a/common/server_player.h
+++ b/common/server_player.h
@@ -84,6 +84,7 @@ private:
bool conceded;
bool sideboardLocked;
void revealTopCardIfNeeded(Server_CardZone *zone, GameEventStorage &ges);
+ void sendCreateTokenEvents(Server_CardZone *zone, Server_Card *card, int xCoord, int yCoord, GameEventStorage &ges);
public:
mutable QMutex playerMutex;
From fc40fea97a2425b4a1eb4272c9b17e03a15981c2 Mon Sep 17 00:00:00 2001
From: tooomm
Date: Mon, 28 Apr 2025 06:31:00 +0200
Subject: [PATCH 31/56] Fix install Qt step (#5883)
---
.github/workflows/desktop-build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index fbb882aa2..df8ca010b 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -380,7 +380,7 @@ jobs:
uses: jurplel/install-qt-action@v4
with:
cache: true
- setup-python: false
+ setup-python: true
version: ${{matrix.qt_version}}
arch: win64_${{matrix.qt_arch}}
tools: ${{matrix.qt_tools}}
From 77d13090b57d1e5bcb6defc4057f3f9e347d7dc8 Mon Sep 17 00:00:00 2001
From: SlightlyCircuitous
<71394296+SlightlyCircuitous@users.noreply.github.com>
Date: Tue, 29 Apr 2025 22:18:18 -0400
Subject: [PATCH 32/56] Remove Fedora 40 build and Add Fedora 42 build (#5893)
* Create Fedora 42 Dockerfile
* Delete .ci/Fedora40 directory
* Update Fedora releases
* Update Fedora builds
---
.ci/{Fedora40 => Fedora42}/Dockerfile | 2 +-
.ci/release_template.md | 2 +-
.github/workflows/desktop-build.yml | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
rename .ci/{Fedora40 => Fedora42}/Dockerfile (95%)
diff --git a/.ci/Fedora40/Dockerfile b/.ci/Fedora42/Dockerfile
similarity index 95%
rename from .ci/Fedora40/Dockerfile
rename to .ci/Fedora42/Dockerfile
index 598bf7562..cf56ff604 100644
--- a/.ci/Fedora40/Dockerfile
+++ b/.ci/Fedora42/Dockerfile
@@ -1,4 +1,4 @@
-FROM fedora:40
+FROM fedora:42
RUN dnf install -y \
ccache \
diff --git a/.ci/release_template.md b/.ci/release_template.md
index c23e285c3..a7a2d31cb 100644
--- a/.ci/release_template.md
+++ b/.ci/release_template.md
@@ -23,8 +23,8 @@ Available pre-compiled binaries for installation:
• Ubuntu 20.04 LTSFocal Fossa
• Debian 12Bookworm
• Debian 11Bullseye
+ • Fedora 42
• Fedora 41
- • Fedora 40We are also packaged in Arch Linux's official extra repository, courtesy of @FFY00.General Linux support is available via a flatpak package at Flathub!
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index df8ca010b..79bc1b815 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -101,12 +101,12 @@ jobs:
package: DEB
- distro: Fedora
- version: 40
+ version: 41
package: RPM
test: skip # Running tests on all distros is superfluous
- distro: Fedora
- version: 41
+ version: 42
package: RPM
- distro: Ubuntu
From 24e27d3c31c02bf42d0946ec6135994e469542f6 Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Fri, 2 May 2025 18:58:21 +0200
Subject: [PATCH 33/56] fix: Prevent dragged cards getting stuck (#5896)
* fix: Prevent dragged cards getting stuck
Update the position of the card even if it is not above any zone.
* Also update the currentZone
---
cockatrice/src/game/board/card_drag_item.cpp | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/game/board/card_drag_item.cpp b/cockatrice/src/game/board/card_drag_item.cpp
index d21e9168b..ab4431958 100644
--- a/cockatrice/src/game/board/card_drag_item.cpp
+++ b/cockatrice/src/game/board/card_drag_item.cpp
@@ -47,10 +47,25 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
cursorZone = zoneViewZone;
else if (cardZone)
cursorZone = cardZone;
- if (!cursorZone)
- return;
+
+ // Always update the current zone, even if its null, to cancel the drag
+ // instead of dropping cards into an non-intuitive location.
currentZone = cursorZone;
+ if (!cursorZone) {
+ // Avoid the cards getting stuck visually when not over
+ // any zone.
+ QPointF newPos = cursorScenePos - hotSpot;
+
+ if (newPos != pos()) {
+ for (int i = 0; i < childDrags.size(); i++)
+ childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
+ setPos(newPos);
+ }
+
+ return;
+ }
+
QPointF zonePos = currentZone->scenePos();
QPointF cursorPosInZone = cursorScenePos - zonePos;
From 57c6f2716fe28c1d1d446f1232d35991badb037c Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Fri, 2 May 2025 10:00:32 -0700
Subject: [PATCH 34/56] Add setting for which deck editor tab to open deck in
(#5895)
* Create new setting
* Update settings dlg
* implement functionality
* Make setting into an enum
---
.../tabs/api/edhrec/tab_edhrec_main.cpp | 2 +-
cockatrice/src/client/tabs/tab_supervisor.cpp | 29 +++++++++++++++++--
cockatrice/src/client/tabs/tab_supervisor.h | 9 ++++++
.../tab_deck_storage_visual.cpp | 2 +-
cockatrice/src/dialogs/dlg_settings.cpp | 12 ++++++++
cockatrice/src/dialogs/dlg_settings.h | 2 ++
cockatrice/src/settings/cache_settings.cpp | 7 +++++
cockatrice/src/settings/cache_settings.h | 6 ++++
dbconverter/src/mocks.cpp | 3 ++
tests/carddatabase/mocks.cpp | 3 ++
10 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
index 0bd4e843a..2eed749af 100644
--- a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
+++ b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
@@ -356,7 +356,7 @@ void TabEdhRecMain::processAverageDeckResponse(QJsonObject reply)
{
EdhrecAverageDeckApiResponse deckData;
deckData.fromJson(reply);
- tabSupervisor->addVisualDeckEditorTab(deckData.deck.deckLoader);
+ tabSupervisor->openDeckInNewTab(deckData.deck.deckLoader);
}
void TabEdhRecMain::prettyPrintJson(const QJsonValue &value, int indentLevel)
diff --git a/cockatrice/src/client/tabs/tab_supervisor.cpp b/cockatrice/src/client/tabs/tab_supervisor.cpp
index 5d9600d11..4ed0e5a6b 100644
--- a/cockatrice/src/client/tabs/tab_supervisor.cpp
+++ b/cockatrice/src/client/tabs/tab_supervisor.cpp
@@ -590,7 +590,7 @@ void TabSupervisor::actTabDeckStorage(bool checked)
void TabSupervisor::openTabDeckStorage()
{
tabDeckStorage = new TabDeckStorage(this, client, userInfo);
- connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tabDeckStorage, aTabDeckStorage);
connect(tabDeckStorage, &Tab::closed, this, [this] {
tabDeckStorage = nullptr;
@@ -691,7 +691,7 @@ void TabSupervisor::gameJoined(const Event_GameJoined &event)
auto *tab = new TabGame(this, QList() << client, event, roomGameTypes);
connect(tab, &TabGame::gameClosing, this, &TabSupervisor::gameLeft);
connect(tab, &TabGame::openMessageDialog, this, &TabSupervisor::addMessageTab);
- connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tab);
gameTabs.insert(event.game_info().game_id(), tab);
setCurrentWidget(tab);
@@ -701,7 +701,7 @@ void TabSupervisor::localGameJoined(const Event_GameJoined &event)
{
auto *tab = new TabGame(this, localClients, event, QMap());
connect(tab, &TabGame::gameClosing, this, &TabSupervisor::gameLeft);
- connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tab);
gameTabs.insert(event.game_info().game_id(), tab);
setCurrentWidget(tab);
@@ -807,6 +807,29 @@ void TabSupervisor::talkLeft(TabMessage *tab)
removeTab(indexOf(tab));
}
+/**
+ * Creates a new deck editor tab and loads the deck into it.
+ * Creates either a classic or visual deck editor tab depending on settings
+ * @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
+ */
+void TabSupervisor::openDeckInNewTab(const DeckLoader *deckToOpen)
+{
+ int type = SettingsCache::instance().getDefaultDeckEditorType();
+ switch (type) {
+ case ClassicDeckEditor:
+ addDeckEditorTab(deckToOpen);
+ break;
+ case VisualDeckEditor:
+ addVisualDeckEditorTab(deckToOpen);
+ break;
+ default:
+ qCWarning(TabSupervisorLog) << "Unknown DeckEditorType [" << type
+ << "]; opening ClassicDeckEditor as fallback";
+ addDeckEditorTab(deckToOpen);
+ break;
+ }
+}
+
/**
* Creates a new deck editor tab
* @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
diff --git a/cockatrice/src/client/tabs/tab_supervisor.h b/cockatrice/src/client/tabs/tab_supervisor.h
index 0ca13ac41..1c367043e 100644
--- a/cockatrice/src/client/tabs/tab_supervisor.h
+++ b/cockatrice/src/client/tabs/tab_supervisor.h
@@ -75,6 +75,14 @@ protected:
class TabSupervisor : public QTabWidget
{
Q_OBJECT
+
+public:
+ enum DeckEditorType
+ {
+ ClassicDeckEditor,
+ VisualDeckEditor
+ };
+
private:
ServerInfo_User *userInfo;
AbstractClient *client;
@@ -152,6 +160,7 @@ signals:
void showWindowIfHidden();
public slots:
+ void openDeckInNewTab(const DeckLoader *deckToOpen);
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
TabDeckEditorVisual *addVisualDeckEditorTab(const DeckLoader *deckToOpen);
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
diff --git a/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp b/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
index 38af03c59..65b4fcab0 100644
--- a/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
+++ b/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
@@ -12,7 +12,7 @@
TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
: Tab(_tabSupervisor), visualDeckStorageWidget(new VisualDeckStorageWidget(this))
{
- connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::addVisualDeckEditorTab);
+ connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::openDeckInNewTab);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this,
&TabDeckStorageVisual::actOpenLocalDeck);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, this,
diff --git a/cockatrice/src/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp
index 502662c14..cda737951 100644
--- a/cockatrice/src/dialogs/dlg_settings.cpp
+++ b/cockatrice/src/dialogs/dlg_settings.cpp
@@ -4,6 +4,7 @@
#include "../client/network/release_channel.h"
#include "../client/network/spoiler_background_updater.h"
#include "../client/sound_engine.h"
+#include "../client/tabs/tab_supervisor.h"
#include "../client/ui/picture_loader/picture_loader.h"
#include "../client/ui/theme_manager.h"
#include "../deck/custom_line_edit.h"
@@ -699,12 +700,20 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
index == visualDeckStoragePromptForConversionIndexAlways);
});
+ defaultDeckEditorTypeSelector.addItem(""); // these will be set in retranslateUI
+ defaultDeckEditorTypeSelector.addItem("");
+ defaultDeckEditorTypeSelector.setCurrentIndex(SettingsCache::instance().getDefaultDeckEditorType());
+ connect(&defaultDeckEditorTypeSelector, QOverload::of(&QComboBox::currentIndexChanged),
+ &SettingsCache::instance(), &SettingsCache::setDefaultDeckEditorType);
+
auto *deckEditorGrid = new QGridLayout;
deckEditorGrid->addWidget(&openDeckInNewTabCheckBox, 0, 0);
deckEditorGrid->addWidget(&visualDeckStorageInGameCheckBox, 1, 0);
deckEditorGrid->addWidget(&visualDeckStorageSelectionAnimationCheckBox, 2, 0);
deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionLabel, 3, 0);
deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionSelector, 3, 1);
+ deckEditorGrid->addWidget(&defaultDeckEditorTypeLabel, 4, 0);
+ deckEditorGrid->addWidget(&defaultDeckEditorTypeSelector, 4, 1);
deckEditorGroupBox = new QGroupBox;
deckEditorGroupBox->setLayout(deckEditorGrid);
@@ -774,6 +783,9 @@ void UserInterfaceSettingsPage::retranslateUi()
tr("ask to convert to .cod"));
visualDeckStoragePromptForConversionSelector.setItemText(visualDeckStoragePromptForConversionIndexAlways,
tr("always convert to .cod"));
+ defaultDeckEditorTypeLabel.setText(tr("Default deck editor type"));
+ defaultDeckEditorTypeSelector.setItemText(TabSupervisor::ClassicDeckEditor, tr("Classic Deck Editor"));
+ defaultDeckEditorTypeSelector.setItemText(TabSupervisor::VisualDeckEditor, tr("Visual Deck Editor"));
replayGroupBox->setTitle(tr("Replay settings"));
rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:"));
rewindBufferingMsBox.setSuffix(" ms");
diff --git a/cockatrice/src/dialogs/dlg_settings.h b/cockatrice/src/dialogs/dlg_settings.h
index 6c9b8b062..3975f8519 100644
--- a/cockatrice/src/dialogs/dlg_settings.h
+++ b/cockatrice/src/dialogs/dlg_settings.h
@@ -155,6 +155,8 @@ private:
QComboBox visualDeckStoragePromptForConversionSelector;
QCheckBox visualDeckStorageInGameCheckBox;
QCheckBox visualDeckStorageSelectionAnimationCheckBox;
+ QLabel defaultDeckEditorTypeLabel;
+ QComboBox defaultDeckEditorTypeSelector;
QLabel rewindBufferingMsLabel;
QSpinBox rewindBufferingMsBox;
QGroupBox *generalGroupBox;
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index ba25590f3..395354751 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -285,6 +285,7 @@ SettingsCache::SettingsCache()
visualDeckStorageInGame = settings->value("interface/visualdeckstorageingame", true).toBool();
visualDeckStorageSelectionAnimation =
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
+ defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
visualDatabaseDisplayFilterToMostRecentSetsEnabled =
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
visualDatabaseDisplayFilterToMostRecentSetsAmount =
@@ -791,6 +792,12 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
}
+void SettingsCache::setDefaultDeckEditorType(int value)
+{
+ defaultDeckEditorType = value;
+ settings->setValue("interface/defaultDeckEditorType", defaultDeckEditorType);
+}
+
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled)
{
visualDatabaseDisplayFilterToMostRecentSetsEnabled = _enabled;
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index 78993ce4a..c922bb9e1 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -153,6 +153,7 @@ private:
bool visualDeckStorageAlwaysConvert;
bool visualDeckStorageInGame;
bool visualDeckStorageSelectionAnimation;
+ int defaultDeckEditorType;
bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
int visualDatabaseDisplayFilterToMostRecentSetsAmount;
bool horizontalHand;
@@ -488,6 +489,10 @@ public:
{
return visualDeckStorageSelectionAnimation;
}
+ int getDefaultDeckEditorType() const
+ {
+ return defaultDeckEditorType;
+ }
bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
{
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
@@ -839,6 +844,7 @@ public slots:
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
+ void setDefaultDeckEditorType(int value);
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 93048d3cf..004bf1ab1 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -256,6 +256,9 @@ void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T /* value */)
void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setDefaultDeckEditorType(int /* value */)
+{
+}
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T /* _enabled */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index a2ca73fb1..4ad635949 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -260,6 +260,9 @@ void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T /* value */)
void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setDefaultDeckEditorType(int /* value */)
+{
+}
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T /* _enabled */)
{
}
From 700feb68afb566e1df8eb1bfc9aa433847d28282 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Fri, 2 May 2025 20:34:41 +0200
Subject: [PATCH 35/56] Don't require .svg for mana symbols. (#5897)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../ui/widgets/cards/additional_info/mana_symbol_widget.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
index e42e93444..b17b0ff47 100644
--- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
@@ -66,7 +66,7 @@ void ManaSymbolWidget::loadManaIcon()
QString filename = "theme:icons/mana/";
if (symbol == "W" || symbol == "U" || symbol == "B" || symbol == "R" || symbol == "G") {
- filename += symbol + ".svg";
+ filename += symbol;
}
manaIcon = QPixmap(filename);
From baa7e25e30428dade3a39f62c70864ed996b162f Mon Sep 17 00:00:00 2001
From: Sebastian Di Luzio
Date: Sat, 3 May 2025 00:10:09 +0200
Subject: [PATCH 36/56] feat: build and release docker images using github
actions and container registry (#5807)
* feat: build and release docker images using github cicd
* fix: attempt to publish to specific image name
* fix: typo in pipeline step
* typo
* typo
* limit to certain paths for PRs & naming
* ci: configure image title and url
* docker: include only necessary files and directories
this should make caching more powerful
* docker: reorder COPY with best guess of what changes least
* build(docker): remove seemingly unnecessary files
* fix: clean up docker metadata
remove annotations, it seems they're applied from the labels already, add description
* fix(ci): add back docker image annotations
* Update desktop-build.yml
* Update desktop-lint.yml
* Update desktop-build.yml
* Update docker-release.yml
* fix: remove run on master and add affected files to PR trigger
* metadata
* ci: run pipeline on main
this will ensure the container can always build and keep caches ready for release. push should only happen on tag triggers
It also removes some files from the PR trigger that should never break the build, and would just invalidate cache.
* Update docker-release.yml
---------
Co-authored-by: tooomm
---
.github/workflows/desktop-build.yml | 1 +
.github/workflows/desktop-lint.yml | 1 +
.github/workflows/docker-release.yml | 71 ++++++++++++++++++++++++++++
Dockerfile | 6 ++-
README.md | 1 -
5 files changed, 78 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/docker-release.yml
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 79bc1b815..4d406c1b6 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -9,6 +9,7 @@ on:
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
+ - '.github/workflows/docker-release.yml'
tags:
- '*'
pull_request:
diff --git a/.github/workflows/desktop-lint.yml b/.github/workflows/desktop-lint.yml
index 4ebfd9b79..aee6e81d5 100644
--- a/.github/workflows/desktop-lint.yml
+++ b/.github/workflows/desktop-lint.yml
@@ -7,6 +7,7 @@ on:
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
+ - '.github/workflows/docker-release.yml'
jobs:
format:
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
new file mode 100644
index 000000000..439ea24cd
--- /dev/null
+++ b/.github/workflows/docker-release.yml
@@ -0,0 +1,71 @@
+name: Build Docker Container
+
+on:
+ push:
+ tags:
+ - '*Release*'
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ paths:
+ - '.github/workflows/docker-release.yml'
+ - 'CMakeLists.txt'
+ - 'Dockerfile'
+ - 'servatrice/**'
+ - 'common/**'
+ - 'cmake/**'
+ - '!**.md'
+
+jobs:
+ docker:
+ name: amd64 & arm64
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Docker metadata
+ id: metadata
+ uses: docker/metadata-action@v5
+ with:
+ images: |
+ ghcr.io/cockatrice/servatrice
+ labels: |
+ org.opencontainers.image.title=Servatrice
+ org.opencontainers.image.url=https://cockatrice.github.io/
+ org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
+ annotations: |
+ org.opencontainers.image.title=Servatrice
+ org.opencontainers.image.url=https://cockatrice.github.io/
+ org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login to GitHub Container Registry
+ if: github.ref_type == 'tag'
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ github.token }}
+
+ - name: Build and push Docker Image
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: ${{ github.ref_type == 'tag' }}
+ tags: ${{ steps.metadata.outputs.tags }}
+ labels: ${{ steps.metadata.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/Dockerfile b/Dockerfile
index 330c51b4a..2a0d10eba 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,7 +16,11 @@ RUN apt-get update && apt-get install -y\
qt6-tools-dev \
qt6-tools-dev-tools
-COPY . /home/servatrice/code/
+COPY ./CMakeLists.txt ./LICENSE ./README.md /home/servatrice/code/
+COPY ./cmake /home/servatrice/code/cmake
+COPY ./common /home/servatrice/code/common
+COPY ./servatrice /home/servatrice/code/servatrice
+
WORKDIR /home/servatrice/code
WORKDIR build
diff --git a/README.md b/README.md
index 0a8058bba..48cacff78 100644
--- a/README.md
+++ b/README.md
@@ -143,7 +143,6 @@ The following flags (with their non-default values) can be passed to `cmake`:
# Run
-
Cockatrice is the game client Oracle fetches card data Servatrice is the server
From 9ae6357c349d7d459b442b238d0cbb94a18a0934 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 4 May 2025 02:03:53 +0200
Subject: [PATCH 37/56] Properly manage hover-zoom child widget in
CardInfoPictureWidget destructor. (#5900)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../ui/widgets/cards/card_info_picture_widget.cpp | 12 ++++++++++++
.../ui/widgets/cards/card_info_picture_widget.h | 2 ++
2 files changed, 14 insertions(+)
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
index 4ee3de5eb..5e275f8e9 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
@@ -64,6 +64,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverT
});
}
+CardInfoPictureWidget::~CardInfoPictureWidget()
+{
+ enlargedPixmapWidget->hide();
+ enlargedPixmapWidget->deleteLater();
+}
+
/**
* @brief Sets the card to be displayed and updates the pixmap.
* @param card A shared pointer to the card information (CardInfoPtr).
@@ -341,6 +347,12 @@ void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
emit cardClicked();
}
+void CardInfoPictureWidget::hideEvent(QHideEvent *event)
+{
+ enlargedPixmapWidget->hide();
+ QWidget::hideEvent(event);
+}
+
QMenu *CardInfoPictureWidget::createRightClickMenu()
{
auto *cardMenu = new QMenu(this);
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
index 10cc422aa..79de74526 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
@@ -21,6 +21,7 @@ public:
explicit CardInfoPictureWidget(QWidget *parent = nullptr,
bool hoverToZoomEnabled = false,
bool raiseOnEnter = false);
+ ~CardInfoPictureWidget();
CardInfoPtr getInfo()
{
return info;
@@ -52,6 +53,7 @@ protected:
void moveEvent(QMoveEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
+ void hideEvent(QHideEvent *event) override;
void loadPixmap();
[[nodiscard]] const QPixmap &getResizedPixmap() const
{
From 2687a3401944e5215b6a19d4b39bb0189aa0f757 Mon Sep 17 00:00:00 2001
From: Bruno Alexandre Rosa <1791393+brunoalr@users.noreply.github.com>
Date: Sun, 4 May 2025 13:02:11 +0000
Subject: [PATCH 38/56] ci: temporarily remove run-vcpkg step (#5902)
There is an issue with run-vcpkg GHA not caching properly. This ends up wasting 20 minutes of redundant vcpkg depency compilation.
See https://github.com/lukka/run-vcpkg/issues/243
---
.github/workflows/desktop-build.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 4d406c1b6..bd7fd37e2 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -387,7 +387,9 @@ jobs:
tools: ${{matrix.qt_tools}}
modules: ${{matrix.qt_modules}}
- - name: Run vcpkg
+ # TODO: re-enable when https://github.com/lukka/run-vcpkg/issues/243 is fixed
+ - if: false
+ name: Run vcpkg (disabled)
uses: lukka/run-vcpkg@v11
with:
runVcpkgInstall: true
From 69107f79e39e8446a9f7a740e661cc05f9442541 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 4 May 2025 17:09:11 -0700
Subject: [PATCH 39/56] Add setting to auto focus search bar when opening card
view window (#5906)
* add new setting
* implement thing
* Rename setting
* fix build failure
---
cockatrice/src/dialogs/dlg_settings.cpp | 10 ++++++++--
cockatrice/src/dialogs/dlg_settings.h | 1 +
cockatrice/src/game/zones/view_zone_widget.cpp | 5 +++++
cockatrice/src/settings/cache_settings.cpp | 7 +++++++
cockatrice/src/settings/cache_settings.h | 6 ++++++
dbconverter/src/mocks.cpp | 3 +++
tests/carddatabase/mocks.cpp | 3 +++
7 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp
index cda737951..63901325f 100644
--- a/cockatrice/src/dialogs/dlg_settings.cpp
+++ b/cockatrice/src/dialogs/dlg_settings.cpp
@@ -630,6 +630,10 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
connect(&closeEmptyCardViewCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setCloseEmptyCardView);
+ focusCardViewSearchBarCheckBox.setChecked(SettingsCache::instance().getFocusCardViewSearchBar());
+ connect(&focusCardViewSearchBarCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setFocusCardViewSearchBar);
+
annotateTokensCheckBox.setChecked(SettingsCache::instance().getAnnotateTokens());
connect(&annotateTokensCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setAnnotateTokens);
@@ -643,8 +647,9 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
generalGrid->addWidget(&clickPlaysAllSelectedCheckBox, 1, 0);
generalGrid->addWidget(&playToStackCheckBox, 2, 0);
generalGrid->addWidget(&closeEmptyCardViewCheckBox, 3, 0);
- generalGrid->addWidget(&annotateTokensCheckBox, 4, 0);
- generalGrid->addWidget(&useTearOffMenusCheckBox, 5, 0);
+ generalGrid->addWidget(&focusCardViewSearchBarCheckBox, 4, 0);
+ generalGrid->addWidget(&annotateTokensCheckBox, 5, 0);
+ generalGrid->addWidget(&useTearOffMenusCheckBox, 6, 0);
generalGroupBox = new QGroupBox;
generalGroupBox->setLayout(generalGrid);
@@ -763,6 +768,7 @@ void UserInterfaceSettingsPage::retranslateUi()
clickPlaysAllSelectedCheckBox.setText(tr("&Clicking plays all selected cards (instead of just the clicked card)"));
playToStackCheckBox.setText(tr("&Play all nonlands onto the stack (not the battlefield) by default"));
closeEmptyCardViewCheckBox.setText(tr("Close card view window when last card is removed"));
+ focusCardViewSearchBarCheckBox.setText(tr("Auto focus search bar when card view window is opened"));
annotateTokensCheckBox.setText(tr("Annotate card text on tokens"));
useTearOffMenusCheckBox.setText(tr("Use tear-off menus, allowing right click menus to persist on screen"));
notificationsGroupBox->setTitle(tr("Notifications settings"));
diff --git a/cockatrice/src/dialogs/dlg_settings.h b/cockatrice/src/dialogs/dlg_settings.h
index 3975f8519..54b2cbcd8 100644
--- a/cockatrice/src/dialogs/dlg_settings.h
+++ b/cockatrice/src/dialogs/dlg_settings.h
@@ -147,6 +147,7 @@ private:
QCheckBox clickPlaysAllSelectedCheckBox;
QCheckBox playToStackCheckBox;
QCheckBox closeEmptyCardViewCheckBox;
+ QCheckBox focusCardViewSearchBarCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox useTearOffMenusCheckBox;
QCheckBox tapAnimationCheckBox;
diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp
index 1721831ac..f0430f549 100644
--- a/cockatrice/src/game/zones/view_zone_widget.cpp
+++ b/cockatrice/src/game/zones/view_zone_widget.cpp
@@ -56,6 +56,11 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(&searchEdit); });
+ if (SettingsCache::instance().getFocusCardViewSearchBar()) {
+ this->setActive(true);
+ searchEdit.setFocus();
+ }
+
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
searchEditProxy->setWidget(&searchEdit);
searchEditProxy->setZValue(2000000007);
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index 395354751..6507780fe 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -251,6 +251,7 @@ SettingsCache::SettingsCache()
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
cardViewExpandedRowsMax = settings->value("interface/cardViewExpandedRowsMax", 20).toInt();
closeEmptyCardView = settings->value("interface/closeEmptyCardView", true).toBool();
+ focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
@@ -370,6 +371,12 @@ void SettingsCache::setCloseEmptyCardView(QT_STATE_CHANGED_T value)
settings->setValue("interface/closeEmptyCardView", closeEmptyCardView);
}
+void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T value)
+{
+ focusCardViewSearchBar = value;
+ settings->setValue("interface/focusCardViewSearchBar", focusCardViewSearchBar);
+}
+
void SettingsCache::setKnownMissingFeatures(const QString &_knownMissingFeatures)
{
knownMissingFeatures = _knownMissingFeatures;
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index c922bb9e1..bb4bed95f 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -184,6 +184,7 @@ private:
int cardViewInitialRowsMax;
int cardViewExpandedRowsMax;
bool closeEmptyCardView;
+ bool focusCardViewSearchBar;
int pixmapCacheSize;
int networkCacheSize;
int redirectCacheTtl;
@@ -699,6 +700,7 @@ public:
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
void setCardViewExpandedRowsMax(int value);
void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
+ void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
QString getClientID()
{
return clientID;
@@ -727,6 +729,10 @@ public:
{
return closeEmptyCardView;
}
+ bool getFocusCardViewSearchBar() const
+ {
+ return focusCardViewSearchBar;
+ }
ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 004bf1ab1..890294870 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -64,6 +64,9 @@ void SettingsCache::setCardViewExpandedRowsMax(int /* value */)
void SettingsCache::setCloseEmptyCardView(const QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T /* value */)
+{
+}
void SettingsCache::setKnownMissingFeatures(const QString & /* _knownMissingFeatures */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index 4ad635949..b34c28727 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -68,6 +68,9 @@ void SettingsCache::setCardViewExpandedRowsMax(int /* value */)
void SettingsCache::setCloseEmptyCardView(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T /* value */)
+{
+}
void SettingsCache::setKnownMissingFeatures(const QString & /* _knownMissingFeatures */)
{
}
From bd8306bd33d1b77844d47614c9daea7d3d1ec14a Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 06:38:46 -0700
Subject: [PATCH 40/56] Strip color escape codes in Debug Log window (#5915)
---
cockatrice/src/dialogs/dlg_view_log.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index dc569c92c..7b4e8c617 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -4,6 +4,7 @@
#include "../utility/logger.h"
#include
+#include
#include
DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
@@ -44,7 +45,12 @@ void DlgViewLog::loadInitialLogBuffer()
void DlgViewLog::logEntryAdded(QString message)
{
- logArea->appendPlainText(message);
+ static auto colorEscapeCodePattern = QRegularExpression("\033\\[\\d+m");
+
+ QString sanitizedMessage = message;
+ sanitizedMessage.replace(colorEscapeCodePattern, "");
+
+ logArea->appendPlainText(sanitizedMessage);
}
void DlgViewLog::closeEvent(QCloseEvent * /* event */)
From 4a54412d47e9b7811d2039ac63112c9011314dd2 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 06:46:29 -0700
Subject: [PATCH 41/56] Pass log messages by const ref (#5914)
* Pass log messages by const ref
* Rename method
---
cockatrice/src/dialogs/dlg_view_log.cpp | 6 +++---
cockatrice/src/dialogs/dlg_view_log.h | 2 +-
cockatrice/src/utility/logger.cpp | 4 ++--
cockatrice/src/utility/logger.h | 6 +++---
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index 7b4e8c617..35accf80f 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -28,7 +28,7 @@ DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
resize(800, 500);
loadInitialLogBuffer();
- connect(&Logger::getInstance(), &Logger::logEntryAdded, this, &DlgViewLog::logEntryAdded);
+ connect(&Logger::getInstance(), &Logger::logEntryAdded, this, &DlgViewLog::appendLogEntry);
}
void DlgViewLog::actCheckBoxChanged(bool abNewValue)
@@ -40,10 +40,10 @@ void DlgViewLog::loadInitialLogBuffer()
{
QList logBuffer = Logger::getInstance().getLogBuffer();
for (const QString &message : logBuffer)
- logEntryAdded(message);
+ appendLogEntry(message);
}
-void DlgViewLog::logEntryAdded(QString message)
+void DlgViewLog::appendLogEntry(const QString &message)
{
static auto colorEscapeCodePattern = QRegularExpression("\033\\[\\d+m");
diff --git a/cockatrice/src/dialogs/dlg_view_log.h b/cockatrice/src/dialogs/dlg_view_log.h
index 3845f0062..870c23fc5 100644
--- a/cockatrice/src/dialogs/dlg_view_log.h
+++ b/cockatrice/src/dialogs/dlg_view_log.h
@@ -22,7 +22,7 @@ private:
void loadInitialLogBuffer();
private slots:
- void logEntryAdded(QString message);
+ void appendLogEntry(const QString &message);
void actCheckBoxChanged(bool abNewValue);
};
diff --git a/cockatrice/src/utility/logger.cpp b/cockatrice/src/utility/logger.cpp
index 74ed90597..0184146ae 100644
--- a/cockatrice/src/utility/logger.cpp
+++ b/cockatrice/src/utility/logger.cpp
@@ -81,12 +81,12 @@ void Logger::closeLogfileSession()
fileHandle.close();
}
-void Logger::log(QtMsgType /* type */, const QMessageLogContext & /* ctx */, const QString message)
+void Logger::log(QtMsgType /* type */, const QMessageLogContext & /* ctx */, const QString &message)
{
QMetaObject::invokeMethod(this, "internalLog", Qt::QueuedConnection, Q_ARG(const QString &, message));
}
-void Logger::internalLog(QString message)
+void Logger::internalLog(const QString &message)
{
QMutexLocker locker(&mutex);
diff --git a/cockatrice/src/utility/logger.h b/cockatrice/src/utility/logger.h
index 246e9204a..b90644b36 100644
--- a/cockatrice/src/utility/logger.h
+++ b/cockatrice/src/utility/logger.h
@@ -28,7 +28,7 @@ public:
}
void logToFile(bool enabled);
- void log(QtMsgType type, const QMessageLogContext &ctx, QString message);
+ void log(QtMsgType type, const QMessageLogContext &ctx, const QString &message);
QString getClientVersion();
QString getClientOperatingSystem();
QString getSystemArchitecture();
@@ -57,10 +57,10 @@ protected:
void closeLogfileSession();
protected slots:
- void internalLog(QString message);
+ void internalLog(const QString &message);
signals:
- void logEntryAdded(QString message);
+ void logEntryAdded(const QString &message);
};
#endif
From 29d93fb9c1ad08dab9aeef135c1f581466ba2214 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 06:50:34 -0700
Subject: [PATCH 42/56] Delete CardDragItem when referenced CardItem is
destroyed (#5911)
---
cockatrice/src/game/board/abstract_card_drag_item.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cockatrice/src/game/board/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp
index 0c7acd917..a7234c3d4 100644
--- a/cockatrice/src/game/board/abstract_card_drag_item.cpp
+++ b/cockatrice/src/game/board/abstract_card_drag_item.cpp
@@ -39,6 +39,8 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
prepareGeometryChange();
update();
});
+
+ connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
}
AbstractCardDragItem::~AbstractCardDragItem()
From a07c1badd8e72a58add5a3cc683f20209f3dd25a Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 08:45:22 -0700
Subject: [PATCH 43/56] Add "copy to clipboard" button to Debug Log window
(#5913)
---
cockatrice/src/dialogs/dlg_view_log.cpp | 25 +++++++++++++++++++++++--
cockatrice/src/dialogs/dlg_view_log.h | 2 ++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index 35accf80f..b60a9767b 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -3,24 +3,40 @@
#include "../settings/cache_settings.h"
#include "../utility/logger.h"
+#include
#include
+#include
#include
#include
DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
{
-
logArea = new QPlainTextEdit;
logArea->setReadOnly(true);
auto *mainLayout = new QVBoxLayout;
+ mainLayout->setSpacing(3);
+ mainLayout->setContentsMargins(20, 20, 20, 6);
+
mainLayout->addWidget(logArea);
+ auto *bottomLayout = new QHBoxLayout;
+
coClearLog = new QCheckBox;
coClearLog->setText(tr("Clear log when closing"));
coClearLog->setChecked(SettingsCache::instance().servers().getClearDebugLogStatus(false));
connect(coClearLog, &QCheckBox::toggled, this, &DlgViewLog::actCheckBoxChanged);
- mainLayout->addWidget(coClearLog);
+
+ copyToClipboardButton = new QPushButton;
+ copyToClipboardButton->setText(tr("Copy to clipboard"));
+ copyToClipboardButton->setAutoDefault(false);
+ connect(copyToClipboardButton, &QPushButton::clicked, this, &DlgViewLog::actCopyToClipboard);
+
+ bottomLayout->addWidget(coClearLog);
+ bottomLayout->addStretch();
+ bottomLayout->addWidget(copyToClipboardButton);
+
+ mainLayout->addLayout(bottomLayout);
setLayout(mainLayout);
@@ -36,6 +52,11 @@ void DlgViewLog::actCheckBoxChanged(bool abNewValue)
SettingsCache::instance().servers().setClearDebugLogStatus(abNewValue);
}
+void DlgViewLog::actCopyToClipboard()
+{
+ QApplication::clipboard()->setText(logArea->toPlainText());
+}
+
void DlgViewLog::loadInitialLogBuffer()
{
QList logBuffer = Logger::getInstance().getLogBuffer();
diff --git a/cockatrice/src/dialogs/dlg_view_log.h b/cockatrice/src/dialogs/dlg_view_log.h
index 870c23fc5..26d6ad5e1 100644
--- a/cockatrice/src/dialogs/dlg_view_log.h
+++ b/cockatrice/src/dialogs/dlg_view_log.h
@@ -19,11 +19,13 @@ protected:
private:
QPlainTextEdit *logArea;
QCheckBox *coClearLog;
+ QPushButton *copyToClipboardButton;
void loadInitialLogBuffer();
private slots:
void appendLogEntry(const QString &message);
void actCheckBoxChanged(bool abNewValue);
+ void actCopyToClipboard();
};
#endif
\ No newline at end of file
From 286a7494d3a79ba1ce0134452a3de453d3bc6dae Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Wed, 7 May 2025 03:18:08 +0200
Subject: [PATCH 44/56] client: Support arbitrary game zones (#5877)
* Remove `isView` flag from CardZone
This flag is used for two purposes:
1. It is used as a check for casting to a zone to a `ZoneViewZone`;
2. Non-view zones are added to the player's zones on construction
This patch removes the `isView` flag and instead:
1. We directly cast zones to `ZoneViewZone` using a dynamic (qobject)
cast and use the result of the cast instead of the `isView` flag to
detect if we are a view zone or not;
2. The player records its own zones when they are created, simplifying
control flow.
* Review
* client: Support arbitrary game zones
Currently, the client ignores cards in unknown zones, as there is an
implicit assumption that the set of zones known by the server and the
client are the same.
This patch makes it so that the client accept "custom zones" from the
server (zones outside the builtin deck, graveyard, exile, sideboard,
table, stack and hand zones) using the information from the
ServerInfo_CardZone. Moving cards from/into these zones happens
through a "View custom zone" action in the Game > Player menu and
properly appears in the chat.
Note that this patch intentionally does not introduce any support for
having the server actually create such zones. Instead, this patch aims
to improve backwards compatibility for when we do get to adding this
capability in the future, by making sure that current clients will be
able to interact with future new zones (even if suboptimally).
---
cockatrice/src/game/player/player.cpp | 75 +++++++++++++++++++-
cockatrice/src/game/player/player.h | 2 +-
cockatrice/src/game/zones/card_zone.cpp | 4 ++
cockatrice/src/game/zones/table_zone.cpp | 4 +-
cockatrice/src/game/zones/table_zone.h | 2 +-
cockatrice/src/server/message_log_widget.cpp | 7 +-
common/pb/serverinfo_zone.proto | 4 ++
7 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index 160d8d336..9fff6b3df 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -144,7 +144,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
PileZone *sb = addZone(new PileZone(this, "sb", false, false, playerArea));
sb->setVisible(false);
- table = addZone(new TableZone(this, this));
+ table = addZone(new TableZone(this, "table", this));
connect(table, &TableZone::sizeChanged, this, &Player::updateBoundingRect);
stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this));
@@ -400,6 +400,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
sbMenu->addAction(aViewSideboard);
sb->setMenu(sbMenu, aViewSideboard);
+ mCustomZones = playerMenu->addMenu(QString());
+ mCustomZones->menuAction()->setVisible(false);
+
aUntapAll = new QAction(this);
connect(aUntapAll, &QAction::triggered, this, &Player::actUntapAll);
@@ -455,6 +458,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
if (!local && !judge) {
countersMenu = nullptr;
sbMenu = nullptr;
+ mCustomZones = nullptr;
aCreateAnotherToken = nullptr;
createPredefinedTokenMenu = nullptr;
}
@@ -829,6 +833,11 @@ void Player::retranslateUi()
sbMenu->setTitle(tr("&Sideboard"));
libraryMenu->setTitle(tr("&Library"));
countersMenu->setTitle(tr("&Counters"));
+ mCustomZones->setTitle(tr("C&ustom Zones"));
+
+ for (auto aViewZone : mCustomZones->actions()) {
+ aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString()));
+ }
aUntapAll->setText(tr("&Untap all permanents"));
aRollDie->setText(tr("R&oll die..."));
@@ -2715,19 +2724,79 @@ void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*op
void Player::processPlayerInfo(const ServerInfo_Player &info)
{
+ static QSet builtinZones{/* PileZones */
+ "deck", "grave", "rfg", "sb",
+ /* TableZone */
+ "table",
+ /* StackZone */
+ "stack",
+ /* HandZone */
+ "hand"};
clearCounters();
clearArrows();
- QMapIterator zoneIt(zones);
+ QMutableMapIterator zoneIt(zones);
while (zoneIt.hasNext()) {
zoneIt.next().value()->clearContents();
+
+ if (!builtinZones.contains(zoneIt.key())) {
+ zoneIt.remove();
+ }
+ }
+
+ // Can be null if we are not the local player!
+ if (mCustomZones) {
+ mCustomZones->clear();
+ mCustomZones->menuAction()->setVisible(false);
}
const int zoneListSize = info.zone_list_size();
for (int i = 0; i < zoneListSize; ++i) {
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
- CardZone *zone = zones.value(QString::fromStdString(zoneInfo.name()), 0);
+
+ QString zoneName = QString::fromStdString(zoneInfo.name());
+ CardZone *zone = zones.value(zoneName, 0);
if (!zone) {
+ // Create a new CardZone if it doesn't exist
+
+ if (zoneInfo.with_coords()) {
+ // Visibility not currently supported for TableZone
+ zone = addZone(new TableZone(this, zoneName, this));
+ } else {
+ // Zones without coordinats are always treated as non-shufflable
+ // PileZones, although supporting alternate hand or stack zones
+ // might make sense in some scenarios.
+ bool contentsKnown;
+
+ switch (zoneInfo.type()) {
+ case ServerInfo_Zone::PrivateZone:
+ contentsKnown = local || judge || (game->getSpectator() && game->getSpectatorsSeeEverything());
+ break;
+
+ case ServerInfo_Zone::PublicZone:
+ contentsKnown = true;
+ break;
+
+ case ServerInfo_Zone::HiddenZone:
+ contentsKnown = false;
+ break;
+ }
+
+ zone = addZone(new PileZone(this, zoneName, /* isShufflable */ false, contentsKnown, this));
+ }
+
+ // Non-builtin zones are hidden by default and can't be interacted
+ // with, except through menus.
+ zone->setVisible(false);
+
+ if (mCustomZones) {
+ mCustomZones->menuAction()->setVisible(true);
+ QAction *aViewZone = mCustomZones->addAction(tr("View custom zone '%1'").arg(zoneName));
+ aViewZone->setData(zoneName);
+ connect(aViewZone, &QAction::triggered, this,
+ [zoneName, this]() { static_cast(scene())->toggleZoneView(this, zoneName, -1); });
+ }
+
continue;
}
diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h
index ea5278572..d802ef796 100644
--- a/cockatrice/src/game/player/player.h
+++ b/cockatrice/src/game/player/player.h
@@ -253,7 +253,7 @@ public:
private:
TabGame *game;
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mLendLibrary, *mRevealTopCard,
- *mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard;
+ *mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard, *mCustomZones;
TearOffMenu *moveGraveMenu, *moveRfgMenu, *graveMenu, *moveHandMenu, *handMenu, *libraryMenu, *topLibraryMenu,
*bottomLibraryMenu, *rfgMenu, *playerMenu;
QList playerLists;
diff --git a/cockatrice/src/game/zones/card_zone.cpp b/cockatrice/src/game/zones/card_zone.cpp
index 05b4c35b9..089ed0a2d 100644
--- a/cockatrice/src/game/zones/card_zone.cpp
+++ b/cockatrice/src/game/zones/card_zone.cpp
@@ -92,6 +92,10 @@ QString CardZone::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
default:
break;
}
+ else {
+ return (theirOwn ? tr("their custom zone '%1'", "nominative").arg(name)
+ : tr("%1's custom zone '%2'", "nominative").arg(ownerName).arg(name));
+ }
return QString();
}
diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp
index e214b2e09..cee782560 100644
--- a/cockatrice/src/game/zones/table_zone.cpp
+++ b/cockatrice/src/game/zones/table_zone.cpp
@@ -19,8 +19,8 @@ const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
const QColor TableZone::GRADIENT_COLOR = QColor(255, 255, 255, 150);
const QColor TableZone::GRADIENT_COLORLESS = QColor(255, 255, 255, 0);
-TableZone::TableZone(Player *_p, QGraphicsItem *parent)
- : SelectZone(_p, "table", true, false, true, parent), active(false)
+TableZone::TableZone(Player *_p, const QString &name, QGraphicsItem *parent)
+ : SelectZone(_p, name, true, false, true, parent), active(false)
{
connect(themeManager, &ThemeManager::themeChanged, this, &TableZone::updateBg);
connect(&SettingsCache::instance(), &SettingsCache::invertVerticalCoordinateChanged, this,
diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h
index f3fbdccb6..3d464e6f3 100644
--- a/cockatrice/src/game/zones/table_zone.h
+++ b/cockatrice/src/game/zones/table_zone.h
@@ -98,7 +98,7 @@ public:
@param _p the Player
@param parent defaults to null
*/
- explicit TableZone(Player *_p, QGraphicsItem *parent = nullptr);
+ explicit TableZone(Player *_p, const QString &name, QGraphicsItem *parent = nullptr);
/**
@return a QRectF of the TableZone bounding box.
diff --git a/cockatrice/src/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 0d21be045..a61a7ba2c 100644
--- a/cockatrice/src/server/message_log_widget.cpp
+++ b/cockatrice/src/server/message_log_widget.cpp
@@ -86,6 +86,8 @@ QPair MessageLogWidget::getFromStr(CardZone *zone, QString car
fromStr = tr(" from sideboard");
} else if (zoneName == STACK_ZONE_NAME) {
fromStr = tr(" from the stack");
+ } else {
+ fromStr = tr(" from custom zone '%1'").arg(zoneName);
}
if (!cardNameContainsStartZone) {
@@ -321,13 +323,16 @@ void MessageLogWidget::logMoveCard(Player *player,
} else if (targetZoneName == STACK_ZONE_NAME) {
soundEngine->playSound("play_card");
finalStr = tr("%1 plays %2%3.");
+ } else {
+ finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
}
if (usesNewX) {
appendHtmlServerMessage(
finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second).arg(newX));
} else {
- appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second));
+ appendHtmlServerMessage(
+ finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second).arg(targetZoneName));
}
}
diff --git a/common/pb/serverinfo_zone.proto b/common/pb/serverinfo_zone.proto
index 0efa2d9be..f0ad5d709 100644
--- a/common/pb/serverinfo_zone.proto
+++ b/common/pb/serverinfo_zone.proto
@@ -11,6 +11,10 @@ message ServerInfo_Zone {
// setting beingLookedAt to true.
// Cards in a zone with the type HiddenZone are referenced by their
// list index, whereas cards in any other zone are referenced by their ids.
+ //
+ // WARNING: Adding new zone types will break compatibility with older
+ // clients. Older clients will read new zone types as PrivateZone, which
+ // is likely *NOT* what you want.
PrivateZone = 0;
PublicZone = 1;
From 4c3cfc8c2d5d00ec95993e8cc10fc390d83673ac Mon Sep 17 00:00:00 2001
From: Bruno Alexandre Rosa <1791393+brunoalr@users.noreply.github.com>
Date: Wed, 7 May 2025 01:18:59 +0000
Subject: [PATCH 45/56] fix: fix qt5 builds on macos 15 (#5923)
Although this config is not built on CI, while trying to compile locally, the build failed due to warnings and -Werror.
Some qt functions were actually deprecated (but not removed) before version 6.0.0 and clang (righfully) complains about comparison between different types of enums.
---
cockatrice/src/server/remote/remote_client.cpp | 2 +-
cockatrice/src/settings/shortcut_treeview.cpp | 2 +-
cockatrice/src/utility/card_info_comparator.cpp | 12 ++++++------
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/cockatrice/src/server/remote/remote_client.cpp b/cockatrice/src/server/remote/remote_client.cpp
index a573765af..1d8579c14 100644
--- a/cockatrice/src/server/remote/remote_client.cpp
+++ b/cockatrice/src/server/remote/remote_client.cpp
@@ -43,7 +43,7 @@ RemoteClient::RemoteClient(QObject *parent)
connect(socket, &QTcpSocket::connected, this, &RemoteClient::slotConnected);
connect(socket, &QTcpSocket::readyRead, this, &RemoteClient::readData);
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
connect(socket, &QTcpSocket::errorOccurred, this, &RemoteClient::slotSocketError);
#else
connect(socket, qOverload(&QTcpSocket::error), this, &RemoteClient::slotSocketError);
diff --git a/cockatrice/src/settings/shortcut_treeview.cpp b/cockatrice/src/settings/shortcut_treeview.cpp
index 02bc08164..6b329b23d 100644
--- a/cockatrice/src/settings/shortcut_treeview.cpp
+++ b/cockatrice/src/settings/shortcut_treeview.cpp
@@ -150,7 +150,7 @@ void ShortcutTreeView::currentChanged(const QModelIndex ¤t, const QModelIn
*/
void ShortcutTreeView::updateSearchString(const QString &searchString)
{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#if QT_VERSION > QT_VERSION_CHECK(5, 14, 0)
const auto skipEmptyParts = Qt::SkipEmptyParts;
#else
const auto skipEmptyParts = QString::SkipEmptyParts;
diff --git a/cockatrice/src/utility/card_info_comparator.cpp b/cockatrice/src/utility/card_info_comparator.cpp
index 26d00420f..821cc8675 100644
--- a/cockatrice/src/utility/card_info_comparator.cpp
+++ b/cockatrice/src/utility/card_info_comparator.cpp
@@ -37,17 +37,17 @@ bool CardInfoComparator::compareVariants(const QVariant &a, const QVariant &b) c
// Perform type-specific comparison
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- switch (a.typeId()) {
+ switch (static_cast(a.typeId())) {
#else
- switch (a.type()) {
+ switch (static_cast(a.type())) {
#endif
- case QMetaType::Int:
+ case static_cast(QMetaType::Int):
return a.toInt() < b.toInt();
- case QMetaType::Double:
+ case static_cast(QMetaType::Double):
return a.toDouble() < b.toDouble();
- case QMetaType::QString:
+ case static_cast(QMetaType::QString):
return a.toString() < b.toString();
- case QMetaType::Bool:
+ case static_cast(QMetaType::Bool):
return a.toBool() < b.toBool();
default:
// Default to comparing as strings
From fb6af544e210b1ddd48ca4ec13a22dc3a792075d Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:20:38 +0200
Subject: [PATCH 46/56] Set Banner Card again when restoring index on deckList
data changes. (#5922)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Set Banner Card again when restoring index on deckList data changes.
* Lint.
---------
Co-authored-by: Lukas Brübach
---
.../ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index 9adf8e095..2fde0b305 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -294,6 +294,10 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
int restoredIndex = bannerCardComboBox->findText(currentText);
if (restoredIndex != -1) {
bannerCardComboBox->setCurrentIndex(restoredIndex);
+ if (deckModel->getDeckList()->getBannerCard().second !=
+ bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap()["uuid"].toString()) {
+ setBannerCard(restoredIndex);
+ }
} else {
// Add a placeholder "-" and set it as the current selection
int bannerIndex = bannerCardComboBox->findText(deckModel->getDeckList()->getBannerCard().first);
From f16ba6861b7eb461441dc0a0d41219649c5c88c6 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:22:37 +0200
Subject: [PATCH 47/56] Forward scroll event to scrollable parents if possible
in NoScrollFilter. (#5921)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../deck_preview/deck_preview_widget.h | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h
index a9df635e5..8b594a9db 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h
@@ -7,6 +7,8 @@
#include "../visual_deck_storage_widget.h"
#include "deck_preview_deck_tags_display_widget.h"
+#include
+#include
#include
#include
#include
@@ -74,7 +76,22 @@ protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
if (event->type() == QEvent::Wheel) {
- return true; // Blocks the event
+ if (auto *combo = qobject_cast(obj)) {
+ // If popup is not open, forward event to parent scroll area
+ if (!combo->view()->isVisible()) {
+ // Try to find a scrollable parent and manually send the event
+ QWidget *parent = combo->parentWidget();
+ while (parent) {
+ if (auto *scroll = qobject_cast(parent)) {
+ QApplication::sendEvent(scroll->viewport(), event);
+ return true; // Mark event as handled
+ }
+ parent = parent->parentWidget();
+ }
+ // If no scrollable parent found, just block
+ return true;
+ }
+ }
}
return QObject::eventFilter(obj, event);
}
From 46e146b34a211e6876095a5e965cf0f7e7b7714f Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:23:49 +0200
Subject: [PATCH 48/56] [VDS] Allow tags to toggle to a NOT state to hide
non-matching decks (#5920)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Allow excluding tags.
* Lint.
* My linter is broken, don't ask.
* Zzz.
---------
Co-authored-by: Lukas Brübach
---
.../deck_preview_tag_display_widget.cpp | 58 +++++++++++++------
.../deck_preview_tag_display_widget.h | 23 +++++---
.../visual_deck_storage_tag_filter_widget.cpp | 42 +++++++++-----
3 files changed, 82 insertions(+), 41 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
index 324cc7288..4cfd9447d 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
@@ -6,7 +6,7 @@
#include
DeckPreviewTagDisplayWidget::DeckPreviewTagDisplayWidget(QWidget *parent, const QString &_tagName)
- : QWidget(parent), tagName(_tagName), isSelected(false)
+ : QWidget(parent), tagName(_tagName), state(TagState::NotSelected)
{
// Create layout
auto *layout = new QHBoxLayout(this);
@@ -48,36 +48,58 @@ QSize DeckPreviewTagDisplayWidget::sizeHint() const
void DeckPreviewTagDisplayWidget::mousePressEvent(QMouseEvent *event)
{
- if (event->button() == Qt::LeftButton) {
- setSelected(!isSelected);
- emit tagClicked();
+ switch (event->button()) {
+ case Qt::LeftButton:
+ setState(TagState::Selected);
+ break;
+ case Qt::RightButton:
+ setState(TagState::Excluded);
+ break;
+ case Qt::MiddleButton:
+ setState(TagState::NotSelected);
+ break;
+ default:
+ break;
}
- QWidget::mousePressEvent(event);
-}
-void DeckPreviewTagDisplayWidget::setSelected(bool selected)
-{
- isSelected = selected;
- update(); // Trigger a repaint
+ emit tagClicked();
+ QWidget::mousePressEvent(event);
}
void DeckPreviewTagDisplayWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
- // Set background color
- QColor backgroundColor = isSelected ? QColor(173, 216, 230) : Qt::white;
+ QColor backgroundColor;
+ QColor borderColor;
+ int borderWidth;
+
+ switch (state) {
+ case TagState::Selected:
+ backgroundColor = QColor(173, 216, 230); // Light blue
+ borderColor = Qt::blue;
+ borderWidth = 2;
+ break;
+ case TagState::Excluded:
+ backgroundColor = QColor(255, 182, 193); // Light red/pink
+ borderColor = Qt::red;
+ borderWidth = 2;
+ break;
+ case TagState::NotSelected:
+ default:
+ backgroundColor = Qt::white;
+ borderColor = Qt::gray;
+ borderWidth = 1;
+ break;
+ }
+
painter.setBrush(backgroundColor);
painter.setPen(Qt::NoPen);
-
- // Draw background
painter.drawRect(rect());
- // Draw border
- QColor borderColor = isSelected ? Qt::blue : Qt::gray;
- QPen borderPen(borderColor, isSelected ? 2 : 1);
+ QPen borderPen(borderColor, borderWidth);
painter.setPen(borderPen);
- painter.drawRect(rect().adjusted(0, 0, -1, -1)); // Adjust for pen width
+ painter.drawRect(rect().adjusted(0, 0, -1, -1));
// Calculate font size based on widget height
QFont font = painter.font();
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h
index 10cc39baf..ff649dd32 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h
@@ -6,6 +6,13 @@
#include
#include
+enum class TagState
+{
+ NotSelected,
+ Selected,
+ Excluded
+};
+
class DeckPreviewTagDisplayWidget : public QWidget
{
Q_OBJECT
@@ -22,16 +29,16 @@ public:
{
return tagName;
}
- bool getSelected() const
+ TagState getState() const
{
- return isSelected;
+ return state;
}
- /**
- * @brief Sets the selected state of the tag.
- * @param selected True if the tag is selected, false otherwise.
- */
- void setSelected(bool selected);
+ void setState(const TagState newState)
+ {
+ state = newState;
+ update();
+ };
signals:
/**
@@ -61,7 +68,7 @@ private:
QLabel *tagLabel; ///< Label for displaying the tag name.
QPushButton *closeButton; ///< Button to close/remove the tag.
QString tagName; ///< The name of the tag.
- bool isSelected; ///< Indicates whether the tag is selected.
+ TagState state; ///< Indicates whether the tag is unselected, selected, or excluded.
};
#endif // DECK_PREVIEW_TAG_DISPLAY_WIDGET_H
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
index 25cb5a1e5..47ed6ebee 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
@@ -33,32 +33,42 @@ void VisualDeckStorageTagFilterWidget::showEvent(QShowEvent *event)
void VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList &deckPreviews) const
{
- // Collect selected tags from DeckPreviewTagDisplayWidget
QStringList selectedTags;
+ QStringList excludedTags;
+
+ // Collect selected and excluded tags
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
- if (tagWidget->getSelected()) {
- selectedTags.append(tagWidget->getTagName());
+ switch (tagWidget->getState()) {
+ case TagState::Selected:
+ selectedTags.append(tagWidget->getTagName());
+ break;
+ case TagState::Excluded:
+ excludedTags.append(tagWidget->getTagName());
+ break;
+ default:
+ break;
}
}
- // If no tags are selected, set all decks as visible
- if (selectedTags.isEmpty()) {
+ // If no tags are selected or excluded, show all
+ if (selectedTags.isEmpty() && excludedTags.isEmpty()) {
for (DeckPreviewWidget *deckPreview : deckPreviews) {
deckPreview->filteredByTags = false;
}
return;
}
- // Filter DeckPreviewWidgets that contain all of the selected tags
- QList filteredDecks;
for (DeckPreviewWidget *deckPreview : deckPreviews) {
QStringList deckTags = deckPreview->deckLoader->getTags();
- // Check if all selectedTags are in deckTags
- bool allTagsPresent = std::all_of(selectedTags.begin(), selectedTags.end(),
+ bool hasAllSelected = std::all_of(selectedTags.begin(), selectedTags.end(),
[&deckTags](const QString &tag) { return deckTags.contains(tag); });
- deckPreview->filteredByTags = !allTagsPresent;
+ bool hasAnyExcluded = std::any_of(excludedTags.begin(), excludedTags.end(),
+ [&deckTags](const QString &tag) { return deckTags.contains(tag); });
+
+ // Filter out if any excluded tag is present or if any selected tag is missing
+ deckPreview->filteredByTags = !(hasAllSelected && !hasAnyExcluded);
}
}
@@ -72,13 +82,15 @@ void VisualDeckStorageTagFilterWidget::refreshTags()
void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QSet &tags)
{
- // Iterate through all DeckPreviewTagDisplayWidgets
+ auto *flowWidget = findChild();
+
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
- // If the tag is not in the provided tags list, remove the widget
- if (!tags.contains(tagWidget->getTagName())) {
- auto *flowWidget = findChild();
+ const QString &tagName = tagWidget->getTagName();
+
+ // Keep the tag widget if it is either selected or excluded
+ if (!tags.contains(tagName) && tagWidget->getState() == TagState::NotSelected) {
flowWidget->removeWidget(tagWidget);
- tagWidget->deleteLater(); // Safely delete the widget
+ tagWidget->deleteLater();
}
}
}
From bddb54ef4cd3fa2e38862d9704663ad37bafb02d Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:24:24 +0200
Subject: [PATCH 49/56] [VDE] Deck analytics visibility (#5919)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add scrollArea, I guess.
* Set mana curve bar color to grey for visibility.
---------
Co-authored-by: Lukas Brübach
---
.../deck_analytics/deck_analytics_widget.cpp | 17 ++++++++++++++---
.../deck_analytics/deck_analytics_widget.h | 8 +++++++-
.../deck_analytics/mana_curve_widget.cpp | 2 +-
3 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
index 02a4bfb5a..2131700fd 100644
--- a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
@@ -6,14 +6,25 @@ DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListModel *_deckLi
mainLayout = new QVBoxLayout();
setLayout(mainLayout);
+ scrollArea = new QScrollArea(this);
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scrollArea->setWidgetResizable(true);
+ mainLayout->addWidget(scrollArea);
+
+ container = new QWidget(scrollArea);
+ containerLayout = new QVBoxLayout(container);
+ container->setLayout(containerLayout);
+ scrollArea->setWidget(container);
+
manaCurveWidget = new ManaCurveWidget(this, deckListModel);
- mainLayout->addWidget(manaCurveWidget);
+ containerLayout->addWidget(manaCurveWidget);
manaDevotionWidget = new ManaDevotionWidget(this, deckListModel);
- mainLayout->addWidget(manaDevotionWidget);
+ containerLayout->addWidget(manaDevotionWidget);
manaBaseWidget = new ManaBaseWidget(this, deckListModel);
- mainLayout->addWidget(manaBaseWidget);
+ containerLayout->addWidget(manaBaseWidget);
}
void DeckAnalyticsWidget::refreshDisplays(DeckListModel *_deckModel)
diff --git a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h
index 6e7a273cf..b379b435c 100644
--- a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h
@@ -8,9 +8,10 @@
#include "mana_devotion_widget.h"
#include
+#include
+#include
#include
#include
-#include
class DeckAnalyticsWidget : public QWidget
{
@@ -26,6 +27,11 @@ private:
DeckListModel *deckListModel;
QVBoxLayout *mainLayout;
+ QWidget *container;
+ QVBoxLayout *containerLayout;
+
+ QScrollArea *scrollArea;
+
ManaCurveWidget *manaCurveWidget;
ManaDevotionWidget *manaDevotionWidget;
ManaBaseWidget *manaBaseWidget;
diff --git a/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp b/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
index acf240e0e..1cef0d794 100644
--- a/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
@@ -91,7 +91,7 @@ void ManaCurveWidget::updateDisplay()
// Add new widgets to the layout in sorted order
for (const auto &entry : sortedManaCurve) {
BarWidget *barWidget =
- new BarWidget(QString::number(entry.first), entry.second, highestEntry, QColor(11, 11, 11), this);
+ new BarWidget(QString::number(entry.first), entry.second, highestEntry, QColor(122, 122, 122), this);
barLayout->addWidget(barWidget);
}
From 05914e38f0009d11ac73e73cfbd9466fcad5787b Mon Sep 17 00:00:00 2001
From: "transifex-integration[bot]"
<43880903+transifex-integration[bot]@users.noreply.github.com>
Date: Tue, 6 May 2025 21:26:27 -0400
Subject: [PATCH 50/56] Translate oracle/oracle_en@source.ts in pt_BR (#5918)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'pt_BR'.
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
---
oracle/translations/oracle_pt_BR.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/oracle/translations/oracle_pt_BR.ts b/oracle/translations/oracle_pt_BR.ts
index 59ea83ec1..0a3439bf5 100644
--- a/oracle/translations/oracle_pt_BR.ts
+++ b/oracle/translations/oracle_pt_BR.ts
@@ -63,7 +63,7 @@
Sets file (%1)Sets JSON file (%1)
-
+ Arquivo de expansões (%1)
From 34400c7f60567710940bcebf7b27ec523a7dfc35 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:28:03 +0200
Subject: [PATCH 51/56] [VDE] Sample Hand Improvements (#5917)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Actually call retranslateUi, add spinBox to change sample hand size, add card size slider.
* Lint.
* Fix include.
* Fix include again.
* Fix overloads.
* Update visual_deck_editor_sample_hand_widget.cpp
---------
Co-authored-by: Lukas Brübach
Co-authored-by: Zach H
---
.../visual_deck_editor_sample_hand_widget.cpp | 34 ++++++++++++++++---
.../visual_deck_editor_sample_hand_widget.h | 6 ++++
cockatrice/src/settings/cache_settings.cpp | 8 +++++
cockatrice/src/settings/cache_settings.h | 7 ++++
dbconverter/src/mocks.cpp | 3 ++
tests/carddatabase/mocks.cpp | 3 ++
6 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
index 7868627e2..8530a8233 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
@@ -2,6 +2,7 @@
#include "../../../../deck/deck_loader.h"
#include "../../../../game/cards/card_database_manager.h"
+#include "../../../../settings/cache_settings.h"
#include "../cards/card_info_picture_widget.h"
#include
@@ -12,23 +13,45 @@ VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *pare
layout = new QVBoxLayout(this);
setLayout(layout);
+ resetAndHandSizeContainerWidget = new QWidget(this);
+ resetAndHandSizeLayout = new QHBoxLayout(resetAndHandSizeContainerWidget);
+ resetAndHandSizeContainerWidget->setLayout(resetAndHandSizeLayout);
+
resetButton = new QPushButton(this);
connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay()));
- layout->addWidget(resetButton);
+ resetAndHandSizeLayout->addWidget(resetButton);
+
+ handSizeSpinBox = new QSpinBox(this);
+ handSizeSpinBox->setValue(SettingsCache::instance().getVisualDeckEditorSampleHandSize());
+ handSizeSpinBox->setMinimum(1);
+ connect(handSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckEditorSampleHandSize);
+ connect(handSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), this,
+ &VisualDeckEditorSampleHandWidget::updateDisplay);
+ resetAndHandSizeLayout->addWidget(handSizeSpinBox);
+
+ layout->addWidget(resetAndHandSizeContainerWidget);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
layout->addWidget(flowWidget);
- for (CardInfoPtr card : getRandomCards(7)) {
+ cardSizeWidget = new CardSizeWidget(this, flowWidget);
+ layout->addWidget(cardSizeWidget);
+
+ for (CardInfoPtr card : getRandomCards(handSizeSpinBox->value())) {
auto displayWidget = new CardInfoPictureWidget(this);
displayWidget->setCard(card);
+ displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
flowWidget->addWidget(displayWidget);
}
+
+ retranslateUi();
}
void VisualDeckEditorSampleHandWidget::retranslateUi()
{
- resetButton->setText(tr("Reset"));
+ resetButton->setText(tr("Draw a new sample hand"));
+ handSizeSpinBox->setToolTip(tr("Sample hand size"));
}
void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
@@ -41,9 +64,12 @@ void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
void VisualDeckEditorSampleHandWidget::updateDisplay()
{
flowWidget->clearLayout();
- for (CardInfoPtr card : getRandomCards(7)) {
+ for (CardInfoPtr card : getRandomCards(handSizeSpinBox->value())) {
auto displayWidget = new CardInfoPictureWidget(this);
displayWidget->setCard(card);
+ displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
+ connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, displayWidget,
+ &CardInfoPictureWidget::setScaleFactor);
flowWidget->addWidget(displayWidget);
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
index 44dc04cab..ba09a978e 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
@@ -1,10 +1,12 @@
#ifndef VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
#define VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
+#include "../../../../client/ui/widgets/cards/card_size_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../general/layout_containers/flow_widget.h"
#include
+#include
#include
class VisualDeckEditorSampleHandWidget : public QWidget
@@ -22,8 +24,12 @@ public slots:
private:
DeckListModel *deckListModel;
QVBoxLayout *layout;
+ QWidget *resetAndHandSizeContainerWidget;
+ QHBoxLayout *resetAndHandSizeLayout;
QPushButton *resetButton;
+ QSpinBox *handSizeSpinBox;
FlowWidget *flowWidget;
+ CardSizeWidget *cardSizeWidget;
};
#endif // VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index 6507780fe..ef369641b 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -291,6 +291,7 @@ SettingsCache::SettingsCache()
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
visualDatabaseDisplayFilterToMostRecentSetsAmount =
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
+ visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
horizontalHand = settings->value("hand/horizontal", true).toBool();
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
@@ -821,6 +822,13 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _am
emit visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(visualDatabaseDisplayFilterToMostRecentSetsAmount);
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int _amount)
+{
+ visualDeckEditorSampleHandSize = _amount;
+ settings->setValue("interface/visualdeckeditorsamplehandsize", visualDeckEditorSampleHandSize);
+ emit visualDeckEditorSampleHandSizeAmountChanged(visualDeckEditorSampleHandSize);
+}
+
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
{
horizontalHand = static_cast(_horizontalHand);
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index bb4bed95f..94cb2ed6a 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -73,6 +73,7 @@ signals:
void visualDeckStorageSelectionAnimationChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
+ void visualDeckEditorSampleHandSizeAmountChanged(int amount);
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@@ -156,6 +157,7 @@ private:
int defaultDeckEditorType;
bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
int visualDatabaseDisplayFilterToMostRecentSetsAmount;
+ int visualDeckEditorSampleHandSize;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@@ -502,6 +504,10 @@ public:
{
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
}
+ int getVisualDeckEditorSampleHandSize() const
+ {
+ return visualDeckEditorSampleHandSize;
+ }
bool getHorizontalHand() const
{
return horizontalHand;
@@ -853,6 +859,7 @@ public slots:
void setDefaultDeckEditorType(int value);
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
+ void setVisualDeckEditorSampleHandSize(int _amount);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 890294870..032cdc95e 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -268,6 +268,9 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STA
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
{
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index b34c28727..db7dd9353 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -272,6 +272,9 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STA
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
{
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
From 99d9ce10c3746392cafbc8ecabc6e3fb535f5d09 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:28:50 +0200
Subject: [PATCH 52/56] [GDE, VDS & VDE] Tooltips and labels (#5916)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add correct inversion for isHidden() on bannerCardLabel.
* Add tooltips to VDS buttons.
* Add tooltip to GDE button.
* Add tooltips to visual deck editor buttons.
* Add tooltips to visual database display buttons.
* Lint.
---------
Co-authored-by: Lukas Brübach
---
.../deck_editor/deck_editor_deck_dock_widget.cpp | 3 ++-
.../visual_database_display_color_filter_widget.cpp | 2 ++
...sual_database_display_filter_save_load_widget.cpp | 1 +
...sual_database_display_main_type_filter_widget.cpp | 8 ++++++++
...visual_database_display_main_type_filter_widget.h | 1 +
.../visual_database_display_name_filter_widget.cpp | 1 +
...isual_database_display_sub_type_filter_widget.cpp | 8 ++++++++
.../visual_database_display_sub_type_filter_widget.h | 1 +
.../visual_database_display_widget.cpp | 12 ++++++++++++
.../visual_database_display_widget.h | 1 +
.../visual_deck_editor/visual_deck_editor_widget.cpp | 5 +++++
.../deck_preview_color_identity_filter_widget.cpp | 1 +
.../visual_deck_storage_widget.cpp | 3 +++
13 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index 2fde0b305..af717fa36 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -91,7 +91,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
bannerCardLabel = new QLabel();
bannerCardLabel->setObjectName("bannerCardLabel");
bannerCardLabel->setText(tr("Banner Card"));
- bannerCardLabel->setHidden(SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
+ bannerCardLabel->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
bannerCardComboBox = new QComboBox(this);
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
// Delay the update to avoid race conditions
@@ -567,6 +567,7 @@ void DeckEditorDeckDockWidget::retranslateUi()
setWindowTitle(tr("Deck"));
nameLabel->setText(tr("Deck &name:"));
+ quickSettingsWidget->setToolTip(tr("Banner Card/Tags Visibility Settings"));
showBannerCardCheckBox->setText(tr("Show banner card selection menu"));
showTagsWidgetCheckBox->setText(tr("Show tags selection menu"));
commentsLabel->setText(tr("&Comments:"));
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
index 681282fc4..e93253585 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
@@ -58,6 +58,8 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
toggleButton->setText(tr("Mode: Include/Exclude"));
break;
}
+
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
index 1a099501e..21ec205fd 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
@@ -39,6 +39,7 @@ VisualDatabaseDisplayFilterSaveLoadWidget::VisualDatabaseDisplayFilterSaveLoadWi
void VisualDatabaseDisplayFilterSaveLoadWidget::retranslateUi()
{
saveButton->setText(tr("Save Filter"));
+ saveButton->setToolTip(tr("Save all currently applied filters to a file"));
filenameInput->setPlaceholderText(tr("Enter filename..."));
}
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
index 688f8f4d2..8cf9c6605 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
@@ -47,6 +47,14 @@ VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWi
createMainTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize toggle button text
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayMainTypeFilterWidget::retranslateUi()
+{
+ spinBox->setToolTip(tr("Do not display card main-types with less than this amount of cards in the database"));
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplayMainTypeFilterWidget::createMainTypeButtons()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
index b13071825..07086bbe3 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplayMainTypeFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createMainTypeButtons();
void updateMainTypeButtonsVisibility();
int getMaxMainTypeCount() const;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
index 69e782b66..e0ededd50 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
@@ -45,6 +45,7 @@ void VisualDatabaseDisplayNameFilterWidget::retranslateUi()
{
searchBox->setPlaceholderText(tr("Filter by name..."));
loadFromDeckButton->setText(tr("Load from Deck"));
+ loadFromDeckButton->setToolTip(tr("Apply all card names in currently loaded deck as exact match name filters"));
}
void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
index 4b8fc21d8..c6ea811a9 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
@@ -51,6 +51,14 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
createSubTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize the toggle button text
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplaySubTypeFilterWidget::retranslateUi()
+{
+ spinBox->setToolTip(tr("Do not display card sub-types with less than this amount of cards in the database"));
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
index 72a0a25bb..64c9c19cd 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplaySubTypeFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createSubTypeButtons();
void updateSubTypeButtonsVisibility();
int getMaxSubTypeCount() const;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
index 9d82463be..f394f508f 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
@@ -150,6 +150,18 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
connect(loadCardsTimer, &QTimer::timeout, this, [this]() { loadCurrentPage(); });
loadCardsTimer->start(5000);
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayWidget::retranslateUi()
+{
+ clearFilterWidget->setToolTip(tr("Clear all filters"));
+
+ quickFilterSaveLoadWidget->setToolTip(tr("Save and load filters"));
+ quickFilterNameWidget->setToolTip(tr("Filter by exact card name"));
+ quickFilterSubTypeWidget->setToolTip(tr("Filter by card sub-type"));
+ quickFilterSetWidget->setToolTip(tr("Filter by set"));
}
void VisualDatabaseDisplayWidget::resizeEvent(QResizeEvent *event)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
index 6d75698dc..8f0cdba97 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
@@ -38,6 +38,7 @@ public:
AbstractTabDeckEditor *deckEditor,
CardDatabaseModel *database_model,
CardDatabaseDisplayModel *database_display_model);
+ void retranslateUi();
void adjustCardsPerPage();
void populateCards();
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
index 0914a472e..1ebf59e36 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
@@ -190,7 +190,12 @@ void VisualDeckEditorWidget::retranslateUi()
{
sortLabel->setText(tr("Click and drag to change the sort order within the groups"));
searchPushButton->setText(tr("Quick search and add card"));
+ searchPushButton->setToolTip(tr("Search for closest match in the database (with auto-suggestions) and add "
+ "preferred printing to the deck on pressing enter"));
+ sortCriteriaButton->setToolTip(tr("Configure how cards are sorted within their groups"));
displayTypeButton->setText(tr("Flat Layout"));
+ displayTypeButton->setToolTip(
+ tr("Change how cards are displayed within zones (i.e. overlapped or fully visible.)"));
}
void VisualDeckEditorWidget::updateZoneWidgets()
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
index b048b2372..ef59e90ff 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
@@ -47,6 +47,7 @@ void DeckPreviewColorIdentityFilterWidget::retranslateUi()
{
// Set the toggle button text based on the current mode
toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
+ toggleButton->setToolTip(tr("Color identity filter mode (AND/OR/NOT conjunctions of filters)"));
}
void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar color, bool active)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
index 4e879bd65..5a27728a3 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
@@ -194,6 +194,9 @@ void VisualDeckStorageWidget::retranslateUi()
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
+
+ refreshButton->setToolTip(tr("Refresh loaded files"));
+ quickSettingsWidget->setToolTip(tr("Visual Deck Storage Settings"));
}
/**
From 5b9cb4fc8daad11a14af04f29442a14d75b6475b Mon Sep 17 00:00:00 2001
From: tooomm
Date: Wed, 7 May 2025 03:29:09 +0200
Subject: [PATCH 53/56] Small changes related to docker image build+upload
(#5907)
* ci label
* naming
* downloads
* run
* fix toc
---
.github/workflows/docker-release.yml | 6 +++---
README.md | 17 +++++++++--------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
index 439ea24cd..5a03b86c8 100644
--- a/.github/workflows/docker-release.yml
+++ b/.github/workflows/docker-release.yml
@@ -1,4 +1,4 @@
-name: Build Docker Container
+name: Build Docker Image
on:
push:
@@ -48,7 +48,7 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- - name: Set up Docker Buildx
+ - name: Set up Docker buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
@@ -59,7 +59,7 @@ jobs:
username: ${{ github.actor }}
password: ${{ github.token }}
- - name: Build and push Docker Image
+ - name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
diff --git a/README.md b/README.md
index 48cacff78..acc2e4110 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
Related|Community|Contribute|
- Build|
+ Build|Run
@@ -38,8 +38,8 @@ Latest stable release:
Latest beta version:
[](https://github.com/cockatrice/cockatrice/releases)  [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice&search=0) [](https://github.com/Cockatrice/Cockatrice/pulls?q=is%3Apr+is%3Aclosed)
-While incorporating the latest fixes and features, beta builds may not be stable and/or contain new bugs!
-Please report any findings when testing them!
+While incorporating the latest fixes and features, beta builds may not be stable or contain new bugs!
+Please report any findings and open new issues when testing them!
# Related Repositories
@@ -79,10 +79,11 @@ Cockatrice tries to use the [Google Developer Documentation Style Guide](https:/
Kudos to our amazing contributors ❤️
+
- Made with contrib.rocks.
+ Made with contrib.rocks
### Translations [](https://transifex.com/cockatrice/cockatrice/)
@@ -92,7 +93,7 @@ Cockatrice uses Transifex to manage translations. You can help us bring Coc
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about getting invovled, and join a group of hundreds of others!
-# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
+# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/docker-release.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
Dependencies: *(for minimum versions search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
- [Qt](https://www.qt.io/developers/)
@@ -149,10 +150,10 @@ The following flags (with their non-default values) can be passed to `cmake`:
#### Docker
-You can run an instance of Servatrice (the Cockatrice server) using [Docker](https://www.docker.com/resources/what-container/) and our Dockerfile.
+You can build an image & deploy a Servatrice (Cockatrice server) container using [Docker](https://www.docker.com/resources/what-container/) and our Dockerfile yourself.
-For more information, have a look in our wiki section on [Setting up Servatrice](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
-There, you'll also find more hints on our **docker-compose** file which will configure and run both a MySQL server and Servatrice.
+For more details, look into our wiki section on [Setting up Servatrice](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
+You'll also find more hints on our **pre-build image** there, or the **docker-compose** file which will configure and run both a MySQL server and Servatrice.
# License [](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE)
From c4e42b94f97300d6d1a3fec2b37989bc7f237b2f Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Tue, 6 May 2025 18:31:01 -0700
Subject: [PATCH 54/56] Refactor CardSizeWidget: don't update setting directly
(#5903)
---
.../src/client/ui/widgets/cards/card_size_widget.cpp | 9 +--------
.../src/client/ui/widgets/cards/card_size_widget.h | 10 +++++++++-
.../ui/widgets/printing_selector/printing_selector.cpp | 2 ++
.../visual_deck_storage/visual_deck_storage_widget.cpp | 2 ++
4 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp
index be231e67a..7ce8e71c4 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp
@@ -34,14 +34,7 @@ CardSizeWidget::CardSizeWidget(QWidget *parent, FlowWidget *_flowWidget, int def
// Debounce setup
debounceTimer.setSingleShot(true);
- connect(&debounceTimer, &QTimer::timeout, this, [this]() {
- // Check the type of the parent widget
- if (qobject_cast(parentWidget())) {
- SettingsCache::instance().setPrintingSelectorCardSize(pendingValue);
- } else if (qobject_cast(parentWidget())) {
- SettingsCache::instance().setVisualDeckStorageCardSize(pendingValue);
- }
- });
+ connect(&debounceTimer, &QTimer::timeout, this, [this] { emit cardSizeSettingUpdated(pendingValue); });
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardSizeWidget::updateCardSizeSetting);
}
diff --git a/cockatrice/src/client/ui/widgets/cards/card_size_widget.h b/cockatrice/src/client/ui/widgets/cards/card_size_widget.h
index d79359f23..1631fa562 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_size_widget.h
+++ b/cockatrice/src/client/ui/widgets/cards/card_size_widget.h
@@ -17,9 +17,17 @@ public:
explicit CardSizeWidget(QWidget *parent, FlowWidget *flowWidget = nullptr, int defaultValue = 100);
[[nodiscard]] QSlider *getSlider() const;
-public slots:
+private slots:
void updateCardSizeSetting(int newValue);
+signals:
+ /**
+ * Emitted when the slider value changes, but on a debounce timer.
+ * Any parents that care about saving the value to settings should use this signal to indicate when to save the new
+ * value to settings.
+ */
+ void cardSizeSettingUpdated(int newValue);
+
private:
QWidget *parent;
FlowWidget *flowWidget;
diff --git a/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp b/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp
index ef3816049..b75ca213e 100644
--- a/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp
+++ b/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp
@@ -70,6 +70,8 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
cardSizeWidget =
new CardSizeWidget(displayOptionsWidget, flowWidget, SettingsCache::instance().getPrintingSelectorCardSize());
+ connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
+ &SettingsCache::setPrintingSelectorCardSize);
displayOptionsWidget->addSettingsWidget(sortToolBar);
displayOptionsWidget->addSettingsWidget(navigationCheckBox);
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
index 5a27728a3..34dd4c808 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
@@ -104,6 +104,8 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
// card size slider
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
+ connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageCardSize);
quickSettingsWidget = new SettingsButtonWidget(this);
quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
From 033c8b269d73ebdf6c6996c3078b34a9cd445219 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Tue, 6 May 2025 20:00:11 -0700
Subject: [PATCH 55/56] [VDS] Refactor: move quick settings to separate class
(#5905)
---
cockatrice/CMakeLists.txt | 1 +
...ual_deck_storage_folder_display_widget.cpp | 4 +-
...ual_deck_storage_quick_settings_widget.cpp | 155 ++++++++++++++++++
...isual_deck_storage_quick_settings_widget.h | 55 +++++++
.../visual_deck_storage_widget.cpp | 99 ++---------
.../visual_deck_storage_widget.h | 14 +-
6 files changed, 232 insertions(+), 96 deletions(-)
create mode 100644 cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
create mode 100644 cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 2b9a10113..50c721a6f 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -135,6 +135,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+ src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
index 319244f85..319393775 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
@@ -90,9 +90,9 @@ void VisualDeckStorageFolderDisplayWidget::createWidgetsForFiles()
&VisualDeckStorageWidget::deckLoadRequested);
connect(display, &DeckPreviewWidget::openDeckEditor, visualDeckStorageWidget,
&VisualDeckStorageWidget::openDeckEditor);
- connect(visualDeckStorageWidget->cardSizeWidget->getSlider(), &QSlider::valueChanged,
+ connect(visualDeckStorageWidget->settings(), &VisualDeckStorageQuickSettingsWidget::cardSizeChanged,
display->bannerCardDisplayWidget, &CardInfoPictureWidget::setScaleFactor);
- display->bannerCardDisplayWidget->setScaleFactor(visualDeckStorageWidget->cardSizeWidget->getSlider()->value());
+ display->bannerCardDisplayWidget->setScaleFactor(visualDeckStorageWidget->settings()->getCardSize());
allDecks.append(display);
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
new file mode 100644
index 000000000..3b9063a9b
--- /dev/null
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
@@ -0,0 +1,155 @@
+#include "visual_deck_storage_quick_settings_widget.h"
+
+#include "../../../../settings/cache_settings.h"
+#include "visual_deck_storage_widget.h"
+
+#include
+#include
+
+VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidget *parent)
+ : SettingsButtonWidget(parent)
+{
+ // show folders checkbox
+ showFoldersCheckBox = new QCheckBox(this);
+ showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
+ connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showFoldersChanged);
+ connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowFolders);
+
+ // show tag filter widget checkbox
+ showTagFilterCheckBox = new QCheckBox(this);
+ showTagFilterCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagFilter());
+ connect(showTagFilterCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged);
+ connect(showTagFilterCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowTagFilter);
+
+ // show tags on DeckPreviewWidget checkbox
+ showTagsOnDeckPreviewsCheckBox = new QCheckBox(this);
+ showTagsOnDeckPreviewsCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews());
+ connect(showTagsOnDeckPreviewsCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showTagsOnDeckPreviewsChanged);
+ connect(showTagsOnDeckPreviewsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowTagsOnDeckPreviews);
+
+ // show banner card selector checkbox
+ showBannerCardComboBoxCheckBox = new QCheckBox(this);
+ showBannerCardComboBoxCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox());
+ connect(showBannerCardComboBoxCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showBannerCardComboBoxChanged);
+ connect(showBannerCardComboBoxCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowBannerCardComboBox);
+
+ // search folder names checkbox
+ searchFolderNamesCheckBox = new QCheckBox(this);
+ searchFolderNamesCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageSearchFolderNames());
+ connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::searchFolderNamesChanged);
+ connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageSearchFolderNames);
+
+ // draw unused color identities checkbox
+ drawUnusedColorIdentitiesCheckBox = new QCheckBox(this);
+ drawUnusedColorIdentitiesCheckBox->setChecked(
+ SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities());
+ connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::drawUnusedColorIdentitiesChanged);
+ connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
+
+ // color identity opacity selector
+ auto unusedColorIdentityOpacityWidget = new QWidget(this);
+
+ unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget);
+ unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget);
+
+ unusedColorIdentitiesOpacitySpinBox->setMinimum(0);
+ unusedColorIdentitiesOpacitySpinBox->setMaximum(100);
+ unusedColorIdentitiesOpacitySpinBox->setValue(
+ SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
+ connect(unusedColorIdentitiesOpacitySpinBox, QOverload::of(&QSpinBox::valueChanged), this,
+ &VisualDeckStorageQuickSettingsWidget::unusedColorIdentitiesOpacityChanged);
+ connect(unusedColorIdentitiesOpacitySpinBox, QOverload::of(&QSpinBox::valueChanged),
+ &SettingsCache::instance(), &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
+
+ unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox);
+
+ auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget);
+ unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0);
+ unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
+ unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
+
+ // card size slider
+ cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
+ connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
+ &VisualDeckStorageQuickSettingsWidget::cardSizeChanged);
+ connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageCardSize);
+
+ // putting everything together
+ this->addSettingsWidget(showFoldersCheckBox);
+ this->addSettingsWidget(showTagFilterCheckBox);
+ this->addSettingsWidget(showTagsOnDeckPreviewsCheckBox);
+ this->addSettingsWidget(showBannerCardComboBoxCheckBox);
+ this->addSettingsWidget(searchFolderNamesCheckBox);
+ this->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
+ this->addSettingsWidget(unusedColorIdentityOpacityWidget);
+ this->addSettingsWidget(cardSizeWidget);
+
+ connect(&SettingsCache::instance(), &SettingsCache::langChanged, this,
+ &VisualDeckStorageQuickSettingsWidget::retranslateUi);
+ retranslateUi();
+}
+
+void VisualDeckStorageQuickSettingsWidget::retranslateUi()
+{
+ showFoldersCheckBox->setText(tr("Show Folders"));
+ showTagFilterCheckBox->setText(tr("Show Tag Filter"));
+ showTagsOnDeckPreviewsCheckBox->setText(tr("Show Tags On Deck Previews"));
+ showBannerCardComboBoxCheckBox->setText(tr("Show Banner Card Selection Option"));
+ searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
+ drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
+ unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
+ unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowFolders() const
+{
+ return showFoldersCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getDrawUnusedColorIdentities() const
+{
+ return drawUnusedColorIdentitiesCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowBannerCardComboBox() const
+{
+ return showBannerCardComboBoxCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowTagFilter() const
+{
+ return showTagFilterCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowTagsOnDeckPreviews() const
+{
+ return showTagsOnDeckPreviewsCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getSearchFolderNames() const
+{
+ return searchFolderNamesCheckBox->isChecked();
+}
+
+int VisualDeckStorageQuickSettingsWidget::getUnusedColorIdentitiesOpacity() const
+{
+ return unusedColorIdentitiesOpacitySpinBox->value();
+}
+
+int VisualDeckStorageQuickSettingsWidget::getCardSize() const
+{
+ return cardSizeWidget->getSlider()->value();
+}
\ No newline at end of file
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h
new file mode 100644
index 000000000..da82b177b
--- /dev/null
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h
@@ -0,0 +1,55 @@
+#ifndef VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H
+#define VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H
+
+#include "../quick_settings/settings_button_widget.h"
+
+class CardSizeWidget;
+class QLabel;
+class QSpinBox;
+class QCheckBox;
+
+/**
+ * The VDS's quick settings menu.
+ * Manages the widgets in the quick settings menu dropdown, as well as syncing their values with SettingsCache.
+ * The current values of the settings are exposed through getters and signals.
+ */
+class VisualDeckStorageQuickSettingsWidget : public SettingsButtonWidget
+{
+ Q_OBJECT
+
+ QCheckBox *showFoldersCheckBox;
+ QCheckBox *drawUnusedColorIdentitiesCheckBox;
+ QCheckBox *showBannerCardComboBoxCheckBox;
+ QCheckBox *showTagFilterCheckBox;
+ QCheckBox *showTagsOnDeckPreviewsCheckBox;
+ QCheckBox *searchFolderNamesCheckBox;
+ QLabel *unusedColorIdentitiesOpacityLabel;
+ QSpinBox *unusedColorIdentitiesOpacitySpinBox;
+ CardSizeWidget *cardSizeWidget;
+
+public:
+ explicit VisualDeckStorageQuickSettingsWidget(QWidget *parent = nullptr);
+
+ void retranslateUi();
+
+ bool getShowFolders() const;
+ bool getDrawUnusedColorIdentities() const;
+ bool getShowBannerCardComboBox() const;
+ bool getShowTagFilter() const;
+ bool getShowTagsOnDeckPreviews() const;
+ bool getSearchFolderNames() const;
+ int getUnusedColorIdentitiesOpacity() const;
+ int getCardSize() const;
+
+signals:
+ void showFoldersChanged(bool enabled);
+ void drawUnusedColorIdentitiesChanged(bool enabled);
+ void showBannerCardComboBoxChanged(bool enabled);
+ void showTagFilterChanged(bool enabled);
+ void showTagsOnDeckPreviewsChanged(bool enabled);
+ void searchFolderNamesChanged(bool enabled);
+ void unusedColorIdentitiesOpacityChanged(int opacity);
+ void cardSizeChanged(int scale);
+};
+
+#endif // VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H
\ No newline at end of file
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
index 34dd4c808..e82f0c8d6 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
@@ -41,81 +41,13 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
refreshButton->setFixedSize(32, 32);
connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible);
- // quick settings menu
- showFoldersCheckBox = new QCheckBox(this);
- showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
- connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &VisualDeckStorageWidget::updateShowFolders);
- connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowFolders);
-
- tagFilterVisibilityCheckBox = new QCheckBox(this);
- tagFilterVisibilityCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagFilter());
- connect(tagFilterVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ quickSettingsWidget = new VisualDeckStorageQuickSettingsWidget(this);
+ connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showFoldersChanged, this,
+ &VisualDeckStorageWidget::updateShowFolders);
+ connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged, this,
&VisualDeckStorageWidget::updateTagsVisibility);
- connect(tagFilterVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowTagFilter);
-
- tagsOnWidgetsVisibilityCheckBox = new QCheckBox(this);
- tagsOnWidgetsVisibilityCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews());
- connect(tagsOnWidgetsVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowTagsOnDeckPreviews);
-
- drawUnusedColorIdentitiesCheckBox = new QCheckBox(this);
- drawUnusedColorIdentitiesCheckBox->setChecked(
- SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities());
- connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
-
- bannerCardComboBoxVisibilityCheckBox = new QCheckBox(this);
- bannerCardComboBoxVisibilityCheckBox->setChecked(
- SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox());
- connect(bannerCardComboBoxVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowBannerCardComboBox);
-
- searchFolderNamesCheckBox = new QCheckBox(this);
- searchFolderNamesCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageSearchFolderNames());
- connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::searchFolderNamesChanged, this,
&VisualDeckStorageWidget::updateSearchFilter);
- connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageSearchFolderNames);
-
- // color identity opacity selector
- auto unusedColorIdentityOpacityWidget = new QWidget(this);
-
- unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget);
- unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget);
-
- unusedColorIdentitiesOpacitySpinBox->setMinimum(0);
- unusedColorIdentitiesOpacitySpinBox->setMaximum(100);
- unusedColorIdentitiesOpacitySpinBox->setValue(
- SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
- connect(unusedColorIdentitiesOpacitySpinBox, QOverload::of(&QSpinBox::valueChanged),
- &SettingsCache::instance(), &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
-
- unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox);
-
- unusedColorIdentitiesOpacitySpinBox->setValue(
- SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
-
- auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget);
- unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0);
- unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
- unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
-
- // card size slider
- cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
- connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageCardSize);
-
- quickSettingsWidget = new SettingsButtonWidget(this);
- quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
- quickSettingsWidget->addSettingsWidget(tagFilterVisibilityCheckBox);
- quickSettingsWidget->addSettingsWidget(tagsOnWidgetsVisibilityCheckBox);
- quickSettingsWidget->addSettingsWidget(bannerCardComboBoxVisibilityCheckBox);
- quickSettingsWidget->addSettingsWidget(searchFolderNamesCheckBox);
- quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
- quickSettingsWidget->addSettingsWidget(unusedColorIdentityOpacityWidget);
- quickSettingsWidget->addSettingsWidget(cardSizeWidget);
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
searchAndSortLayout->addWidget(sortWidget);
@@ -188,19 +120,18 @@ void VisualDeckStorageWidget::retranslateUi()
{
databaseLoadIndicator->setText(tr("Loading database ..."));
- showFoldersCheckBox->setText(tr("Show Folders"));
- tagFilterVisibilityCheckBox->setText(tr("Show Tag Filter"));
- tagsOnWidgetsVisibilityCheckBox->setText(tr("Show Tags On Deck Previews"));
- bannerCardComboBoxVisibilityCheckBox->setText(tr("Show Banner Card Selection Option"));
- searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
- drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
- unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
- unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
-
refreshButton->setToolTip(tr("Refresh loaded files"));
quickSettingsWidget->setToolTip(tr("Visual Deck Storage Settings"));
}
+/**
+ * Gets a const pointer to the quick settings so that the values can be accessed.
+ */
+const VisualDeckStorageQuickSettingsWidget *VisualDeckStorageWidget::settings() const
+{
+ return quickSettingsWidget;
+}
+
/**
* Reapplies all sort and filter options by calling the appropriate update methods.
*/
@@ -215,7 +146,7 @@ void VisualDeckStorageWidget::reapplySortAndFilters()
void VisualDeckStorageWidget::createRootFolderWidget()
{
folderWidget = new VisualDeckStorageFolderDisplayWidget(this, this, SettingsCache::instance().getDeckPath(), false,
- showFoldersCheckBox->isChecked());
+ quickSettingsWidget->getShowFolders());
scrollArea->setWidget(folderWidget); // this automatically destroys the old folderWidget
scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width());
@@ -266,7 +197,7 @@ void VisualDeckStorageWidget::updateSearchFilter()
{
if (folderWidget) {
searchWidget->filterWidgets(folderWidget->findChildren(), searchWidget->getSearchText(),
- searchFolderNamesCheckBox->isChecked());
+ quickSettingsWidget->getSearchFolderNames());
folderWidget->updateVisibility();
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h
index b52086a4f..755243fdf 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h
@@ -8,6 +8,7 @@
#include "deck_preview/deck_preview_color_identity_filter_widget.h"
#include "deck_preview/deck_preview_widget.h"
#include "visual_deck_storage_folder_display_widget.h"
+#include "visual_deck_storage_quick_settings_widget.h"
#include "visual_deck_storage_search_widget.h"
#include "visual_deck_storage_sort_widget.h"
#include "visual_deck_storage_tag_filter_widget.h"
@@ -29,10 +30,11 @@ public:
void refreshIfPossible();
void retranslateUi();
- CardSizeWidget *cardSizeWidget;
VisualDeckStorageTagFilterWidget *tagFilterWidget;
bool deckPreviewSelectionAnimationEnabled;
+ const VisualDeckStorageQuickSettingsWidget *settings() const;
+
public slots:
void createRootFolderWidget(); // Refresh the display of cards based on the current sorting option
void updateShowFolders(bool enabled);
@@ -60,15 +62,7 @@ private:
VisualDeckStorageSearchWidget *searchWidget;
DeckPreviewColorIdentityFilterWidget *deckPreviewColorIdentityFilterWidget;
QToolButton *refreshButton;
- SettingsButtonWidget *quickSettingsWidget;
- QCheckBox *showFoldersCheckBox;
- QCheckBox *drawUnusedColorIdentitiesCheckBox;
- QCheckBox *bannerCardComboBoxVisibilityCheckBox;
- QCheckBox *tagFilterVisibilityCheckBox;
- QCheckBox *tagsOnWidgetsVisibilityCheckBox;
- QCheckBox *searchFolderNamesCheckBox;
- QLabel *unusedColorIdentitiesOpacityLabel;
- QSpinBox *unusedColorIdentitiesOpacitySpinBox;
+ VisualDeckStorageQuickSettingsWidget *quickSettingsWidget;
QScrollArea *scrollArea;
VisualDeckStorageFolderDisplayWidget *folderWidget;
From 9cf979d154949e811f70d591db37f2460a09fab9 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Fri, 9 May 2025 03:32:00 +0200
Subject: [PATCH 56/56] [GDE/VDE] More granular modification signals. (#5927)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* More granular modification signals.
* Bruh.
---------
Co-authored-by: Lukas Brübach
---
.../client/tabs/abstract_tab_deck_editor.cpp | 5 +++++
.../client/tabs/abstract_tab_deck_editor.h | 1 +
.../tab_deck_editor_visual.cpp | 2 +-
.../deck_editor_deck_dock_widget.cpp | 21 ++++++++++++-------
.../deck_editor_deck_dock_widget.h | 4 ++++
5 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
index 1c599034b..eba0bfb0f 100644
--- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
+++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
@@ -50,6 +50,7 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
printingSelectorDockWidget = new DeckEditorPrintingSelectorDockWidget(this);
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckChanged, this, &AbstractTabDeckEditor::onDeckChanged);
+ connect(deckDockWidget, &DeckEditorDeckDockWidget::deckModified, this, &AbstractTabDeckEditor::onDeckModified);
connect(deckDockWidget, &DeckEditorDeckDockWidget::cardChanged, this, &AbstractTabDeckEditor::updateCard);
connect(this, &AbstractTabDeckEditor::decrementCard, deckDockWidget, &DeckEditorDeckDockWidget::actDecrementCard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
@@ -77,6 +78,10 @@ void AbstractTabDeckEditor::updateCard(CardInfoPtr _card)
}
void AbstractTabDeckEditor::onDeckChanged()
+{
+}
+
+void AbstractTabDeckEditor::onDeckModified()
{
setModified(!isBlankNewDeck());
deckMenu->setSaveStatus(!isBlankNewDeck());
diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h
index 796213d27..1642ac107 100644
--- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h
+++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h
@@ -70,6 +70,7 @@ public:
public slots:
virtual void onDeckChanged();
+ virtual void onDeckModified();
void updateCard(CardInfoPtr _card);
void actAddCard(CardInfoPtr info);
void actAddCardToSideboard(CardInfoPtr info);
diff --git a/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp b/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
index 224c4db15..68f1eee17 100644
--- a/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
+++ b/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
@@ -80,7 +80,7 @@ void TabDeckEditorVisual::createCentralFrame()
void TabDeckEditorVisual::onDeckChanged()
{
- AbstractTabDeckEditor::onDeckChanged();
+ AbstractTabDeckEditor::onDeckModified();
tabContainer->visualDeckView->decklistDataChanged(QModelIndex(), QModelIndex());
tabContainer->deckAnalytics->refreshDisplays(deckDockWidget->deckModel);
tabContainer->sampleHandWidget->setDeckModel(deckDockWidget->deckModel);
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index af717fa36..3683666a2 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -228,19 +228,22 @@ void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*¤t*/, const
void DeckEditorDeckDockWidget::updateName(const QString &name)
{
deckModel->getDeckList()->setName(name);
- emit deckChanged();
+ emit nameChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateComments()
{
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
- emit deckChanged();
+ emit commentsChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateHash()
{
hashLabel->setText(deckModel->getDeckList()->getDeckHash());
- emit deckChanged();
+ emit hashChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
@@ -318,7 +321,7 @@ void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
QVariantMap itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
deckModel->getDeckList()->setBannerCard(
QPair(itemData["name"].toString(), itemData["uuid"].toString()));
- emit deckChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
@@ -366,8 +369,12 @@ void DeckEditorDeckDockWidget::cleanDeck()
{
deckModel->cleanList();
nameEdit->setText(QString());
+ emit nameChanged();
commentsEdit->setText(QString());
+ emit commentsChanged();
hashLabel->setText(QString());
+ emit hashChanged();
+ emit deckModified();
emit deckChanged();
updateBannerCardComboBox();
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
@@ -426,7 +433,7 @@ void DeckEditorDeckDockWidget::actSwapCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
update();
@@ -521,7 +528,7 @@ void DeckEditorDeckDockWidget::actRemoveCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
}
@@ -539,7 +546,7 @@ void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, int of
else
deckModel->setData(numberIndex, new_count, Qt::EditRole);
- emit deckChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::decklistCustomMenu(QPoint point)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
index 0a9ebcd65..c81b4a6fa 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
@@ -49,7 +49,11 @@ public slots:
void offsetCountAtIndex(const QModelIndex &idx, int offset);
signals:
+ void nameChanged();
+ void commentsChanged();
+ void hashChanged();
void deckChanged();
+ void deckModified();
void cardChanged(CardInfoPtr _card);
private: