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 0650ae9f4..f1aa4a261 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -135,6 +135,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+ src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
diff --git a/cockatrice/src/client/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/tab_edhrec_main.cpp b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
index 0bd4e843a..2eed749af 100644
--- a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
+++ b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
@@ -356,7 +356,7 @@ void TabEdhRecMain::processAverageDeckResponse(QJsonObject reply)
{
EdhrecAverageDeckApiResponse deckData;
deckData.fromJson(reply);
- tabSupervisor->addVisualDeckEditorTab(deckData.deck.deckLoader);
+ tabSupervisor->openDeckInNewTab(deckData.deck.deckLoader);
}
void TabEdhRecMain::prettyPrintJson(const QJsonValue &value, int indentLevel)
diff --git a/cockatrice/src/client/tabs/tab_supervisor.cpp b/cockatrice/src/client/tabs/tab_supervisor.cpp
index 5d9600d11..4ed0e5a6b 100644
--- a/cockatrice/src/client/tabs/tab_supervisor.cpp
+++ b/cockatrice/src/client/tabs/tab_supervisor.cpp
@@ -590,7 +590,7 @@ void TabSupervisor::actTabDeckStorage(bool checked)
void TabSupervisor::openTabDeckStorage()
{
tabDeckStorage = new TabDeckStorage(this, client, userInfo);
- connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tabDeckStorage, aTabDeckStorage);
connect(tabDeckStorage, &Tab::closed, this, [this] {
tabDeckStorage = nullptr;
@@ -691,7 +691,7 @@ void TabSupervisor::gameJoined(const Event_GameJoined &event)
auto *tab = new TabGame(this, QList() << client, event, roomGameTypes);
connect(tab, &TabGame::gameClosing, this, &TabSupervisor::gameLeft);
connect(tab, &TabGame::openMessageDialog, this, &TabSupervisor::addMessageTab);
- connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tab);
gameTabs.insert(event.game_info().game_id(), tab);
setCurrentWidget(tab);
@@ -701,7 +701,7 @@ void TabSupervisor::localGameJoined(const Event_GameJoined &event)
{
auto *tab = new TabGame(this, localClients, event, QMap());
connect(tab, &TabGame::gameClosing, this, &TabSupervisor::gameLeft);
- connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tab);
gameTabs.insert(event.game_info().game_id(), tab);
setCurrentWidget(tab);
@@ -807,6 +807,29 @@ void TabSupervisor::talkLeft(TabMessage *tab)
removeTab(indexOf(tab));
}
+/**
+ * Creates a new deck editor tab and loads the deck into it.
+ * Creates either a classic or visual deck editor tab depending on settings
+ * @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
+ */
+void TabSupervisor::openDeckInNewTab(const DeckLoader *deckToOpen)
+{
+ int type = SettingsCache::instance().getDefaultDeckEditorType();
+ switch (type) {
+ case ClassicDeckEditor:
+ addDeckEditorTab(deckToOpen);
+ break;
+ case VisualDeckEditor:
+ addVisualDeckEditorTab(deckToOpen);
+ break;
+ default:
+ qCWarning(TabSupervisorLog) << "Unknown DeckEditorType [" << type
+ << "]; opening ClassicDeckEditor as fallback";
+ addDeckEditorTab(deckToOpen);
+ break;
+ }
+}
+
/**
* Creates a new deck editor tab
* @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
diff --git a/cockatrice/src/client/tabs/tab_supervisor.h b/cockatrice/src/client/tabs/tab_supervisor.h
index 0ca13ac41..1c367043e 100644
--- a/cockatrice/src/client/tabs/tab_supervisor.h
+++ b/cockatrice/src/client/tabs/tab_supervisor.h
@@ -75,6 +75,14 @@ protected:
class TabSupervisor : public QTabWidget
{
Q_OBJECT
+
+public:
+ enum DeckEditorType
+ {
+ ClassicDeckEditor,
+ VisualDeckEditor
+ };
+
private:
ServerInfo_User *userInfo;
AbstractClient *client;
@@ -152,6 +160,7 @@ signals:
void showWindowIfHidden();
public slots:
+ void openDeckInNewTab(const DeckLoader *deckToOpen);
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
TabDeckEditorVisual *addVisualDeckEditorTab(const DeckLoader *deckToOpen);
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
diff --git a/cockatrice/src/client/tabs/visual_deck_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/ui/widgets/cards/additional_info/mana_symbol_widget.cpp b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
index e42e93444..b17b0ff47 100644
--- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
@@ -66,7 +66,7 @@ void ManaSymbolWidget::loadManaIcon()
QString filename = "theme:icons/mana/";
if (symbol == "W" || symbol == "U" || symbol == "B" || symbol == "R" || symbol == "G") {
- filename += symbol + ".svg";
+ filename += symbol;
}
manaIcon = QPixmap(filename);
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
index 4ee3de5eb..5e275f8e9 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
@@ -64,6 +64,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverT
});
}
+CardInfoPictureWidget::~CardInfoPictureWidget()
+{
+ enlargedPixmapWidget->hide();
+ enlargedPixmapWidget->deleteLater();
+}
+
/**
* @brief Sets the card to be displayed and updates the pixmap.
* @param card A shared pointer to the card information (CardInfoPtr).
@@ -341,6 +347,12 @@ void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
emit cardClicked();
}
+void CardInfoPictureWidget::hideEvent(QHideEvent *event)
+{
+ enlargedPixmapWidget->hide();
+ QWidget::hideEvent(event);
+}
+
QMenu *CardInfoPictureWidget::createRightClickMenu()
{
auto *cardMenu = new QMenu(this);
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
index 10cc422aa..79de74526 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
@@ -21,6 +21,7 @@ public:
explicit CardInfoPictureWidget(QWidget *parent = nullptr,
bool hoverToZoomEnabled = false,
bool raiseOnEnter = false);
+ ~CardInfoPictureWidget();
CardInfoPtr getInfo()
{
return info;
@@ -52,6 +53,7 @@ protected:
void moveEvent(QMoveEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
+ void hideEvent(QHideEvent *event) override;
void loadPixmap();
[[nodiscard]] const QPixmap &getResizedPixmap() const
{
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/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 9adf8e095..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
@@ -91,7 +91,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
bannerCardLabel = new QLabel();
bannerCardLabel->setObjectName("bannerCardLabel");
bannerCardLabel->setText(tr("Banner Card"));
- bannerCardLabel->setHidden(SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
+ bannerCardLabel->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
bannerCardComboBox = new QComboBox(this);
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
// Delay the update to avoid race conditions
@@ -228,19 +228,22 @@ void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*¤t*/, const
void DeckEditorDeckDockWidget::updateName(const QString &name)
{
deckModel->getDeckList()->setName(name);
- emit deckChanged();
+ emit nameChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateComments()
{
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
- emit deckChanged();
+ emit commentsChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateHash()
{
hashLabel->setText(deckModel->getDeckList()->getDeckHash());
- emit deckChanged();
+ emit hashChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
@@ -294,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);
@@ -314,7 +321,7 @@ void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
QVariantMap itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
deckModel->getDeckList()->setBannerCard(
QPair(itemData["name"].toString(), itemData["uuid"].toString()));
- emit deckChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
@@ -362,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());
@@ -422,7 +433,7 @@ void DeckEditorDeckDockWidget::actSwapCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
update();
@@ -517,7 +528,7 @@ void DeckEditorDeckDockWidget::actRemoveCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
}
@@ -535,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)
@@ -563,6 +574,7 @@ void DeckEditorDeckDockWidget::retranslateUi()
setWindowTitle(tr("Deck"));
nameLabel->setText(tr("Deck &name:"));
+ quickSettingsWidget->setToolTip(tr("Banner Card/Tags Visibility Settings"));
showBannerCardCheckBox->setText(tr("Show banner card selection menu"));
showTagsWidgetCheckBox->setText(tr("Show tags selection menu"));
commentsLabel->setText(tr("&Comments:"));
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
index 0a9ebcd65..c81b4a6fa 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
@@ -49,7 +49,11 @@ public slots:
void offsetCountAtIndex(const QModelIndex &idx, int offset);
signals:
+ void nameChanged();
+ void commentsChanged();
+ void hashChanged();
void deckChanged();
+ void deckModified();
void cardChanged(CardInfoPtr _card);
private:
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 681282fc4..e93253585 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
@@ -58,6 +58,8 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
toggleButton->setText(tr("Mode: Include/Exclude"));
break;
}
+
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
index 1a099501e..21ec205fd 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
@@ -39,6 +39,7 @@ VisualDatabaseDisplayFilterSaveLoadWidget::VisualDatabaseDisplayFilterSaveLoadWi
void VisualDatabaseDisplayFilterSaveLoadWidget::retranslateUi()
{
saveButton->setText(tr("Save Filter"));
+ saveButton->setToolTip(tr("Save all currently applied filters to a file"));
filenameInput->setPlaceholderText(tr("Enter filename..."));
}
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
index 688f8f4d2..8cf9c6605 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
@@ -47,6 +47,14 @@ VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWi
createMainTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize toggle button text
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayMainTypeFilterWidget::retranslateUi()
+{
+ spinBox->setToolTip(tr("Do not display card main-types with less than this amount of cards in the database"));
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplayMainTypeFilterWidget::createMainTypeButtons()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
index b13071825..07086bbe3 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplayMainTypeFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createMainTypeButtons();
void updateMainTypeButtonsVisibility();
int getMaxMainTypeCount() const;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
index 69e782b66..e0ededd50 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
@@ -45,6 +45,7 @@ void VisualDatabaseDisplayNameFilterWidget::retranslateUi()
{
searchBox->setPlaceholderText(tr("Filter by name..."));
loadFromDeckButton->setText(tr("Load from Deck"));
+ loadFromDeckButton->setToolTip(tr("Apply all card names in currently loaded deck as exact match name filters"));
}
void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
index 4b8fc21d8..c6ea811a9 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
@@ -51,6 +51,14 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
createSubTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize the toggle button text
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplaySubTypeFilterWidget::retranslateUi()
+{
+ spinBox->setToolTip(tr("Do not display card sub-types with less than this amount of cards in the database"));
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
index 72a0a25bb..64c9c19cd 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplaySubTypeFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createSubTypeButtons();
void updateSubTypeButtonsVisibility();
int getMaxSubTypeCount() const;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
index 9d82463be..f394f508f 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
@@ -150,6 +150,18 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
connect(loadCardsTimer, &QTimer::timeout, this, [this]() { loadCurrentPage(); });
loadCardsTimer->start(5000);
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayWidget::retranslateUi()
+{
+ clearFilterWidget->setToolTip(tr("Clear all filters"));
+
+ quickFilterSaveLoadWidget->setToolTip(tr("Save and load filters"));
+ quickFilterNameWidget->setToolTip(tr("Filter by exact card name"));
+ quickFilterSubTypeWidget->setToolTip(tr("Filter by card sub-type"));
+ quickFilterSetWidget->setToolTip(tr("Filter by set"));
}
void VisualDatabaseDisplayWidget::resizeEvent(QResizeEvent *event)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
index 6d75698dc..8f0cdba97 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
@@ -38,6 +38,7 @@ public:
AbstractTabDeckEditor *deckEditor,
CardDatabaseModel *database_model,
CardDatabaseDisplayModel *database_display_model);
+ void retranslateUi();
void adjustCardsPerPage();
void populateCards();
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
index 7868627e2..8530a8233 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
@@ -2,6 +2,7 @@
#include "../../../../deck/deck_loader.h"
#include "../../../../game/cards/card_database_manager.h"
+#include "../../../../settings/cache_settings.h"
#include "../cards/card_info_picture_widget.h"
#include
@@ -12,23 +13,45 @@ VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *pare
layout = new QVBoxLayout(this);
setLayout(layout);
+ resetAndHandSizeContainerWidget = new QWidget(this);
+ resetAndHandSizeLayout = new QHBoxLayout(resetAndHandSizeContainerWidget);
+ resetAndHandSizeContainerWidget->setLayout(resetAndHandSizeLayout);
+
resetButton = new QPushButton(this);
connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay()));
- layout->addWidget(resetButton);
+ resetAndHandSizeLayout->addWidget(resetButton);
+
+ handSizeSpinBox = new QSpinBox(this);
+ handSizeSpinBox->setValue(SettingsCache::instance().getVisualDeckEditorSampleHandSize());
+ handSizeSpinBox->setMinimum(1);
+ connect(handSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckEditorSampleHandSize);
+ connect(handSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), this,
+ &VisualDeckEditorSampleHandWidget::updateDisplay);
+ resetAndHandSizeLayout->addWidget(handSizeSpinBox);
+
+ layout->addWidget(resetAndHandSizeContainerWidget);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
layout->addWidget(flowWidget);
- for (CardInfoPtr card : getRandomCards(7)) {
+ cardSizeWidget = new CardSizeWidget(this, flowWidget);
+ layout->addWidget(cardSizeWidget);
+
+ for (CardInfoPtr card : getRandomCards(handSizeSpinBox->value())) {
auto displayWidget = new CardInfoPictureWidget(this);
displayWidget->setCard(card);
+ displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
flowWidget->addWidget(displayWidget);
}
+
+ retranslateUi();
}
void VisualDeckEditorSampleHandWidget::retranslateUi()
{
- resetButton->setText(tr("Reset"));
+ resetButton->setText(tr("Draw a new sample hand"));
+ handSizeSpinBox->setToolTip(tr("Sample hand size"));
}
void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
@@ -41,9 +64,12 @@ void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
void VisualDeckEditorSampleHandWidget::updateDisplay()
{
flowWidget->clearLayout();
- for (CardInfoPtr card : getRandomCards(7)) {
+ for (CardInfoPtr card : getRandomCards(handSizeSpinBox->value())) {
auto displayWidget = new CardInfoPictureWidget(this);
displayWidget->setCard(card);
+ displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
+ connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, displayWidget,
+ &CardInfoPictureWidget::setScaleFactor);
flowWidget->addWidget(displayWidget);
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
index 44dc04cab..ba09a978e 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
@@ -1,10 +1,12 @@
#ifndef VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
#define VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
+#include "../../../../client/ui/widgets/cards/card_size_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../general/layout_containers/flow_widget.h"
#include
+#include
#include
class VisualDeckEditorSampleHandWidget : public QWidget
@@ -22,8 +24,12 @@ public slots:
private:
DeckListModel *deckListModel;
QVBoxLayout *layout;
+ QWidget *resetAndHandSizeContainerWidget;
+ QHBoxLayout *resetAndHandSizeLayout;
QPushButton *resetButton;
+ QSpinBox *handSizeSpinBox;
FlowWidget *flowWidget;
+ CardSizeWidget *cardSizeWidget;
};
#endif // VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
index 0914a472e..1ebf59e36 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
@@ -190,7 +190,12 @@ void VisualDeckEditorWidget::retranslateUi()
{
sortLabel->setText(tr("Click and drag to change the sort order within the groups"));
searchPushButton->setText(tr("Quick search and add card"));
+ searchPushButton->setToolTip(tr("Search for closest match in the database (with auto-suggestions) and add "
+ "preferred printing to the deck on pressing enter"));
+ sortCriteriaButton->setToolTip(tr("Configure how cards are sorted within their groups"));
displayTypeButton->setText(tr("Flat Layout"));
+ displayTypeButton->setToolTip(
+ tr("Change how cards are displayed within zones (i.e. overlapped or fully visible.)"));
}
void VisualDeckEditorWidget::updateZoneWidgets()
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
index b048b2372..ef59e90ff 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
@@ -47,6 +47,7 @@ void DeckPreviewColorIdentityFilterWidget::retranslateUi()
{
// Set the toggle button text based on the current mode
toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
+ toggleButton->setToolTip(tr("Color identity filter mode (AND/OR/NOT conjunctions of filters)"));
}
void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar color, bool active)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/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.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 25cb5a1e5..47ed6ebee 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
@@ -33,32 +33,42 @@ void VisualDeckStorageTagFilterWidget::showEvent(QShowEvent *event)
void VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList &deckPreviews) const
{
- // Collect selected tags from DeckPreviewTagDisplayWidget
QStringList selectedTags;
+ QStringList excludedTags;
+
+ // Collect selected and excluded tags
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
- if (tagWidget->getSelected()) {
- selectedTags.append(tagWidget->getTagName());
+ switch (tagWidget->getState()) {
+ case TagState::Selected:
+ selectedTags.append(tagWidget->getTagName());
+ break;
+ case TagState::Excluded:
+ excludedTags.append(tagWidget->getTagName());
+ break;
+ default:
+ break;
}
}
- // If no tags are selected, set all decks as visible
- if (selectedTags.isEmpty()) {
+ // If no tags are selected or excluded, show all
+ if (selectedTags.isEmpty() && excludedTags.isEmpty()) {
for (DeckPreviewWidget *deckPreview : deckPreviews) {
deckPreview->filteredByTags = false;
}
return;
}
- // Filter DeckPreviewWidgets that contain all of the selected tags
- QList filteredDecks;
for (DeckPreviewWidget *deckPreview : deckPreviews) {
QStringList deckTags = deckPreview->deckLoader->getTags();
- // Check if all selectedTags are in deckTags
- bool allTagsPresent = std::all_of(selectedTags.begin(), selectedTags.end(),
+ bool hasAllSelected = std::all_of(selectedTags.begin(), selectedTags.end(),
[&deckTags](const QString &tag) { return deckTags.contains(tag); });
- deckPreview->filteredByTags = !allTagsPresent;
+ bool hasAnyExcluded = std::any_of(excludedTags.begin(), excludedTags.end(),
+ [&deckTags](const QString &tag) { return deckTags.contains(tag); });
+
+ // Filter out if any excluded tag is present or if any selected tag is missing
+ deckPreview->filteredByTags = !(hasAllSelected && !hasAnyExcluded);
}
}
@@ -72,13 +82,15 @@ void VisualDeckStorageTagFilterWidget::refreshTags()
void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QSet &tags)
{
- // Iterate through all DeckPreviewTagDisplayWidgets
+ auto *flowWidget = findChild();
+
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
- // If the tag is not in the provided tags list, remove the widget
- if (!tags.contains(tagWidget->getTagName())) {
- auto *flowWidget = findChild();
+ const QString &tagName = tagWidget->getTagName();
+
+ // Keep the tag widget if it is either selected or excluded
+ if (!tags.contains(tagName) && tagWidget->getState() == TagState::NotSelected) {
flowWidget->removeWidget(tagWidget);
- tagWidget->deleteLater(); // Safely delete the widget
+ tagWidget->deleteLater();
}
}
}
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/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp
index 99f11efd6..c0195af87 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"
@@ -686,6 +687,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);
@@ -699,8 +704,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);
@@ -756,12 +762,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);
@@ -811,6 +825,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"));
@@ -831,6 +846,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 32ce5a410..f0b9c62c9 100644
--- a/cockatrice/src/dialogs/dlg_settings.h
+++ b/cockatrice/src/dialogs/dlg_settings.h
@@ -149,6 +149,7 @@ private:
QCheckBox clickPlaysAllSelectedCheckBox;
QCheckBox playToStackCheckBox;
QCheckBox closeEmptyCardViewCheckBox;
+ QCheckBox focusCardViewSearchBarCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox useTearOffMenusCheckBox;
QCheckBox tapAnimationCheckBox;
@@ -157,6 +158,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/board/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp
index 0c7acd917..d7b0b7d46 100644
--- a/cockatrice/src/game/board/abstract_card_drag_item.cpp
+++ b/cockatrice/src/game/board/abstract_card_drag_item.cpp
@@ -19,6 +19,7 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
if (parentDrag) {
parentDrag->addChildDrag(this);
setZValue(2000000007 + hotSpot.x() * 1000000 + hotSpot.y() * 1000 + 1000);
+ connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
} else {
hotSpot = QPointF{qBound(0.0, hotSpot.x(), static_cast(CARD_WIDTH - 1)),
qBound(0.0, hotSpot.y(), static_cast(CARD_HEIGHT - 1))};
@@ -39,12 +40,8 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
prepareGeometryChange();
update();
});
-}
-AbstractCardDragItem::~AbstractCardDragItem()
-{
- for (int i = 0; i < childDrags.size(); i++)
- delete childDrags[i];
+ connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
}
QPainterPath AbstractCardDragItem::shape() const
diff --git a/cockatrice/src/game/board/abstract_card_drag_item.h b/cockatrice/src/game/board/abstract_card_drag_item.h
index 85ce38b15..a411a24d1 100644
--- a/cockatrice/src/game/board/abstract_card_drag_item.h
+++ b/cockatrice/src/game/board/abstract_card_drag_item.h
@@ -26,7 +26,6 @@ public:
return Type;
}
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
- ~AbstractCardDragItem() override;
QRectF boundingRect() const override
{
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
diff --git a/cockatrice/src/game/board/card_drag_item.cpp b/cockatrice/src/game/board/card_drag_item.cpp
index d21e9168b..ab4431958 100644
--- a/cockatrice/src/game/board/card_drag_item.cpp
+++ b/cockatrice/src/game/board/card_drag_item.cpp
@@ -47,10 +47,25 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
cursorZone = zoneViewZone;
else if (cardZone)
cursorZone = cardZone;
- if (!cursorZone)
- return;
+
+ // Always update the current zone, even if its null, to cancel the drag
+ // instead of dropping cards into an non-intuitive location.
currentZone = cursorZone;
+ if (!cursorZone) {
+ // Avoid the cards getting stuck visually when not over
+ // any zone.
+ QPointF newPos = cursorScenePos - hotSpot;
+
+ if (newPos != pos()) {
+ for (int i = 0; i < childDrags.size(); i++)
+ childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
+ setPos(newPos);
+ }
+
+ return;
+ }
+
QPointF zonePos = currentZone->scenePos();
QPointF cursorPosInZone = cursorScenePos - zonePos;
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index 2380454b9..8ce7b0055 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -145,7 +145,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
PileZone *sb = addZone(new PileZone(this, "sb", false, false, playerArea));
sb->setVisible(false);
- table = addZone(new TableZone(this, this));
+ table = addZone(new TableZone(this, "table", this));
connect(table, &TableZone::sizeChanged, this, &Player::updateBoundingRect);
stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this));
@@ -401,6 +401,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);
@@ -458,6 +461,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;
mCardCounters = nullptr;
@@ -833,6 +837,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..."));
@@ -2726,19 +2735,79 @@ void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*op
void Player::processPlayerInfo(const ServerInfo_Player &info)
{
+ static QSet builtinZones{/* PileZones */
+ "deck", "grave", "rfg", "sb",
+ /* TableZone */
+ "table",
+ /* StackZone */
+ "stack",
+ /* HandZone */
+ "hand"};
clearCounters();
clearArrows();
- QMapIterator zoneIt(zones);
+ QMutableMapIterator zoneIt(zones);
while (zoneIt.hasNext()) {
zoneIt.next().value()->clearContents();
+
+ if (!builtinZones.contains(zoneIt.key())) {
+ zoneIt.remove();
+ }
+ }
+
+ // Can be null if we are not the local player!
+ if (mCustomZones) {
+ mCustomZones->clear();
+ mCustomZones->menuAction()->setVisible(false);
}
const int zoneListSize = info.zone_list_size();
for (int i = 0; i < zoneListSize; ++i) {
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
- CardZone *zone = zones.value(QString::fromStdString(zoneInfo.name()), 0);
+
+ QString zoneName = QString::fromStdString(zoneInfo.name());
+ CardZone *zone = zones.value(zoneName, 0);
if (!zone) {
+ // Create a new CardZone if it doesn't exist
+
+ if (zoneInfo.with_coords()) {
+ // Visibility not currently supported for TableZone
+ zone = addZone(new TableZone(this, zoneName, this));
+ } else {
+ // Zones without coordinats are always treated as non-shufflable
+ // PileZones, although supporting alternate hand or stack zones
+ // might make sense in some scenarios.
+ bool contentsKnown;
+
+ switch (zoneInfo.type()) {
+ case ServerInfo_Zone::PrivateZone:
+ contentsKnown = local || judge || (game->getSpectator() && game->getSpectatorsSeeEverything());
+ break;
+
+ case ServerInfo_Zone::PublicZone:
+ contentsKnown = true;
+ break;
+
+ case ServerInfo_Zone::HiddenZone:
+ contentsKnown = false;
+ break;
+ }
+
+ zone = addZone(new PileZone(this, zoneName, /* isShufflable */ false, contentsKnown, this));
+ }
+
+ // Non-builtin zones are hidden by default and can't be interacted
+ // with, except through menus.
+ zone->setVisible(false);
+
+ if (mCustomZones) {
+ mCustomZones->menuAction()->setVisible(true);
+ QAction *aViewZone = mCustomZones->addAction(tr("View custom zone '%1'").arg(zoneName));
+ aViewZone->setData(zoneName);
+ connect(aViewZone, &QAction::triggered, this,
+ [zoneName, this]() { static_cast(scene())->toggleZoneView(this, zoneName, -1); });
+ }
+
continue;
}
diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h
index 960a24057..9062ac5b4 100644
--- a/cockatrice/src/game/player/player.h
+++ b/cockatrice/src/game/player/player.h
@@ -253,7 +253,7 @@ public:
private:
TabGame *game;
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mLendLibrary, *mRevealTopCard,
- *mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard, *mCardCounters;
+ *mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard, *mCustomZones, *mCardCounters;
TearOffMenu *moveGraveMenu, *moveRfgMenu, *graveMenu, *moveHandMenu, *handMenu, *libraryMenu, *topLibraryMenu,
*bottomLibraryMenu, *rfgMenu, *playerMenu;
QList playerLists;
diff --git a/cockatrice/src/game/zones/card_zone.cpp b/cockatrice/src/game/zones/card_zone.cpp
index 05b4c35b9..089ed0a2d 100644
--- a/cockatrice/src/game/zones/card_zone.cpp
+++ b/cockatrice/src/game/zones/card_zone.cpp
@@ -92,6 +92,10 @@ QString CardZone::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
default:
break;
}
+ else {
+ return (theirOwn ? tr("their custom zone '%1'", "nominative").arg(name)
+ : tr("%1's custom zone '%2'", "nominative").arg(ownerName).arg(name));
+ }
return QString();
}
diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp
index e214b2e09..cee782560 100644
--- a/cockatrice/src/game/zones/table_zone.cpp
+++ b/cockatrice/src/game/zones/table_zone.cpp
@@ -19,8 +19,8 @@ const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
const QColor TableZone::GRADIENT_COLOR = QColor(255, 255, 255, 150);
const QColor TableZone::GRADIENT_COLORLESS = QColor(255, 255, 255, 0);
-TableZone::TableZone(Player *_p, QGraphicsItem *parent)
- : SelectZone(_p, "table", true, false, true, parent), active(false)
+TableZone::TableZone(Player *_p, const QString &name, QGraphicsItem *parent)
+ : SelectZone(_p, name, true, false, true, parent), active(false)
{
connect(themeManager, &ThemeManager::themeChanged, this, &TableZone::updateBg);
connect(&SettingsCache::instance(), &SettingsCache::invertVerticalCoordinateChanged, this,
diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h
index f3fbdccb6..3d464e6f3 100644
--- a/cockatrice/src/game/zones/table_zone.h
+++ b/cockatrice/src/game/zones/table_zone.h
@@ -98,7 +98,7 @@ public:
@param _p the Player
@param parent defaults to null
*/
- explicit TableZone(Player *_p, QGraphicsItem *parent = nullptr);
+ explicit TableZone(Player *_p, const QString &name, QGraphicsItem *parent = nullptr);
/**
@return a QRectF of the TableZone bounding box.
diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp
index 1721831ac..f0430f549 100644
--- a/cockatrice/src/game/zones/view_zone_widget.cpp
+++ b/cockatrice/src/game/zones/view_zone_widget.cpp
@@ -56,6 +56,11 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(&searchEdit); });
+ if (SettingsCache::instance().getFocusCardViewSearchBar()) {
+ this->setActive(true);
+ searchEdit.setFocus();
+ }
+
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
searchEditProxy->setWidget(&searchEdit);
searchEditProxy->setZValue(2000000007);
diff --git a/cockatrice/src/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 045f47242..ed25801f6 100644
--- a/cockatrice/src/server/message_log_widget.cpp
+++ b/cockatrice/src/server/message_log_widget.cpp
@@ -87,6 +87,8 @@ QPair MessageLogWidget::getFromStr(CardZone *zone, QString car
fromStr = tr(" from sideboard");
} else if (zoneName == STACK_ZONE_NAME) {
fromStr = tr(" from the stack");
+ } else {
+ fromStr = tr(" from custom zone '%1'").arg(zoneName);
}
if (!cardNameContainsStartZone) {
@@ -322,13 +324,16 @@ void MessageLogWidget::logMoveCard(Player *player,
} else if (targetZoneName == STACK_ZONE_NAME) {
soundEngine->playSound("play_card");
finalStr = tr("%1 plays %2%3.");
+ } else {
+ finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
}
if (usesNewX) {
appendHtmlServerMessage(
finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second).arg(newX));
} else {
- appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second));
+ appendHtmlServerMessage(
+ finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second).arg(targetZoneName));
}
}
diff --git a/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 cb5025540..1635d8420 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -255,6 +255,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();
@@ -289,10 +290,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();
@@ -373,6 +376,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;
@@ -795,6 +804,12 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
}
+void SettingsCache::setDefaultDeckEditorType(int value)
+{
+ defaultDeckEditorType = value;
+ settings->setValue("interface/defaultDeckEditorType", defaultDeckEditorType);
+}
+
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled)
{
visualDatabaseDisplayFilterToMostRecentSetsEnabled = _enabled;
@@ -811,6 +826,13 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _am
emit visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(visualDatabaseDisplayFilterToMostRecentSetsAmount);
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int _amount)
+{
+ visualDeckEditorSampleHandSize = _amount;
+ settings->setValue("interface/visualdeckeditorsamplehandsize", visualDeckEditorSampleHandSize);
+ emit visualDeckEditorSampleHandSizeAmountChanged(visualDeckEditorSampleHandSize);
+}
+
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
{
horizontalHand = static_cast(_horizontalHand);
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index 4555681e0..f4cc95bb3 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -74,6 +74,7 @@ signals:
void visualDeckStorageSelectionAnimationChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
+ void visualDeckEditorSampleHandSizeAmountChanged(int amount);
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@@ -155,8 +156,10 @@ private:
bool visualDeckStorageAlwaysConvert;
bool visualDeckStorageInGame;
bool visualDeckStorageSelectionAnimation;
+ int defaultDeckEditorType;
bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
int visualDatabaseDisplayFilterToMostRecentSetsAmount;
+ int visualDeckEditorSampleHandSize;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@@ -185,6 +188,7 @@ private:
int cardViewInitialRowsMax;
int cardViewExpandedRowsMax;
bool closeEmptyCardView;
+ bool focusCardViewSearchBar;
int pixmapCacheSize;
int networkCacheSize;
int redirectCacheTtl;
@@ -490,6 +494,10 @@ public:
{
return visualDeckStorageSelectionAnimation;
}
+ int getDefaultDeckEditorType() const
+ {
+ return defaultDeckEditorType;
+ }
bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
{
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
@@ -498,6 +506,10 @@ public:
{
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
}
+ int getVisualDeckEditorSampleHandSize() const
+ {
+ return visualDeckEditorSampleHandSize;
+ }
bool getHorizontalHand() const
{
return horizontalHand;
@@ -696,6 +708,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;
@@ -724,6 +737,10 @@ public:
{
return closeEmptyCardView;
}
+ bool getFocusCardViewSearchBar() const
+ {
+ return focusCardViewSearchBar;
+ }
ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
@@ -843,8 +860,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/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/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 93048d3cf..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 */)
{
}
@@ -256,12 +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/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/mocks.cpp b/tests/carddatabase/mocks.cpp
index a2ca73fb1..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 */)
{
}
@@ -260,12 +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 */)
{
}