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/)
@@ -143,17 +144,16 @@ 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
#### 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)
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index cbd0ed1d7..50c721a6f 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
@@ -132,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
@@ -165,13 +169,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
@@ -179,10 +186,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/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/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..2eed749af 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);
@@ -349,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/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/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/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_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/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/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/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..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
@@ -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();
}
}
@@ -63,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);
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/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/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..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
@@ -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"
@@ -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
{
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/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/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/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);
}
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..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
@@ -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);
@@ -202,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()
@@ -268,6 +297,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);
@@ -288,7 +321,18 @@ 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)
+{
+ bannerCardLabel->setHidden(!visible);
+ bannerCardComboBox->setHidden(!visible);
+}
+
+void DeckEditorDeckDockWidget::updateShowTagsWidget(const bool visible)
+{
+ deckTagsDisplayWidget->setHidden(!visible);
}
/**
@@ -325,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());
@@ -385,7 +433,7 @@ void DeckEditorDeckDockWidget::actSwapCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
update();
@@ -480,7 +528,7 @@ void DeckEditorDeckDockWidget::actRemoveCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
}
@@ -498,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)
@@ -526,6 +574,9 @@ 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:"));
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..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:
@@ -57,6 +61,9 @@ private:
KeySignals deckViewKeySignals;
QLabel *nameLabel;
LineEditUnfocusable *nameEdit;
+ SettingsButtonWidget *quickSettingsWidget;
+ QCheckBox *showBannerCardCheckBox;
+ QCheckBox *showTagsWidgetCheckBox;
QLabel *commentsLabel;
QTextEdit *commentsEdit;
QLabel *bannerCardLabel;
@@ -77,6 +84,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/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
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_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..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
@@ -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();
@@ -69,95 +58,94 @@ 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)
{
- 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 +158,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/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_set_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
index 795c83d68..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);
@@ -36,24 +76,26 @@ 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()
{
- 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);
@@ -66,14 +108,47 @@ void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
// 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);
- }
}
- 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()
@@ -183,13 +258,15 @@ 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);
}
}
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..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,19 +4,36 @@
#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
public:
explicit VisualDatabaseDisplaySetFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createSetButtons();
+ void filterToRecentSets();
void updateSetButtonsVisibility();
void handleSetToggled(const QString &setShortName, bool active);
@@ -28,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/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 d1e4b2db5..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
@@ -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,11 +141,27 @@ 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
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)
@@ -195,13 +208,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!";
}
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_sample_hand_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
index f6b73b0d5..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);
- flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
+ 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/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..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
@@ -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);
@@ -191,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()
@@ -227,6 +231,7 @@ void VisualDeckEditorWidget::addZoneIfDoesNotExist()
for (DeckCardZoneDisplayWidget *displayWidget : cardZoneDisplayWidgets) {
if (displayWidget->zoneName == zone) {
found = true;
+ displayWidget->displayCards();
break;
}
}
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/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
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/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)
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);
}
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_tag_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
index 983ab13bd..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,57 +33,69 @@ 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);
}
}
void VisualDeckStorageTagFilterWidget::refreshTags()
{
- QStringList allTags = gatherAllTags();
- removeTagsNotInList(gatherAllTags());
- addTagsIfNotPresent(gatherAllTags());
+ QSet allTags = gatherAllTags();
+ removeTagsNotInList(allTags);
+ addTagsIfNotPresent(allTags);
sortTags();
}
-void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QStringList &tags)
+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();
}
}
}
-void VisualDeckStorageTagFilterWidget::addTagsIfNotPresent(const QStringList &tags)
+void VisualDeckStorageTagFilterWidget::addTagsIfNotPresent(const QSet &tags)
{
for (const QString &tag : tags) {
addTagIfNotPresent(tag);
@@ -136,20 +148,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();
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..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,79 +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());
-
- 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);
@@ -186,14 +120,16 @@ 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;
}
/**
@@ -210,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());
@@ -261,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;
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/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/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/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp
index 502662c14..63901325f 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"
@@ -629,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);
@@ -642,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);
@@ -699,12 +705,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);
@@ -754,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"));
@@ -774,6 +789,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..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;
@@ -155,6 +156,8 @@ private:
QComboBox visualDeckStoragePromptForConversionSelector;
QCheckBox visualDeckStorageInGameCheckBox;
QCheckBox visualDeckStorageSelectionAnimationCheckBox;
+ QLabel defaultDeckEditorTypeLabel;
+ QComboBox defaultDeckEditorTypeSelector;
QLabel rewindBufferingMsLabel;
QSpinBox rewindBufferingMsBox;
QGroupBox *generalGroupBox;
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index dc569c92c..b60a9767b 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -3,23 +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);
@@ -27,7 +44,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)
@@ -35,16 +52,26 @@ 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();
for (const QString &message : logBuffer)
- logEntryAdded(message);
+ appendLogEntry(message);
}
-void DlgViewLog::logEntryAdded(QString message)
+void DlgViewLog::appendLogEntry(const 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 */)
diff --git a/cockatrice/src/dialogs/dlg_view_log.h b/cockatrice/src/dialogs/dlg_view_log.h
index 3845f0062..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 logEntryAdded(QString message);
+ void appendLogEntry(const QString &message);
void actCheckBoxChanged(bool abNewValue);
+ void actCopyToClipboard();
};
#endif
\ No newline at end of file
diff --git a/cockatrice/src/game/cards/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp
similarity index 96%
rename from cockatrice/src/game/cards/abstract_card_drag_item.cpp
rename to cockatrice/src/game/board/abstract_card_drag_item.cpp
index 0c7acd917..a7234c3d4 100644
--- a/cockatrice/src/game/cards/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()
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 88%
rename from cockatrice/src/game/cards/card_drag_item.cpp
rename to cockatrice/src/game/board/card_drag_item.cpp
index d21e9168b..ab4431958 100644
--- a/cockatrice/src/game/cards/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;
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 97%
rename from cockatrice/src/game/cards/card_item.cpp
rename to cockatrice/src/game/board/card_item.cpp
index 40fa8d119..55df7a477 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
@@ -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/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/cards/card_database.cpp b/cockatrice/src/game/cards/card_database.cpp
index 7181ffd06..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");
@@ -386,9 +384,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;
+ }
}
}
}
@@ -559,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 ae55ad7af..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,
@@ -289,8 +291,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();
}
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/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/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/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;
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..9fff6b3df 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"
@@ -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, "table", 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);
@@ -399,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);
@@ -454,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;
}
@@ -828,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..."));
@@ -1854,6 +1864,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);
@@ -2065,6 +2076,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());
@@ -2230,10 +2243,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());
@@ -2242,8 +2255,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());
}
@@ -2710,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;
}
@@ -2889,11 +2963,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 +3761,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 +3852,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 +4022,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..d802ef796 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);
@@ -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;
@@ -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 7516923b0..089ed0a2d 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"
@@ -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,
@@ -97,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();
}
@@ -236,4 +235,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 91cad179c..8ce31e885 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
@@ -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/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..b26aa23ff 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
@@ -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/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..cee782560 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"
@@ -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 271276967..3d464e6f3 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"
/*
@@ -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/game/zones/view_zone.cpp b/cockatrice/src/game/zones/view_zone.cpp
index 9aec01db3..fd9387064 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"
@@ -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)
diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp
index 85a91afdf..f0430f549 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"
@@ -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/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 2c0174673..a61a7ba2c 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"
@@ -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,18 @@ 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");
+ } else {
+ fromStr = tr(" from custom zone '%1'").arg(zoneName);
}
if (!cardNameContainsStartZone) {
cardName.clear();
}
- return QPair(cardName, fromStr);
+ return {cardName, fromStr};
}
void MessageLogWidget::containerProcessingDone()
@@ -249,12 +216,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)
@@ -291,9 +262,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 +293,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,18 +318,21 @@ 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.");
+ } 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));
}
}
@@ -845,6 +819,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..21b03dee9 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();
@@ -53,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/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/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index 096ab23b8..ef369641b 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();
@@ -263,6 +264,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();
@@ -282,6 +286,12 @@ 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 =
+ 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();
@@ -362,6 +372,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;
@@ -681,6 +697,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;
@@ -770,6 +800,35 @@ 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;
+ 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::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 82625d9f7..94cb2ed6a 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);
@@ -69,6 +71,9 @@ signals:
void visualDeckStorageUnusedColorIdentitiesOpacityChanged(bool value);
void visualDeckStorageInGameChanged(bool enabled);
void visualDeckStorageSelectionAnimationChanged(bool enabled);
+ void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
+ void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
+ void visualDeckEditorSampleHandSizeAmountChanged(int amount);
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@@ -134,6 +139,8 @@ private:
int printingSelectorCardSize;
bool includeRebalancedCards;
bool printingSelectorNavigationButtonsVisible;
+ bool deckEditorBannerCardComboBoxVisible;
+ bool deckEditorTagsWidgetVisible;
int visualDeckStorageSortingOrder;
bool visualDeckStorageShowFolders;
bool visualDeckStorageShowBannerCardComboBox;
@@ -147,6 +154,10 @@ private:
bool visualDeckStorageAlwaysConvert;
bool visualDeckStorageInGame;
bool visualDeckStorageSelectionAnimation;
+ int defaultDeckEditorType;
+ bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
+ int visualDatabaseDisplayFilterToMostRecentSetsAmount;
+ int visualDeckEditorSampleHandSize;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@@ -175,6 +186,7 @@ private:
int cardViewInitialRowsMax;
int cardViewExpandedRowsMax;
bool closeEmptyCardView;
+ bool focusCardViewSearchBar;
int pixmapCacheSize;
int networkCacheSize;
int redirectCacheTtl;
@@ -420,6 +432,14 @@ public:
{
return printingSelectorNavigationButtonsVisible;
}
+ bool getDeckEditorBannerCardComboBoxVisible() const
+ {
+ return deckEditorBannerCardComboBoxVisible;
+ }
+ bool getDeckEditorTagsWidgetVisible() const
+ {
+ return deckEditorTagsWidgetVisible;
+ }
int getVisualDeckStorageSortingOrder() const
{
return visualDeckStorageSortingOrder;
@@ -472,6 +492,22 @@ public:
{
return visualDeckStorageSelectionAnimation;
}
+ int getDefaultDeckEditorType() const
+ {
+ return defaultDeckEditorType;
+ }
+ bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
+ {
+ return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
+ }
+ int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
+ {
+ return visualDatabaseDisplayFilterToMostRecentSetsAmount;
+ }
+ int getVisualDeckEditorSampleHandSize() const
+ {
+ return visualDeckEditorSampleHandSize;
+ }
bool getHorizontalHand() const
{
return horizontalHand;
@@ -670,6 +706,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;
@@ -698,6 +735,10 @@ public:
{
return closeEmptyCardView;
}
+ bool getFocusCardViewSearchBar() const
+ {
+ return focusCardViewSearchBar;
+ }
ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
@@ -800,6 +841,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);
@@ -813,6 +856,10 @@ 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 setVisualDeckEditorSampleHandSize(int _amount);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
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
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
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...
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/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/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;
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_player.cpp b/common/server_player.cpp
index 60ebfa3c0..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;
@@ -417,6 +426,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 +555,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()));
@@ -1471,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;
@@ -1482,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) {
@@ -1619,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;
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);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 53260e1fd..032cdc95e 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 */)
{
}
@@ -208,6 +211,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 */)
{
}
@@ -249,6 +259,18 @@ 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 */)
+{
+}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
+{
+}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp
index de81cee3f..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) : CardDatabase(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,29 +458,12 @@ 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;
// 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 +493,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..314723706 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
@@ -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;
@@ -117,48 +120,49 @@ 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;
- QList allSets;
- QVariantMap setsMap;
- QString dataDir;
- QString getMainCardType(const QStringList &typeList);
+ /**
+ * The cards, indexed by name.
+ */
+ CardNameMap cards;
+
+ /**
+ * The sets, indexed by short name.
+ */
+ SetNameMap sets;
+
+ QList allSets;
+
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;
+ }
QList &getSets()
{
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 c1c366948..bea87dde2 100644
--- a/oracle/src/oraclewizard.cpp
+++ b/oracle/src/oraclewizard.cpp
@@ -58,9 +58,9 @@ 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);
+ importer = new OracleImporter(this);
nam = new QNetworkAccessManager(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)
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)
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..f235ab4f9 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)
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index c5cf99b68..db7dd9353 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 */)
{
}
@@ -212,6 +215,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 */)
{
}
@@ -253,6 +263,18 @@ 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 */)
+{
+}
+void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
+{
+}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
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);
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"
}