From 24e27d3c31c02bf42d0946ec6135994e469542f6 Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Fri, 2 May 2025 18:58:21 +0200
Subject: [PATCH 01/26] fix: Prevent dragged cards getting stuck (#5896)
* fix: Prevent dragged cards getting stuck
Update the position of the card even if it is not above any zone.
* Also update the currentZone
---
cockatrice/src/game/board/card_drag_item.cpp | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/game/board/card_drag_item.cpp b/cockatrice/src/game/board/card_drag_item.cpp
index d21e9168b..ab4431958 100644
--- a/cockatrice/src/game/board/card_drag_item.cpp
+++ b/cockatrice/src/game/board/card_drag_item.cpp
@@ -47,10 +47,25 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
cursorZone = zoneViewZone;
else if (cardZone)
cursorZone = cardZone;
- if (!cursorZone)
- return;
+
+ // Always update the current zone, even if its null, to cancel the drag
+ // instead of dropping cards into an non-intuitive location.
currentZone = cursorZone;
+ if (!cursorZone) {
+ // Avoid the cards getting stuck visually when not over
+ // any zone.
+ QPointF newPos = cursorScenePos - hotSpot;
+
+ if (newPos != pos()) {
+ for (int i = 0; i < childDrags.size(); i++)
+ childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
+ setPos(newPos);
+ }
+
+ return;
+ }
+
QPointF zonePos = currentZone->scenePos();
QPointF cursorPosInZone = cursorScenePos - zonePos;
From 57c6f2716fe28c1d1d446f1232d35991badb037c Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Fri, 2 May 2025 10:00:32 -0700
Subject: [PATCH 02/26] Add setting for which deck editor tab to open deck in
(#5895)
* Create new setting
* Update settings dlg
* implement functionality
* Make setting into an enum
---
.../tabs/api/edhrec/tab_edhrec_main.cpp | 2 +-
cockatrice/src/client/tabs/tab_supervisor.cpp | 29 +++++++++++++++++--
cockatrice/src/client/tabs/tab_supervisor.h | 9 ++++++
.../tab_deck_storage_visual.cpp | 2 +-
cockatrice/src/dialogs/dlg_settings.cpp | 12 ++++++++
cockatrice/src/dialogs/dlg_settings.h | 2 ++
cockatrice/src/settings/cache_settings.cpp | 7 +++++
cockatrice/src/settings/cache_settings.h | 6 ++++
dbconverter/src/mocks.cpp | 3 ++
tests/carddatabase/mocks.cpp | 3 ++
10 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
index 0bd4e843a..2eed749af 100644
--- a/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
+++ b/cockatrice/src/client/tabs/api/edhrec/tab_edhrec_main.cpp
@@ -356,7 +356,7 @@ void TabEdhRecMain::processAverageDeckResponse(QJsonObject reply)
{
EdhrecAverageDeckApiResponse deckData;
deckData.fromJson(reply);
- tabSupervisor->addVisualDeckEditorTab(deckData.deck.deckLoader);
+ tabSupervisor->openDeckInNewTab(deckData.deck.deckLoader);
}
void TabEdhRecMain::prettyPrintJson(const QJsonValue &value, int indentLevel)
diff --git a/cockatrice/src/client/tabs/tab_supervisor.cpp b/cockatrice/src/client/tabs/tab_supervisor.cpp
index 5d9600d11..4ed0e5a6b 100644
--- a/cockatrice/src/client/tabs/tab_supervisor.cpp
+++ b/cockatrice/src/client/tabs/tab_supervisor.cpp
@@ -590,7 +590,7 @@ void TabSupervisor::actTabDeckStorage(bool checked)
void TabSupervisor::openTabDeckStorage()
{
tabDeckStorage = new TabDeckStorage(this, client, userInfo);
- connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tabDeckStorage, aTabDeckStorage);
connect(tabDeckStorage, &Tab::closed, this, [this] {
tabDeckStorage = nullptr;
@@ -691,7 +691,7 @@ void TabSupervisor::gameJoined(const Event_GameJoined &event)
auto *tab = new TabGame(this, QList() << client, event, roomGameTypes);
connect(tab, &TabGame::gameClosing, this, &TabSupervisor::gameLeft);
connect(tab, &TabGame::openMessageDialog, this, &TabSupervisor::addMessageTab);
- connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tab);
gameTabs.insert(event.game_info().game_id(), tab);
setCurrentWidget(tab);
@@ -701,7 +701,7 @@ void TabSupervisor::localGameJoined(const Event_GameJoined &event)
{
auto *tab = new TabGame(this, localClients, event, QMap());
connect(tab, &TabGame::gameClosing, this, &TabSupervisor::gameLeft);
- connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
+ connect(tab, &TabGame::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tab);
gameTabs.insert(event.game_info().game_id(), tab);
setCurrentWidget(tab);
@@ -807,6 +807,29 @@ void TabSupervisor::talkLeft(TabMessage *tab)
removeTab(indexOf(tab));
}
+/**
+ * Creates a new deck editor tab and loads the deck into it.
+ * Creates either a classic or visual deck editor tab depending on settings
+ * @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
+ */
+void TabSupervisor::openDeckInNewTab(const DeckLoader *deckToOpen)
+{
+ int type = SettingsCache::instance().getDefaultDeckEditorType();
+ switch (type) {
+ case ClassicDeckEditor:
+ addDeckEditorTab(deckToOpen);
+ break;
+ case VisualDeckEditor:
+ addVisualDeckEditorTab(deckToOpen);
+ break;
+ default:
+ qCWarning(TabSupervisorLog) << "Unknown DeckEditorType [" << type
+ << "]; opening ClassicDeckEditor as fallback";
+ addDeckEditorTab(deckToOpen);
+ break;
+ }
+}
+
/**
* Creates a new deck editor tab
* @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
diff --git a/cockatrice/src/client/tabs/tab_supervisor.h b/cockatrice/src/client/tabs/tab_supervisor.h
index 0ca13ac41..1c367043e 100644
--- a/cockatrice/src/client/tabs/tab_supervisor.h
+++ b/cockatrice/src/client/tabs/tab_supervisor.h
@@ -75,6 +75,14 @@ protected:
class TabSupervisor : public QTabWidget
{
Q_OBJECT
+
+public:
+ enum DeckEditorType
+ {
+ ClassicDeckEditor,
+ VisualDeckEditor
+ };
+
private:
ServerInfo_User *userInfo;
AbstractClient *client;
@@ -152,6 +160,7 @@ signals:
void showWindowIfHidden();
public slots:
+ void openDeckInNewTab(const DeckLoader *deckToOpen);
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
TabDeckEditorVisual *addVisualDeckEditorTab(const DeckLoader *deckToOpen);
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
diff --git a/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp b/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
index 38af03c59..65b4fcab0 100644
--- a/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
+++ b/cockatrice/src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
@@ -12,7 +12,7 @@
TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
: Tab(_tabSupervisor), visualDeckStorageWidget(new VisualDeckStorageWidget(this))
{
- connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::addVisualDeckEditorTab);
+ connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::openDeckInNewTab);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this,
&TabDeckStorageVisual::actOpenLocalDeck);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, this,
diff --git a/cockatrice/src/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp
index 502662c14..cda737951 100644
--- a/cockatrice/src/dialogs/dlg_settings.cpp
+++ b/cockatrice/src/dialogs/dlg_settings.cpp
@@ -4,6 +4,7 @@
#include "../client/network/release_channel.h"
#include "../client/network/spoiler_background_updater.h"
#include "../client/sound_engine.h"
+#include "../client/tabs/tab_supervisor.h"
#include "../client/ui/picture_loader/picture_loader.h"
#include "../client/ui/theme_manager.h"
#include "../deck/custom_line_edit.h"
@@ -699,12 +700,20 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
index == visualDeckStoragePromptForConversionIndexAlways);
});
+ defaultDeckEditorTypeSelector.addItem(""); // these will be set in retranslateUI
+ defaultDeckEditorTypeSelector.addItem("");
+ defaultDeckEditorTypeSelector.setCurrentIndex(SettingsCache::instance().getDefaultDeckEditorType());
+ connect(&defaultDeckEditorTypeSelector, QOverload::of(&QComboBox::currentIndexChanged),
+ &SettingsCache::instance(), &SettingsCache::setDefaultDeckEditorType);
+
auto *deckEditorGrid = new QGridLayout;
deckEditorGrid->addWidget(&openDeckInNewTabCheckBox, 0, 0);
deckEditorGrid->addWidget(&visualDeckStorageInGameCheckBox, 1, 0);
deckEditorGrid->addWidget(&visualDeckStorageSelectionAnimationCheckBox, 2, 0);
deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionLabel, 3, 0);
deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionSelector, 3, 1);
+ deckEditorGrid->addWidget(&defaultDeckEditorTypeLabel, 4, 0);
+ deckEditorGrid->addWidget(&defaultDeckEditorTypeSelector, 4, 1);
deckEditorGroupBox = new QGroupBox;
deckEditorGroupBox->setLayout(deckEditorGrid);
@@ -774,6 +783,9 @@ void UserInterfaceSettingsPage::retranslateUi()
tr("ask to convert to .cod"));
visualDeckStoragePromptForConversionSelector.setItemText(visualDeckStoragePromptForConversionIndexAlways,
tr("always convert to .cod"));
+ defaultDeckEditorTypeLabel.setText(tr("Default deck editor type"));
+ defaultDeckEditorTypeSelector.setItemText(TabSupervisor::ClassicDeckEditor, tr("Classic Deck Editor"));
+ defaultDeckEditorTypeSelector.setItemText(TabSupervisor::VisualDeckEditor, tr("Visual Deck Editor"));
replayGroupBox->setTitle(tr("Replay settings"));
rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:"));
rewindBufferingMsBox.setSuffix(" ms");
diff --git a/cockatrice/src/dialogs/dlg_settings.h b/cockatrice/src/dialogs/dlg_settings.h
index 6c9b8b062..3975f8519 100644
--- a/cockatrice/src/dialogs/dlg_settings.h
+++ b/cockatrice/src/dialogs/dlg_settings.h
@@ -155,6 +155,8 @@ private:
QComboBox visualDeckStoragePromptForConversionSelector;
QCheckBox visualDeckStorageInGameCheckBox;
QCheckBox visualDeckStorageSelectionAnimationCheckBox;
+ QLabel defaultDeckEditorTypeLabel;
+ QComboBox defaultDeckEditorTypeSelector;
QLabel rewindBufferingMsLabel;
QSpinBox rewindBufferingMsBox;
QGroupBox *generalGroupBox;
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index ba25590f3..395354751 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -285,6 +285,7 @@ SettingsCache::SettingsCache()
visualDeckStorageInGame = settings->value("interface/visualdeckstorageingame", true).toBool();
visualDeckStorageSelectionAnimation =
settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
+ defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
visualDatabaseDisplayFilterToMostRecentSetsEnabled =
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
visualDatabaseDisplayFilterToMostRecentSetsAmount =
@@ -791,6 +792,12 @@ void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T va
emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
}
+void SettingsCache::setDefaultDeckEditorType(int value)
+{
+ defaultDeckEditorType = value;
+ settings->setValue("interface/defaultDeckEditorType", defaultDeckEditorType);
+}
+
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled)
{
visualDatabaseDisplayFilterToMostRecentSetsEnabled = _enabled;
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index 78993ce4a..c922bb9e1 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -153,6 +153,7 @@ private:
bool visualDeckStorageAlwaysConvert;
bool visualDeckStorageInGame;
bool visualDeckStorageSelectionAnimation;
+ int defaultDeckEditorType;
bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
int visualDatabaseDisplayFilterToMostRecentSetsAmount;
bool horizontalHand;
@@ -488,6 +489,10 @@ public:
{
return visualDeckStorageSelectionAnimation;
}
+ int getDefaultDeckEditorType() const
+ {
+ return defaultDeckEditorType;
+ }
bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
{
return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
@@ -839,6 +844,7 @@ public slots:
void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
+ void setDefaultDeckEditorType(int value);
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 93048d3cf..004bf1ab1 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -256,6 +256,9 @@ void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T /* value */)
void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setDefaultDeckEditorType(int /* value */)
+{
+}
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T /* _enabled */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index a2ca73fb1..4ad635949 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -260,6 +260,9 @@ void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T /* value */)
void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setDefaultDeckEditorType(int /* value */)
+{
+}
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T /* _enabled */)
{
}
From 700feb68afb566e1df8eb1bfc9aa433847d28282 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Fri, 2 May 2025 20:34:41 +0200
Subject: [PATCH 03/26] Don't require .svg for mana symbols. (#5897)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../ui/widgets/cards/additional_info/mana_symbol_widget.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
index e42e93444..b17b0ff47 100644
--- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
@@ -66,7 +66,7 @@ void ManaSymbolWidget::loadManaIcon()
QString filename = "theme:icons/mana/";
if (symbol == "W" || symbol == "U" || symbol == "B" || symbol == "R" || symbol == "G") {
- filename += symbol + ".svg";
+ filename += symbol;
}
manaIcon = QPixmap(filename);
From baa7e25e30428dade3a39f62c70864ed996b162f Mon Sep 17 00:00:00 2001
From: Sebastian Di Luzio
Date: Sat, 3 May 2025 00:10:09 +0200
Subject: [PATCH 04/26] feat: build and release docker images using github
actions and container registry (#5807)
* feat: build and release docker images using github cicd
* fix: attempt to publish to specific image name
* fix: typo in pipeline step
* typo
* typo
* limit to certain paths for PRs & naming
* ci: configure image title and url
* docker: include only necessary files and directories
this should make caching more powerful
* docker: reorder COPY with best guess of what changes least
* build(docker): remove seemingly unnecessary files
* fix: clean up docker metadata
remove annotations, it seems they're applied from the labels already, add description
* fix(ci): add back docker image annotations
* Update desktop-build.yml
* Update desktop-lint.yml
* Update desktop-build.yml
* Update docker-release.yml
* fix: remove run on master and add affected files to PR trigger
* metadata
* ci: run pipeline on main
this will ensure the container can always build and keep caches ready for release. push should only happen on tag triggers
It also removes some files from the PR trigger that should never break the build, and would just invalidate cache.
* Update docker-release.yml
---------
Co-authored-by: tooomm
---
.github/workflows/desktop-build.yml | 1 +
.github/workflows/desktop-lint.yml | 1 +
.github/workflows/docker-release.yml | 71 ++++++++++++++++++++++++++++
Dockerfile | 6 ++-
README.md | 1 -
5 files changed, 78 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/docker-release.yml
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 79bc1b815..4d406c1b6 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -9,6 +9,7 @@ on:
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
+ - '.github/workflows/docker-release.yml'
tags:
- '*'
pull_request:
diff --git a/.github/workflows/desktop-lint.yml b/.github/workflows/desktop-lint.yml
index 4ebfd9b79..aee6e81d5 100644
--- a/.github/workflows/desktop-lint.yml
+++ b/.github/workflows/desktop-lint.yml
@@ -7,6 +7,7 @@ on:
- 'webclient/**'
- '.github/workflows/web-*.yml'
- '.github/workflows/translations-*.yml'
+ - '.github/workflows/docker-release.yml'
jobs:
format:
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
new file mode 100644
index 000000000..439ea24cd
--- /dev/null
+++ b/.github/workflows/docker-release.yml
@@ -0,0 +1,71 @@
+name: Build Docker Container
+
+on:
+ push:
+ tags:
+ - '*Release*'
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ paths:
+ - '.github/workflows/docker-release.yml'
+ - 'CMakeLists.txt'
+ - 'Dockerfile'
+ - 'servatrice/**'
+ - 'common/**'
+ - 'cmake/**'
+ - '!**.md'
+
+jobs:
+ docker:
+ name: amd64 & arm64
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Docker metadata
+ id: metadata
+ uses: docker/metadata-action@v5
+ with:
+ images: |
+ ghcr.io/cockatrice/servatrice
+ labels: |
+ org.opencontainers.image.title=Servatrice
+ org.opencontainers.image.url=https://cockatrice.github.io/
+ org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
+ annotations: |
+ org.opencontainers.image.title=Servatrice
+ org.opencontainers.image.url=https://cockatrice.github.io/
+ org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login to GitHub Container Registry
+ if: github.ref_type == 'tag'
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ github.token }}
+
+ - name: Build and push Docker Image
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: ${{ github.ref_type == 'tag' }}
+ tags: ${{ steps.metadata.outputs.tags }}
+ labels: ${{ steps.metadata.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/Dockerfile b/Dockerfile
index 330c51b4a..2a0d10eba 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,7 +16,11 @@ RUN apt-get update && apt-get install -y\
qt6-tools-dev \
qt6-tools-dev-tools
-COPY . /home/servatrice/code/
+COPY ./CMakeLists.txt ./LICENSE ./README.md /home/servatrice/code/
+COPY ./cmake /home/servatrice/code/cmake
+COPY ./common /home/servatrice/code/common
+COPY ./servatrice /home/servatrice/code/servatrice
+
WORKDIR /home/servatrice/code
WORKDIR build
diff --git a/README.md b/README.md
index 0a8058bba..48cacff78 100644
--- a/README.md
+++ b/README.md
@@ -143,7 +143,6 @@ The following flags (with their non-default values) can be passed to `cmake`:
# Run
-
Cockatrice is the game client Oracle fetches card data Servatrice is the server
From 9ae6357c349d7d459b442b238d0cbb94a18a0934 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Sun, 4 May 2025 02:03:53 +0200
Subject: [PATCH 05/26] Properly manage hover-zoom child widget in
CardInfoPictureWidget destructor. (#5900)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../ui/widgets/cards/card_info_picture_widget.cpp | 12 ++++++++++++
.../ui/widgets/cards/card_info_picture_widget.h | 2 ++
2 files changed, 14 insertions(+)
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
index 4ee3de5eb..5e275f8e9 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.cpp
@@ -64,6 +64,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverT
});
}
+CardInfoPictureWidget::~CardInfoPictureWidget()
+{
+ enlargedPixmapWidget->hide();
+ enlargedPixmapWidget->deleteLater();
+}
+
/**
* @brief Sets the card to be displayed and updates the pixmap.
* @param card A shared pointer to the card information (CardInfoPtr).
@@ -341,6 +347,12 @@ void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
emit cardClicked();
}
+void CardInfoPictureWidget::hideEvent(QHideEvent *event)
+{
+ enlargedPixmapWidget->hide();
+ QWidget::hideEvent(event);
+}
+
QMenu *CardInfoPictureWidget::createRightClickMenu()
{
auto *cardMenu = new QMenu(this);
diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
index 10cc422aa..79de74526 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
+++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_widget.h
@@ -21,6 +21,7 @@ public:
explicit CardInfoPictureWidget(QWidget *parent = nullptr,
bool hoverToZoomEnabled = false,
bool raiseOnEnter = false);
+ ~CardInfoPictureWidget();
CardInfoPtr getInfo()
{
return info;
@@ -52,6 +53,7 @@ protected:
void moveEvent(QMoveEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
+ void hideEvent(QHideEvent *event) override;
void loadPixmap();
[[nodiscard]] const QPixmap &getResizedPixmap() const
{
From 2687a3401944e5215b6a19d4b39bb0189aa0f757 Mon Sep 17 00:00:00 2001
From: Bruno Alexandre Rosa <1791393+brunoalr@users.noreply.github.com>
Date: Sun, 4 May 2025 13:02:11 +0000
Subject: [PATCH 06/26] ci: temporarily remove run-vcpkg step (#5902)
There is an issue with run-vcpkg GHA not caching properly. This ends up wasting 20 minutes of redundant vcpkg depency compilation.
See https://github.com/lukka/run-vcpkg/issues/243
---
.github/workflows/desktop-build.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 4d406c1b6..bd7fd37e2 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -387,7 +387,9 @@ jobs:
tools: ${{matrix.qt_tools}}
modules: ${{matrix.qt_modules}}
- - name: Run vcpkg
+ # TODO: re-enable when https://github.com/lukka/run-vcpkg/issues/243 is fixed
+ - if: false
+ name: Run vcpkg (disabled)
uses: lukka/run-vcpkg@v11
with:
runVcpkgInstall: true
From 69107f79e39e8446a9f7a740e661cc05f9442541 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sun, 4 May 2025 17:09:11 -0700
Subject: [PATCH 07/26] Add setting to auto focus search bar when opening card
view window (#5906)
* add new setting
* implement thing
* Rename setting
* fix build failure
---
cockatrice/src/dialogs/dlg_settings.cpp | 10 ++++++++--
cockatrice/src/dialogs/dlg_settings.h | 1 +
cockatrice/src/game/zones/view_zone_widget.cpp | 5 +++++
cockatrice/src/settings/cache_settings.cpp | 7 +++++++
cockatrice/src/settings/cache_settings.h | 6 ++++++
dbconverter/src/mocks.cpp | 3 +++
tests/carddatabase/mocks.cpp | 3 +++
7 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp
index cda737951..63901325f 100644
--- a/cockatrice/src/dialogs/dlg_settings.cpp
+++ b/cockatrice/src/dialogs/dlg_settings.cpp
@@ -630,6 +630,10 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
connect(&closeEmptyCardViewCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setCloseEmptyCardView);
+ focusCardViewSearchBarCheckBox.setChecked(SettingsCache::instance().getFocusCardViewSearchBar());
+ connect(&focusCardViewSearchBarCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setFocusCardViewSearchBar);
+
annotateTokensCheckBox.setChecked(SettingsCache::instance().getAnnotateTokens());
connect(&annotateTokensCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setAnnotateTokens);
@@ -643,8 +647,9 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
generalGrid->addWidget(&clickPlaysAllSelectedCheckBox, 1, 0);
generalGrid->addWidget(&playToStackCheckBox, 2, 0);
generalGrid->addWidget(&closeEmptyCardViewCheckBox, 3, 0);
- generalGrid->addWidget(&annotateTokensCheckBox, 4, 0);
- generalGrid->addWidget(&useTearOffMenusCheckBox, 5, 0);
+ generalGrid->addWidget(&focusCardViewSearchBarCheckBox, 4, 0);
+ generalGrid->addWidget(&annotateTokensCheckBox, 5, 0);
+ generalGrid->addWidget(&useTearOffMenusCheckBox, 6, 0);
generalGroupBox = new QGroupBox;
generalGroupBox->setLayout(generalGrid);
@@ -763,6 +768,7 @@ void UserInterfaceSettingsPage::retranslateUi()
clickPlaysAllSelectedCheckBox.setText(tr("&Clicking plays all selected cards (instead of just the clicked card)"));
playToStackCheckBox.setText(tr("&Play all nonlands onto the stack (not the battlefield) by default"));
closeEmptyCardViewCheckBox.setText(tr("Close card view window when last card is removed"));
+ focusCardViewSearchBarCheckBox.setText(tr("Auto focus search bar when card view window is opened"));
annotateTokensCheckBox.setText(tr("Annotate card text on tokens"));
useTearOffMenusCheckBox.setText(tr("Use tear-off menus, allowing right click menus to persist on screen"));
notificationsGroupBox->setTitle(tr("Notifications settings"));
diff --git a/cockatrice/src/dialogs/dlg_settings.h b/cockatrice/src/dialogs/dlg_settings.h
index 3975f8519..54b2cbcd8 100644
--- a/cockatrice/src/dialogs/dlg_settings.h
+++ b/cockatrice/src/dialogs/dlg_settings.h
@@ -147,6 +147,7 @@ private:
QCheckBox clickPlaysAllSelectedCheckBox;
QCheckBox playToStackCheckBox;
QCheckBox closeEmptyCardViewCheckBox;
+ QCheckBox focusCardViewSearchBarCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox useTearOffMenusCheckBox;
QCheckBox tapAnimationCheckBox;
diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp
index 1721831ac..f0430f549 100644
--- a/cockatrice/src/game/zones/view_zone_widget.cpp
+++ b/cockatrice/src/game/zones/view_zone_widget.cpp
@@ -56,6 +56,11 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(&searchEdit); });
+ if (SettingsCache::instance().getFocusCardViewSearchBar()) {
+ this->setActive(true);
+ searchEdit.setFocus();
+ }
+
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
searchEditProxy->setWidget(&searchEdit);
searchEditProxy->setZValue(2000000007);
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index 395354751..6507780fe 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -251,6 +251,7 @@ SettingsCache::SettingsCache()
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
cardViewExpandedRowsMax = settings->value("interface/cardViewExpandedRowsMax", 20).toInt();
closeEmptyCardView = settings->value("interface/closeEmptyCardView", true).toBool();
+ focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
@@ -370,6 +371,12 @@ void SettingsCache::setCloseEmptyCardView(QT_STATE_CHANGED_T value)
settings->setValue("interface/closeEmptyCardView", closeEmptyCardView);
}
+void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T value)
+{
+ focusCardViewSearchBar = value;
+ settings->setValue("interface/focusCardViewSearchBar", focusCardViewSearchBar);
+}
+
void SettingsCache::setKnownMissingFeatures(const QString &_knownMissingFeatures)
{
knownMissingFeatures = _knownMissingFeatures;
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index c922bb9e1..bb4bed95f 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -184,6 +184,7 @@ private:
int cardViewInitialRowsMax;
int cardViewExpandedRowsMax;
bool closeEmptyCardView;
+ bool focusCardViewSearchBar;
int pixmapCacheSize;
int networkCacheSize;
int redirectCacheTtl;
@@ -699,6 +700,7 @@ public:
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
void setCardViewExpandedRowsMax(int value);
void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
+ void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
QString getClientID()
{
return clientID;
@@ -727,6 +729,10 @@ public:
{
return closeEmptyCardView;
}
+ bool getFocusCardViewSearchBar() const
+ {
+ return focusCardViewSearchBar;
+ }
ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 004bf1ab1..890294870 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -64,6 +64,9 @@ void SettingsCache::setCardViewExpandedRowsMax(int /* value */)
void SettingsCache::setCloseEmptyCardView(const QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T /* value */)
+{
+}
void SettingsCache::setKnownMissingFeatures(const QString & /* _knownMissingFeatures */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index 4ad635949..b34c28727 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -68,6 +68,9 @@ void SettingsCache::setCardViewExpandedRowsMax(int /* value */)
void SettingsCache::setCloseEmptyCardView(QT_STATE_CHANGED_T /* value */)
{
}
+void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T /* value */)
+{
+}
void SettingsCache::setKnownMissingFeatures(const QString & /* _knownMissingFeatures */)
{
}
From bd8306bd33d1b77844d47614c9daea7d3d1ec14a Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 06:38:46 -0700
Subject: [PATCH 08/26] Strip color escape codes in Debug Log window (#5915)
---
cockatrice/src/dialogs/dlg_view_log.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index dc569c92c..7b4e8c617 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -4,6 +4,7 @@
#include "../utility/logger.h"
#include
+#include
#include
DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
@@ -44,7 +45,12 @@ void DlgViewLog::loadInitialLogBuffer()
void DlgViewLog::logEntryAdded(QString message)
{
- logArea->appendPlainText(message);
+ static auto colorEscapeCodePattern = QRegularExpression("\033\\[\\d+m");
+
+ QString sanitizedMessage = message;
+ sanitizedMessage.replace(colorEscapeCodePattern, "");
+
+ logArea->appendPlainText(sanitizedMessage);
}
void DlgViewLog::closeEvent(QCloseEvent * /* event */)
From 4a54412d47e9b7811d2039ac63112c9011314dd2 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 06:46:29 -0700
Subject: [PATCH 09/26] Pass log messages by const ref (#5914)
* Pass log messages by const ref
* Rename method
---
cockatrice/src/dialogs/dlg_view_log.cpp | 6 +++---
cockatrice/src/dialogs/dlg_view_log.h | 2 +-
cockatrice/src/utility/logger.cpp | 4 ++--
cockatrice/src/utility/logger.h | 6 +++---
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index 7b4e8c617..35accf80f 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -28,7 +28,7 @@ DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
resize(800, 500);
loadInitialLogBuffer();
- connect(&Logger::getInstance(), &Logger::logEntryAdded, this, &DlgViewLog::logEntryAdded);
+ connect(&Logger::getInstance(), &Logger::logEntryAdded, this, &DlgViewLog::appendLogEntry);
}
void DlgViewLog::actCheckBoxChanged(bool abNewValue)
@@ -40,10 +40,10 @@ void DlgViewLog::loadInitialLogBuffer()
{
QList logBuffer = Logger::getInstance().getLogBuffer();
for (const QString &message : logBuffer)
- logEntryAdded(message);
+ appendLogEntry(message);
}
-void DlgViewLog::logEntryAdded(QString message)
+void DlgViewLog::appendLogEntry(const QString &message)
{
static auto colorEscapeCodePattern = QRegularExpression("\033\\[\\d+m");
diff --git a/cockatrice/src/dialogs/dlg_view_log.h b/cockatrice/src/dialogs/dlg_view_log.h
index 3845f0062..870c23fc5 100644
--- a/cockatrice/src/dialogs/dlg_view_log.h
+++ b/cockatrice/src/dialogs/dlg_view_log.h
@@ -22,7 +22,7 @@ private:
void loadInitialLogBuffer();
private slots:
- void logEntryAdded(QString message);
+ void appendLogEntry(const QString &message);
void actCheckBoxChanged(bool abNewValue);
};
diff --git a/cockatrice/src/utility/logger.cpp b/cockatrice/src/utility/logger.cpp
index 74ed90597..0184146ae 100644
--- a/cockatrice/src/utility/logger.cpp
+++ b/cockatrice/src/utility/logger.cpp
@@ -81,12 +81,12 @@ void Logger::closeLogfileSession()
fileHandle.close();
}
-void Logger::log(QtMsgType /* type */, const QMessageLogContext & /* ctx */, const QString message)
+void Logger::log(QtMsgType /* type */, const QMessageLogContext & /* ctx */, const QString &message)
{
QMetaObject::invokeMethod(this, "internalLog", Qt::QueuedConnection, Q_ARG(const QString &, message));
}
-void Logger::internalLog(QString message)
+void Logger::internalLog(const QString &message)
{
QMutexLocker locker(&mutex);
diff --git a/cockatrice/src/utility/logger.h b/cockatrice/src/utility/logger.h
index 246e9204a..b90644b36 100644
--- a/cockatrice/src/utility/logger.h
+++ b/cockatrice/src/utility/logger.h
@@ -28,7 +28,7 @@ public:
}
void logToFile(bool enabled);
- void log(QtMsgType type, const QMessageLogContext &ctx, QString message);
+ void log(QtMsgType type, const QMessageLogContext &ctx, const QString &message);
QString getClientVersion();
QString getClientOperatingSystem();
QString getSystemArchitecture();
@@ -57,10 +57,10 @@ protected:
void closeLogfileSession();
protected slots:
- void internalLog(QString message);
+ void internalLog(const QString &message);
signals:
- void logEntryAdded(QString message);
+ void logEntryAdded(const QString &message);
};
#endif
From 29d93fb9c1ad08dab9aeef135c1f581466ba2214 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 06:50:34 -0700
Subject: [PATCH 10/26] Delete CardDragItem when referenced CardItem is
destroyed (#5911)
---
cockatrice/src/game/board/abstract_card_drag_item.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cockatrice/src/game/board/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp
index 0c7acd917..a7234c3d4 100644
--- a/cockatrice/src/game/board/abstract_card_drag_item.cpp
+++ b/cockatrice/src/game/board/abstract_card_drag_item.cpp
@@ -39,6 +39,8 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
prepareGeometryChange();
update();
});
+
+ connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
}
AbstractCardDragItem::~AbstractCardDragItem()
From a07c1badd8e72a58add5a3cc683f20209f3dd25a Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Mon, 5 May 2025 08:45:22 -0700
Subject: [PATCH 11/26] Add "copy to clipboard" button to Debug Log window
(#5913)
---
cockatrice/src/dialogs/dlg_view_log.cpp | 25 +++++++++++++++++++++++--
cockatrice/src/dialogs/dlg_view_log.h | 2 ++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/cockatrice/src/dialogs/dlg_view_log.cpp b/cockatrice/src/dialogs/dlg_view_log.cpp
index 35accf80f..b60a9767b 100644
--- a/cockatrice/src/dialogs/dlg_view_log.cpp
+++ b/cockatrice/src/dialogs/dlg_view_log.cpp
@@ -3,24 +3,40 @@
#include "../settings/cache_settings.h"
#include "../utility/logger.h"
+#include
#include
+#include
#include
#include
DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
{
-
logArea = new QPlainTextEdit;
logArea->setReadOnly(true);
auto *mainLayout = new QVBoxLayout;
+ mainLayout->setSpacing(3);
+ mainLayout->setContentsMargins(20, 20, 20, 6);
+
mainLayout->addWidget(logArea);
+ auto *bottomLayout = new QHBoxLayout;
+
coClearLog = new QCheckBox;
coClearLog->setText(tr("Clear log when closing"));
coClearLog->setChecked(SettingsCache::instance().servers().getClearDebugLogStatus(false));
connect(coClearLog, &QCheckBox::toggled, this, &DlgViewLog::actCheckBoxChanged);
- mainLayout->addWidget(coClearLog);
+
+ copyToClipboardButton = new QPushButton;
+ copyToClipboardButton->setText(tr("Copy to clipboard"));
+ copyToClipboardButton->setAutoDefault(false);
+ connect(copyToClipboardButton, &QPushButton::clicked, this, &DlgViewLog::actCopyToClipboard);
+
+ bottomLayout->addWidget(coClearLog);
+ bottomLayout->addStretch();
+ bottomLayout->addWidget(copyToClipboardButton);
+
+ mainLayout->addLayout(bottomLayout);
setLayout(mainLayout);
@@ -36,6 +52,11 @@ void DlgViewLog::actCheckBoxChanged(bool abNewValue)
SettingsCache::instance().servers().setClearDebugLogStatus(abNewValue);
}
+void DlgViewLog::actCopyToClipboard()
+{
+ QApplication::clipboard()->setText(logArea->toPlainText());
+}
+
void DlgViewLog::loadInitialLogBuffer()
{
QList logBuffer = Logger::getInstance().getLogBuffer();
diff --git a/cockatrice/src/dialogs/dlg_view_log.h b/cockatrice/src/dialogs/dlg_view_log.h
index 870c23fc5..26d6ad5e1 100644
--- a/cockatrice/src/dialogs/dlg_view_log.h
+++ b/cockatrice/src/dialogs/dlg_view_log.h
@@ -19,11 +19,13 @@ protected:
private:
QPlainTextEdit *logArea;
QCheckBox *coClearLog;
+ QPushButton *copyToClipboardButton;
void loadInitialLogBuffer();
private slots:
void appendLogEntry(const QString &message);
void actCheckBoxChanged(bool abNewValue);
+ void actCopyToClipboard();
};
#endif
\ No newline at end of file
From 286a7494d3a79ba1ce0134452a3de453d3bc6dae Mon Sep 17 00:00:00 2001
From: Basile Clement
Date: Wed, 7 May 2025 03:18:08 +0200
Subject: [PATCH 12/26] client: Support arbitrary game zones (#5877)
* Remove `isView` flag from CardZone
This flag is used for two purposes:
1. It is used as a check for casting to a zone to a `ZoneViewZone`;
2. Non-view zones are added to the player's zones on construction
This patch removes the `isView` flag and instead:
1. We directly cast zones to `ZoneViewZone` using a dynamic (qobject)
cast and use the result of the cast instead of the `isView` flag to
detect if we are a view zone or not;
2. The player records its own zones when they are created, simplifying
control flow.
* Review
* client: Support arbitrary game zones
Currently, the client ignores cards in unknown zones, as there is an
implicit assumption that the set of zones known by the server and the
client are the same.
This patch makes it so that the client accept "custom zones" from the
server (zones outside the builtin deck, graveyard, exile, sideboard,
table, stack and hand zones) using the information from the
ServerInfo_CardZone. Moving cards from/into these zones happens
through a "View custom zone" action in the Game > Player menu and
properly appears in the chat.
Note that this patch intentionally does not introduce any support for
having the server actually create such zones. Instead, this patch aims
to improve backwards compatibility for when we do get to adding this
capability in the future, by making sure that current clients will be
able to interact with future new zones (even if suboptimally).
---
cockatrice/src/game/player/player.cpp | 75 +++++++++++++++++++-
cockatrice/src/game/player/player.h | 2 +-
cockatrice/src/game/zones/card_zone.cpp | 4 ++
cockatrice/src/game/zones/table_zone.cpp | 4 +-
cockatrice/src/game/zones/table_zone.h | 2 +-
cockatrice/src/server/message_log_widget.cpp | 7 +-
common/pb/serverinfo_zone.proto | 4 ++
7 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp
index 160d8d336..9fff6b3df 100644
--- a/cockatrice/src/game/player/player.cpp
+++ b/cockatrice/src/game/player/player.cpp
@@ -144,7 +144,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
PileZone *sb = addZone(new PileZone(this, "sb", false, false, playerArea));
sb->setVisible(false);
- table = addZone(new TableZone(this, this));
+ table = addZone(new TableZone(this, "table", this));
connect(table, &TableZone::sizeChanged, this, &Player::updateBoundingRect);
stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this));
@@ -400,6 +400,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
sbMenu->addAction(aViewSideboard);
sb->setMenu(sbMenu, aViewSideboard);
+ mCustomZones = playerMenu->addMenu(QString());
+ mCustomZones->menuAction()->setVisible(false);
+
aUntapAll = new QAction(this);
connect(aUntapAll, &QAction::triggered, this, &Player::actUntapAll);
@@ -455,6 +458,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
if (!local && !judge) {
countersMenu = nullptr;
sbMenu = nullptr;
+ mCustomZones = nullptr;
aCreateAnotherToken = nullptr;
createPredefinedTokenMenu = nullptr;
}
@@ -829,6 +833,11 @@ void Player::retranslateUi()
sbMenu->setTitle(tr("&Sideboard"));
libraryMenu->setTitle(tr("&Library"));
countersMenu->setTitle(tr("&Counters"));
+ mCustomZones->setTitle(tr("C&ustom Zones"));
+
+ for (auto aViewZone : mCustomZones->actions()) {
+ aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString()));
+ }
aUntapAll->setText(tr("&Untap all permanents"));
aRollDie->setText(tr("R&oll die..."));
@@ -2715,19 +2724,79 @@ void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*op
void Player::processPlayerInfo(const ServerInfo_Player &info)
{
+ static QSet builtinZones{/* PileZones */
+ "deck", "grave", "rfg", "sb",
+ /* TableZone */
+ "table",
+ /* StackZone */
+ "stack",
+ /* HandZone */
+ "hand"};
clearCounters();
clearArrows();
- QMapIterator zoneIt(zones);
+ QMutableMapIterator zoneIt(zones);
while (zoneIt.hasNext()) {
zoneIt.next().value()->clearContents();
+
+ if (!builtinZones.contains(zoneIt.key())) {
+ zoneIt.remove();
+ }
+ }
+
+ // Can be null if we are not the local player!
+ if (mCustomZones) {
+ mCustomZones->clear();
+ mCustomZones->menuAction()->setVisible(false);
}
const int zoneListSize = info.zone_list_size();
for (int i = 0; i < zoneListSize; ++i) {
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
- CardZone *zone = zones.value(QString::fromStdString(zoneInfo.name()), 0);
+
+ QString zoneName = QString::fromStdString(zoneInfo.name());
+ CardZone *zone = zones.value(zoneName, 0);
if (!zone) {
+ // Create a new CardZone if it doesn't exist
+
+ if (zoneInfo.with_coords()) {
+ // Visibility not currently supported for TableZone
+ zone = addZone(new TableZone(this, zoneName, this));
+ } else {
+ // Zones without coordinats are always treated as non-shufflable
+ // PileZones, although supporting alternate hand or stack zones
+ // might make sense in some scenarios.
+ bool contentsKnown;
+
+ switch (zoneInfo.type()) {
+ case ServerInfo_Zone::PrivateZone:
+ contentsKnown = local || judge || (game->getSpectator() && game->getSpectatorsSeeEverything());
+ break;
+
+ case ServerInfo_Zone::PublicZone:
+ contentsKnown = true;
+ break;
+
+ case ServerInfo_Zone::HiddenZone:
+ contentsKnown = false;
+ break;
+ }
+
+ zone = addZone(new PileZone(this, zoneName, /* isShufflable */ false, contentsKnown, this));
+ }
+
+ // Non-builtin zones are hidden by default and can't be interacted
+ // with, except through menus.
+ zone->setVisible(false);
+
+ if (mCustomZones) {
+ mCustomZones->menuAction()->setVisible(true);
+ QAction *aViewZone = mCustomZones->addAction(tr("View custom zone '%1'").arg(zoneName));
+ aViewZone->setData(zoneName);
+ connect(aViewZone, &QAction::triggered, this,
+ [zoneName, this]() { static_cast(scene())->toggleZoneView(this, zoneName, -1); });
+ }
+
continue;
}
diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h
index ea5278572..d802ef796 100644
--- a/cockatrice/src/game/player/player.h
+++ b/cockatrice/src/game/player/player.h
@@ -253,7 +253,7 @@ public:
private:
TabGame *game;
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mLendLibrary, *mRevealTopCard,
- *mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard;
+ *mRevealHand, *mRevealRandomHandCard, *mRevealRandomGraveyardCard, *mCustomZones;
TearOffMenu *moveGraveMenu, *moveRfgMenu, *graveMenu, *moveHandMenu, *handMenu, *libraryMenu, *topLibraryMenu,
*bottomLibraryMenu, *rfgMenu, *playerMenu;
QList playerLists;
diff --git a/cockatrice/src/game/zones/card_zone.cpp b/cockatrice/src/game/zones/card_zone.cpp
index 05b4c35b9..089ed0a2d 100644
--- a/cockatrice/src/game/zones/card_zone.cpp
+++ b/cockatrice/src/game/zones/card_zone.cpp
@@ -92,6 +92,10 @@ QString CardZone::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
default:
break;
}
+ else {
+ return (theirOwn ? tr("their custom zone '%1'", "nominative").arg(name)
+ : tr("%1's custom zone '%2'", "nominative").arg(ownerName).arg(name));
+ }
return QString();
}
diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp
index e214b2e09..cee782560 100644
--- a/cockatrice/src/game/zones/table_zone.cpp
+++ b/cockatrice/src/game/zones/table_zone.cpp
@@ -19,8 +19,8 @@ const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
const QColor TableZone::GRADIENT_COLOR = QColor(255, 255, 255, 150);
const QColor TableZone::GRADIENT_COLORLESS = QColor(255, 255, 255, 0);
-TableZone::TableZone(Player *_p, QGraphicsItem *parent)
- : SelectZone(_p, "table", true, false, true, parent), active(false)
+TableZone::TableZone(Player *_p, const QString &name, QGraphicsItem *parent)
+ : SelectZone(_p, name, true, false, true, parent), active(false)
{
connect(themeManager, &ThemeManager::themeChanged, this, &TableZone::updateBg);
connect(&SettingsCache::instance(), &SettingsCache::invertVerticalCoordinateChanged, this,
diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h
index f3fbdccb6..3d464e6f3 100644
--- a/cockatrice/src/game/zones/table_zone.h
+++ b/cockatrice/src/game/zones/table_zone.h
@@ -98,7 +98,7 @@ public:
@param _p the Player
@param parent defaults to null
*/
- explicit TableZone(Player *_p, QGraphicsItem *parent = nullptr);
+ explicit TableZone(Player *_p, const QString &name, QGraphicsItem *parent = nullptr);
/**
@return a QRectF of the TableZone bounding box.
diff --git a/cockatrice/src/server/message_log_widget.cpp b/cockatrice/src/server/message_log_widget.cpp
index 0d21be045..a61a7ba2c 100644
--- a/cockatrice/src/server/message_log_widget.cpp
+++ b/cockatrice/src/server/message_log_widget.cpp
@@ -86,6 +86,8 @@ QPair MessageLogWidget::getFromStr(CardZone *zone, QString car
fromStr = tr(" from sideboard");
} else if (zoneName == STACK_ZONE_NAME) {
fromStr = tr(" from the stack");
+ } else {
+ fromStr = tr(" from custom zone '%1'").arg(zoneName);
}
if (!cardNameContainsStartZone) {
@@ -321,13 +323,16 @@ void MessageLogWidget::logMoveCard(Player *player,
} else if (targetZoneName == STACK_ZONE_NAME) {
soundEngine->playSound("play_card");
finalStr = tr("%1 plays %2%3.");
+ } else {
+ finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
}
if (usesNewX) {
appendHtmlServerMessage(
finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second).arg(newX));
} else {
- appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second));
+ appendHtmlServerMessage(
+ finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(nameFrom.second).arg(targetZoneName));
}
}
diff --git a/common/pb/serverinfo_zone.proto b/common/pb/serverinfo_zone.proto
index 0efa2d9be..f0ad5d709 100644
--- a/common/pb/serverinfo_zone.proto
+++ b/common/pb/serverinfo_zone.proto
@@ -11,6 +11,10 @@ message ServerInfo_Zone {
// setting beingLookedAt to true.
// Cards in a zone with the type HiddenZone are referenced by their
// list index, whereas cards in any other zone are referenced by their ids.
+ //
+ // WARNING: Adding new zone types will break compatibility with older
+ // clients. Older clients will read new zone types as PrivateZone, which
+ // is likely *NOT* what you want.
PrivateZone = 0;
PublicZone = 1;
From 4c3cfc8c2d5d00ec95993e8cc10fc390d83673ac Mon Sep 17 00:00:00 2001
From: Bruno Alexandre Rosa <1791393+brunoalr@users.noreply.github.com>
Date: Wed, 7 May 2025 01:18:59 +0000
Subject: [PATCH 13/26] fix: fix qt5 builds on macos 15 (#5923)
Although this config is not built on CI, while trying to compile locally, the build failed due to warnings and -Werror.
Some qt functions were actually deprecated (but not removed) before version 6.0.0 and clang (righfully) complains about comparison between different types of enums.
---
cockatrice/src/server/remote/remote_client.cpp | 2 +-
cockatrice/src/settings/shortcut_treeview.cpp | 2 +-
cockatrice/src/utility/card_info_comparator.cpp | 12 ++++++------
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/cockatrice/src/server/remote/remote_client.cpp b/cockatrice/src/server/remote/remote_client.cpp
index a573765af..1d8579c14 100644
--- a/cockatrice/src/server/remote/remote_client.cpp
+++ b/cockatrice/src/server/remote/remote_client.cpp
@@ -43,7 +43,7 @@ RemoteClient::RemoteClient(QObject *parent)
connect(socket, &QTcpSocket::connected, this, &RemoteClient::slotConnected);
connect(socket, &QTcpSocket::readyRead, this, &RemoteClient::readData);
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
connect(socket, &QTcpSocket::errorOccurred, this, &RemoteClient::slotSocketError);
#else
connect(socket, qOverload(&QTcpSocket::error), this, &RemoteClient::slotSocketError);
diff --git a/cockatrice/src/settings/shortcut_treeview.cpp b/cockatrice/src/settings/shortcut_treeview.cpp
index 02bc08164..6b329b23d 100644
--- a/cockatrice/src/settings/shortcut_treeview.cpp
+++ b/cockatrice/src/settings/shortcut_treeview.cpp
@@ -150,7 +150,7 @@ void ShortcutTreeView::currentChanged(const QModelIndex ¤t, const QModelIn
*/
void ShortcutTreeView::updateSearchString(const QString &searchString)
{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#if QT_VERSION > QT_VERSION_CHECK(5, 14, 0)
const auto skipEmptyParts = Qt::SkipEmptyParts;
#else
const auto skipEmptyParts = QString::SkipEmptyParts;
diff --git a/cockatrice/src/utility/card_info_comparator.cpp b/cockatrice/src/utility/card_info_comparator.cpp
index 26d00420f..821cc8675 100644
--- a/cockatrice/src/utility/card_info_comparator.cpp
+++ b/cockatrice/src/utility/card_info_comparator.cpp
@@ -37,17 +37,17 @@ bool CardInfoComparator::compareVariants(const QVariant &a, const QVariant &b) c
// Perform type-specific comparison
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- switch (a.typeId()) {
+ switch (static_cast(a.typeId())) {
#else
- switch (a.type()) {
+ switch (static_cast(a.type())) {
#endif
- case QMetaType::Int:
+ case static_cast(QMetaType::Int):
return a.toInt() < b.toInt();
- case QMetaType::Double:
+ case static_cast(QMetaType::Double):
return a.toDouble() < b.toDouble();
- case QMetaType::QString:
+ case static_cast(QMetaType::QString):
return a.toString() < b.toString();
- case QMetaType::Bool:
+ case static_cast(QMetaType::Bool):
return a.toBool() < b.toBool();
default:
// Default to comparing as strings
From fb6af544e210b1ddd48ca4ec13a22dc3a792075d Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:20:38 +0200
Subject: [PATCH 14/26] Set Banner Card again when restoring index on deckList
data changes. (#5922)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Set Banner Card again when restoring index on deckList data changes.
* Lint.
---------
Co-authored-by: Lukas Brübach
---
.../ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index 9adf8e095..2fde0b305 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -294,6 +294,10 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
int restoredIndex = bannerCardComboBox->findText(currentText);
if (restoredIndex != -1) {
bannerCardComboBox->setCurrentIndex(restoredIndex);
+ if (deckModel->getDeckList()->getBannerCard().second !=
+ bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap()["uuid"].toString()) {
+ setBannerCard(restoredIndex);
+ }
} else {
// Add a placeholder "-" and set it as the current selection
int bannerIndex = bannerCardComboBox->findText(deckModel->getDeckList()->getBannerCard().first);
From f16ba6861b7eb461441dc0a0d41219649c5c88c6 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:22:37 +0200
Subject: [PATCH 15/26] Forward scroll event to scrollable parents if possible
in NoScrollFilter. (#5921)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Lukas Brübach
---
.../deck_preview/deck_preview_widget.h | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h
index a9df635e5..8b594a9db 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h
@@ -7,6 +7,8 @@
#include "../visual_deck_storage_widget.h"
#include "deck_preview_deck_tags_display_widget.h"
+#include
+#include
#include
#include
#include
@@ -74,7 +76,22 @@ protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
if (event->type() == QEvent::Wheel) {
- return true; // Blocks the event
+ if (auto *combo = qobject_cast(obj)) {
+ // If popup is not open, forward event to parent scroll area
+ if (!combo->view()->isVisible()) {
+ // Try to find a scrollable parent and manually send the event
+ QWidget *parent = combo->parentWidget();
+ while (parent) {
+ if (auto *scroll = qobject_cast(parent)) {
+ QApplication::sendEvent(scroll->viewport(), event);
+ return true; // Mark event as handled
+ }
+ parent = parent->parentWidget();
+ }
+ // If no scrollable parent found, just block
+ return true;
+ }
+ }
}
return QObject::eventFilter(obj, event);
}
From 46e146b34a211e6876095a5e965cf0f7e7b7714f Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:23:49 +0200
Subject: [PATCH 16/26] [VDS] Allow tags to toggle to a NOT state to hide
non-matching decks (#5920)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Allow excluding tags.
* Lint.
* My linter is broken, don't ask.
* Zzz.
---------
Co-authored-by: Lukas Brübach
---
.../deck_preview_tag_display_widget.cpp | 58 +++++++++++++------
.../deck_preview_tag_display_widget.h | 23 +++++---
.../visual_deck_storage_tag_filter_widget.cpp | 42 +++++++++-----
3 files changed, 82 insertions(+), 41 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
index 324cc7288..4cfd9447d 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp
@@ -6,7 +6,7 @@
#include
DeckPreviewTagDisplayWidget::DeckPreviewTagDisplayWidget(QWidget *parent, const QString &_tagName)
- : QWidget(parent), tagName(_tagName), isSelected(false)
+ : QWidget(parent), tagName(_tagName), state(TagState::NotSelected)
{
// Create layout
auto *layout = new QHBoxLayout(this);
@@ -48,36 +48,58 @@ QSize DeckPreviewTagDisplayWidget::sizeHint() const
void DeckPreviewTagDisplayWidget::mousePressEvent(QMouseEvent *event)
{
- if (event->button() == Qt::LeftButton) {
- setSelected(!isSelected);
- emit tagClicked();
+ switch (event->button()) {
+ case Qt::LeftButton:
+ setState(TagState::Selected);
+ break;
+ case Qt::RightButton:
+ setState(TagState::Excluded);
+ break;
+ case Qt::MiddleButton:
+ setState(TagState::NotSelected);
+ break;
+ default:
+ break;
}
- QWidget::mousePressEvent(event);
-}
-void DeckPreviewTagDisplayWidget::setSelected(bool selected)
-{
- isSelected = selected;
- update(); // Trigger a repaint
+ emit tagClicked();
+ QWidget::mousePressEvent(event);
}
void DeckPreviewTagDisplayWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
- // Set background color
- QColor backgroundColor = isSelected ? QColor(173, 216, 230) : Qt::white;
+ QColor backgroundColor;
+ QColor borderColor;
+ int borderWidth;
+
+ switch (state) {
+ case TagState::Selected:
+ backgroundColor = QColor(173, 216, 230); // Light blue
+ borderColor = Qt::blue;
+ borderWidth = 2;
+ break;
+ case TagState::Excluded:
+ backgroundColor = QColor(255, 182, 193); // Light red/pink
+ borderColor = Qt::red;
+ borderWidth = 2;
+ break;
+ case TagState::NotSelected:
+ default:
+ backgroundColor = Qt::white;
+ borderColor = Qt::gray;
+ borderWidth = 1;
+ break;
+ }
+
painter.setBrush(backgroundColor);
painter.setPen(Qt::NoPen);
-
- // Draw background
painter.drawRect(rect());
- // Draw border
- QColor borderColor = isSelected ? Qt::blue : Qt::gray;
- QPen borderPen(borderColor, isSelected ? 2 : 1);
+ QPen borderPen(borderColor, borderWidth);
painter.setPen(borderPen);
- painter.drawRect(rect().adjusted(0, 0, -1, -1)); // Adjust for pen width
+ painter.drawRect(rect().adjusted(0, 0, -1, -1));
// Calculate font size based on widget height
QFont font = painter.font();
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h
index 10cc39baf..ff649dd32 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h
@@ -6,6 +6,13 @@
#include
#include
+enum class TagState
+{
+ NotSelected,
+ Selected,
+ Excluded
+};
+
class DeckPreviewTagDisplayWidget : public QWidget
{
Q_OBJECT
@@ -22,16 +29,16 @@ public:
{
return tagName;
}
- bool getSelected() const
+ TagState getState() const
{
- return isSelected;
+ return state;
}
- /**
- * @brief Sets the selected state of the tag.
- * @param selected True if the tag is selected, false otherwise.
- */
- void setSelected(bool selected);
+ void setState(const TagState newState)
+ {
+ state = newState;
+ update();
+ };
signals:
/**
@@ -61,7 +68,7 @@ private:
QLabel *tagLabel; ///< Label for displaying the tag name.
QPushButton *closeButton; ///< Button to close/remove the tag.
QString tagName; ///< The name of the tag.
- bool isSelected; ///< Indicates whether the tag is selected.
+ TagState state; ///< Indicates whether the tag is unselected, selected, or excluded.
};
#endif // DECK_PREVIEW_TAG_DISPLAY_WIDGET_H
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
index 25cb5a1e5..47ed6ebee 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
@@ -33,32 +33,42 @@ void VisualDeckStorageTagFilterWidget::showEvent(QShowEvent *event)
void VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList &deckPreviews) const
{
- // Collect selected tags from DeckPreviewTagDisplayWidget
QStringList selectedTags;
+ QStringList excludedTags;
+
+ // Collect selected and excluded tags
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
- if (tagWidget->getSelected()) {
- selectedTags.append(tagWidget->getTagName());
+ switch (tagWidget->getState()) {
+ case TagState::Selected:
+ selectedTags.append(tagWidget->getTagName());
+ break;
+ case TagState::Excluded:
+ excludedTags.append(tagWidget->getTagName());
+ break;
+ default:
+ break;
}
}
- // If no tags are selected, set all decks as visible
- if (selectedTags.isEmpty()) {
+ // If no tags are selected or excluded, show all
+ if (selectedTags.isEmpty() && excludedTags.isEmpty()) {
for (DeckPreviewWidget *deckPreview : deckPreviews) {
deckPreview->filteredByTags = false;
}
return;
}
- // Filter DeckPreviewWidgets that contain all of the selected tags
- QList filteredDecks;
for (DeckPreviewWidget *deckPreview : deckPreviews) {
QStringList deckTags = deckPreview->deckLoader->getTags();
- // Check if all selectedTags are in deckTags
- bool allTagsPresent = std::all_of(selectedTags.begin(), selectedTags.end(),
+ bool hasAllSelected = std::all_of(selectedTags.begin(), selectedTags.end(),
[&deckTags](const QString &tag) { return deckTags.contains(tag); });
- deckPreview->filteredByTags = !allTagsPresent;
+ bool hasAnyExcluded = std::any_of(excludedTags.begin(), excludedTags.end(),
+ [&deckTags](const QString &tag) { return deckTags.contains(tag); });
+
+ // Filter out if any excluded tag is present or if any selected tag is missing
+ deckPreview->filteredByTags = !(hasAllSelected && !hasAnyExcluded);
}
}
@@ -72,13 +82,15 @@ void VisualDeckStorageTagFilterWidget::refreshTags()
void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QSet &tags)
{
- // Iterate through all DeckPreviewTagDisplayWidgets
+ auto *flowWidget = findChild();
+
for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) {
- // If the tag is not in the provided tags list, remove the widget
- if (!tags.contains(tagWidget->getTagName())) {
- auto *flowWidget = findChild();
+ const QString &tagName = tagWidget->getTagName();
+
+ // Keep the tag widget if it is either selected or excluded
+ if (!tags.contains(tagName) && tagWidget->getState() == TagState::NotSelected) {
flowWidget->removeWidget(tagWidget);
- tagWidget->deleteLater(); // Safely delete the widget
+ tagWidget->deleteLater();
}
}
}
From bddb54ef4cd3fa2e38862d9704663ad37bafb02d Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:24:24 +0200
Subject: [PATCH 17/26] [VDE] Deck analytics visibility (#5919)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add scrollArea, I guess.
* Set mana curve bar color to grey for visibility.
---------
Co-authored-by: Lukas Brübach
---
.../deck_analytics/deck_analytics_widget.cpp | 17 ++++++++++++++---
.../deck_analytics/deck_analytics_widget.h | 8 +++++++-
.../deck_analytics/mana_curve_widget.cpp | 2 +-
3 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
index 02a4bfb5a..2131700fd 100644
--- a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
@@ -6,14 +6,25 @@ DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListModel *_deckLi
mainLayout = new QVBoxLayout();
setLayout(mainLayout);
+ scrollArea = new QScrollArea(this);
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scrollArea->setWidgetResizable(true);
+ mainLayout->addWidget(scrollArea);
+
+ container = new QWidget(scrollArea);
+ containerLayout = new QVBoxLayout(container);
+ container->setLayout(containerLayout);
+ scrollArea->setWidget(container);
+
manaCurveWidget = new ManaCurveWidget(this, deckListModel);
- mainLayout->addWidget(manaCurveWidget);
+ containerLayout->addWidget(manaCurveWidget);
manaDevotionWidget = new ManaDevotionWidget(this, deckListModel);
- mainLayout->addWidget(manaDevotionWidget);
+ containerLayout->addWidget(manaDevotionWidget);
manaBaseWidget = new ManaBaseWidget(this, deckListModel);
- mainLayout->addWidget(manaBaseWidget);
+ containerLayout->addWidget(manaBaseWidget);
}
void DeckAnalyticsWidget::refreshDisplays(DeckListModel *_deckModel)
diff --git a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h
index 6e7a273cf..b379b435c 100644
--- a/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_analytics/deck_analytics_widget.h
@@ -8,9 +8,10 @@
#include "mana_devotion_widget.h"
#include
+#include
+#include
#include
#include
-#include
class DeckAnalyticsWidget : public QWidget
{
@@ -26,6 +27,11 @@ private:
DeckListModel *deckListModel;
QVBoxLayout *mainLayout;
+ QWidget *container;
+ QVBoxLayout *containerLayout;
+
+ QScrollArea *scrollArea;
+
ManaCurveWidget *manaCurveWidget;
ManaDevotionWidget *manaDevotionWidget;
ManaBaseWidget *manaBaseWidget;
diff --git a/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp b/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
index acf240e0e..1cef0d794 100644
--- a/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
@@ -91,7 +91,7 @@ void ManaCurveWidget::updateDisplay()
// Add new widgets to the layout in sorted order
for (const auto &entry : sortedManaCurve) {
BarWidget *barWidget =
- new BarWidget(QString::number(entry.first), entry.second, highestEntry, QColor(11, 11, 11), this);
+ new BarWidget(QString::number(entry.first), entry.second, highestEntry, QColor(122, 122, 122), this);
barLayout->addWidget(barWidget);
}
From 05914e38f0009d11ac73e73cfbd9466fcad5787b Mon Sep 17 00:00:00 2001
From: "transifex-integration[bot]"
<43880903+transifex-integration[bot]@users.noreply.github.com>
Date: Tue, 6 May 2025 21:26:27 -0400
Subject: [PATCH 18/26] Translate oracle/oracle_en@source.ts in pt_BR (#5918)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'pt_BR'.
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
---
oracle/translations/oracle_pt_BR.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/oracle/translations/oracle_pt_BR.ts b/oracle/translations/oracle_pt_BR.ts
index 59ea83ec1..0a3439bf5 100644
--- a/oracle/translations/oracle_pt_BR.ts
+++ b/oracle/translations/oracle_pt_BR.ts
@@ -63,7 +63,7 @@
Sets file (%1)Sets JSON file (%1)
-
+ Arquivo de expansões (%1)
From 34400c7f60567710940bcebf7b27ec523a7dfc35 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:28:03 +0200
Subject: [PATCH 19/26] [VDE] Sample Hand Improvements (#5917)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Actually call retranslateUi, add spinBox to change sample hand size, add card size slider.
* Lint.
* Fix include.
* Fix include again.
* Fix overloads.
* Update visual_deck_editor_sample_hand_widget.cpp
---------
Co-authored-by: Lukas Brübach
Co-authored-by: Zach H
---
.../visual_deck_editor_sample_hand_widget.cpp | 34 ++++++++++++++++---
.../visual_deck_editor_sample_hand_widget.h | 6 ++++
cockatrice/src/settings/cache_settings.cpp | 8 +++++
cockatrice/src/settings/cache_settings.h | 7 ++++
dbconverter/src/mocks.cpp | 3 ++
tests/carddatabase/mocks.cpp | 3 ++
6 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
index 7868627e2..8530a8233 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
@@ -2,6 +2,7 @@
#include "../../../../deck/deck_loader.h"
#include "../../../../game/cards/card_database_manager.h"
+#include "../../../../settings/cache_settings.h"
#include "../cards/card_info_picture_widget.h"
#include
@@ -12,23 +13,45 @@ VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *pare
layout = new QVBoxLayout(this);
setLayout(layout);
+ resetAndHandSizeContainerWidget = new QWidget(this);
+ resetAndHandSizeLayout = new QHBoxLayout(resetAndHandSizeContainerWidget);
+ resetAndHandSizeContainerWidget->setLayout(resetAndHandSizeLayout);
+
resetButton = new QPushButton(this);
connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay()));
- layout->addWidget(resetButton);
+ resetAndHandSizeLayout->addWidget(resetButton);
+
+ handSizeSpinBox = new QSpinBox(this);
+ handSizeSpinBox->setValue(SettingsCache::instance().getVisualDeckEditorSampleHandSize());
+ handSizeSpinBox->setMinimum(1);
+ connect(handSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckEditorSampleHandSize);
+ connect(handSizeSpinBox, QOverload::of(&QSpinBox::valueChanged), this,
+ &VisualDeckEditorSampleHandWidget::updateDisplay);
+ resetAndHandSizeLayout->addWidget(handSizeSpinBox);
+
+ layout->addWidget(resetAndHandSizeContainerWidget);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
layout->addWidget(flowWidget);
- for (CardInfoPtr card : getRandomCards(7)) {
+ cardSizeWidget = new CardSizeWidget(this, flowWidget);
+ layout->addWidget(cardSizeWidget);
+
+ for (CardInfoPtr card : getRandomCards(handSizeSpinBox->value())) {
auto displayWidget = new CardInfoPictureWidget(this);
displayWidget->setCard(card);
+ displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
flowWidget->addWidget(displayWidget);
}
+
+ retranslateUi();
}
void VisualDeckEditorSampleHandWidget::retranslateUi()
{
- resetButton->setText(tr("Reset"));
+ resetButton->setText(tr("Draw a new sample hand"));
+ handSizeSpinBox->setToolTip(tr("Sample hand size"));
}
void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
@@ -41,9 +64,12 @@ void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
void VisualDeckEditorSampleHandWidget::updateDisplay()
{
flowWidget->clearLayout();
- for (CardInfoPtr card : getRandomCards(7)) {
+ for (CardInfoPtr card : getRandomCards(handSizeSpinBox->value())) {
auto displayWidget = new CardInfoPictureWidget(this);
displayWidget->setCard(card);
+ displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value());
+ connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, displayWidget,
+ &CardInfoPictureWidget::setScaleFactor);
flowWidget->addWidget(displayWidget);
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
index 44dc04cab..ba09a978e 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h
@@ -1,10 +1,12 @@
#ifndef VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
#define VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
+#include "../../../../client/ui/widgets/cards/card_size_widget.h"
#include "../../../../deck/deck_list_model.h"
#include "../general/layout_containers/flow_widget.h"
#include
+#include
#include
class VisualDeckEditorSampleHandWidget : public QWidget
@@ -22,8 +24,12 @@ public slots:
private:
DeckListModel *deckListModel;
QVBoxLayout *layout;
+ QWidget *resetAndHandSizeContainerWidget;
+ QHBoxLayout *resetAndHandSizeLayout;
QPushButton *resetButton;
+ QSpinBox *handSizeSpinBox;
FlowWidget *flowWidget;
+ CardSizeWidget *cardSizeWidget;
};
#endif // VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp
index 6507780fe..ef369641b 100644
--- a/cockatrice/src/settings/cache_settings.cpp
+++ b/cockatrice/src/settings/cache_settings.cpp
@@ -291,6 +291,7 @@ SettingsCache::SettingsCache()
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", true).toBool();
visualDatabaseDisplayFilterToMostRecentSetsAmount =
settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
+ visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
horizontalHand = settings->value("hand/horizontal", true).toBool();
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
@@ -821,6 +822,13 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _am
emit visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(visualDatabaseDisplayFilterToMostRecentSetsAmount);
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int _amount)
+{
+ visualDeckEditorSampleHandSize = _amount;
+ settings->setValue("interface/visualdeckeditorsamplehandsize", visualDeckEditorSampleHandSize);
+ emit visualDeckEditorSampleHandSizeAmountChanged(visualDeckEditorSampleHandSize);
+}
+
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
{
horizontalHand = static_cast(_horizontalHand);
diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h
index bb4bed95f..94cb2ed6a 100644
--- a/cockatrice/src/settings/cache_settings.h
+++ b/cockatrice/src/settings/cache_settings.h
@@ -73,6 +73,7 @@ signals:
void visualDeckStorageSelectionAnimationChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
+ void visualDeckEditorSampleHandSizeAmountChanged(int amount);
void horizontalHandChanged();
void handJustificationChanged();
void invertVerticalCoordinateChanged();
@@ -156,6 +157,7 @@ private:
int defaultDeckEditorType;
bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
int visualDatabaseDisplayFilterToMostRecentSetsAmount;
+ int visualDeckEditorSampleHandSize;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@@ -502,6 +504,10 @@ public:
{
return visualDatabaseDisplayFilterToMostRecentSetsAmount;
}
+ int getVisualDeckEditorSampleHandSize() const
+ {
+ return visualDeckEditorSampleHandSize;
+ }
bool getHorizontalHand() const
{
return horizontalHand;
@@ -853,6 +859,7 @@ public slots:
void setDefaultDeckEditorType(int value);
void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
+ void setVisualDeckEditorSampleHandSize(int _amount);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp
index 890294870..032cdc95e 100644
--- a/dbconverter/src/mocks.cpp
+++ b/dbconverter/src/mocks.cpp
@@ -268,6 +268,9 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STA
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
{
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp
index b34c28727..db7dd9353 100644
--- a/tests/carddatabase/mocks.cpp
+++ b/tests/carddatabase/mocks.cpp
@@ -272,6 +272,9 @@ void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STA
void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int /* _amount */)
{
}
+void SettingsCache::setVisualDeckEditorSampleHandSize(int /* _amount */)
+{
+}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}
From 99d9ce10c3746392cafbc8ecabc6e3fb535f5d09 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Wed, 7 May 2025 03:28:50 +0200
Subject: [PATCH 20/26] [GDE, VDS & VDE] Tooltips and labels (#5916)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add correct inversion for isHidden() on bannerCardLabel.
* Add tooltips to VDS buttons.
* Add tooltip to GDE button.
* Add tooltips to visual deck editor buttons.
* Add tooltips to visual database display buttons.
* Lint.
---------
Co-authored-by: Lukas Brübach
---
.../deck_editor/deck_editor_deck_dock_widget.cpp | 3 ++-
.../visual_database_display_color_filter_widget.cpp | 2 ++
...sual_database_display_filter_save_load_widget.cpp | 1 +
...sual_database_display_main_type_filter_widget.cpp | 8 ++++++++
...visual_database_display_main_type_filter_widget.h | 1 +
.../visual_database_display_name_filter_widget.cpp | 1 +
...isual_database_display_sub_type_filter_widget.cpp | 8 ++++++++
.../visual_database_display_sub_type_filter_widget.h | 1 +
.../visual_database_display_widget.cpp | 12 ++++++++++++
.../visual_database_display_widget.h | 1 +
.../visual_deck_editor/visual_deck_editor_widget.cpp | 5 +++++
.../deck_preview_color_identity_filter_widget.cpp | 1 +
.../visual_deck_storage_widget.cpp | 3 +++
13 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index 2fde0b305..af717fa36 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -91,7 +91,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
bannerCardLabel = new QLabel();
bannerCardLabel->setObjectName("bannerCardLabel");
bannerCardLabel->setText(tr("Banner Card"));
- bannerCardLabel->setHidden(SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
+ bannerCardLabel->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
bannerCardComboBox = new QComboBox(this);
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
// Delay the update to avoid race conditions
@@ -567,6 +567,7 @@ void DeckEditorDeckDockWidget::retranslateUi()
setWindowTitle(tr("Deck"));
nameLabel->setText(tr("Deck &name:"));
+ quickSettingsWidget->setToolTip(tr("Banner Card/Tags Visibility Settings"));
showBannerCardCheckBox->setText(tr("Show banner card selection menu"));
showTagsWidgetCheckBox->setText(tr("Show tags selection menu"));
commentsLabel->setText(tr("&Comments:"));
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
index 681282fc4..e93253585 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
@@ -58,6 +58,8 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
toggleButton->setText(tr("Mode: Include/Exclude"));
break;
}
+
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
index 1a099501e..21ec205fd 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
@@ -39,6 +39,7 @@ VisualDatabaseDisplayFilterSaveLoadWidget::VisualDatabaseDisplayFilterSaveLoadWi
void VisualDatabaseDisplayFilterSaveLoadWidget::retranslateUi()
{
saveButton->setText(tr("Save Filter"));
+ saveButton->setToolTip(tr("Save all currently applied filters to a file"));
filenameInput->setPlaceholderText(tr("Enter filename..."));
}
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
index 688f8f4d2..8cf9c6605 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
@@ -47,6 +47,14 @@ VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWi
createMainTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize toggle button text
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayMainTypeFilterWidget::retranslateUi()
+{
+ spinBox->setToolTip(tr("Do not display card main-types with less than this amount of cards in the database"));
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplayMainTypeFilterWidget::createMainTypeButtons()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
index b13071825..07086bbe3 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplayMainTypeFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createMainTypeButtons();
void updateMainTypeButtonsVisibility();
int getMaxMainTypeCount() const;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
index 69e782b66..e0ededd50 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
@@ -45,6 +45,7 @@ void VisualDatabaseDisplayNameFilterWidget::retranslateUi()
{
searchBox->setPlaceholderText(tr("Filter by name..."));
loadFromDeckButton->setText(tr("Load from Deck"));
+ loadFromDeckButton->setToolTip(tr("Apply all card names in currently loaded deck as exact match name filters"));
}
void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
index 4b8fc21d8..c6ea811a9 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
@@ -51,6 +51,14 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
createSubTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize the toggle button text
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplaySubTypeFilterWidget::retranslateUi()
+{
+ spinBox->setToolTip(tr("Do not display card sub-types with less than this amount of cards in the database"));
+ toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
}
void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons()
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
index 72a0a25bb..64c9c19cd 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h
@@ -16,6 +16,7 @@ class VisualDatabaseDisplaySubTypeFilterWidget : public QWidget
Q_OBJECT
public:
explicit VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
+ void retranslateUi();
void createSubTypeButtons();
void updateSubTypeButtonsVisibility();
int getMaxSubTypeCount() const;
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
index 9d82463be..f394f508f 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.cpp
@@ -150,6 +150,18 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
connect(loadCardsTimer, &QTimer::timeout, this, [this]() { loadCurrentPage(); });
loadCardsTimer->start(5000);
+
+ retranslateUi();
+}
+
+void VisualDatabaseDisplayWidget::retranslateUi()
+{
+ clearFilterWidget->setToolTip(tr("Clear all filters"));
+
+ quickFilterSaveLoadWidget->setToolTip(tr("Save and load filters"));
+ quickFilterNameWidget->setToolTip(tr("Filter by exact card name"));
+ quickFilterSubTypeWidget->setToolTip(tr("Filter by card sub-type"));
+ quickFilterSetWidget->setToolTip(tr("Filter by set"));
}
void VisualDatabaseDisplayWidget::resizeEvent(QResizeEvent *event)
diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
index 6d75698dc..8f0cdba97 100644
--- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h
@@ -38,6 +38,7 @@ public:
AbstractTabDeckEditor *deckEditor,
CardDatabaseModel *database_model,
CardDatabaseDisplayModel *database_display_model);
+ void retranslateUi();
void adjustCardsPerPage();
void populateCards();
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
index 0914a472e..1ebf59e36 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
@@ -190,7 +190,12 @@ void VisualDeckEditorWidget::retranslateUi()
{
sortLabel->setText(tr("Click and drag to change the sort order within the groups"));
searchPushButton->setText(tr("Quick search and add card"));
+ searchPushButton->setToolTip(tr("Search for closest match in the database (with auto-suggestions) and add "
+ "preferred printing to the deck on pressing enter"));
+ sortCriteriaButton->setToolTip(tr("Configure how cards are sorted within their groups"));
displayTypeButton->setText(tr("Flat Layout"));
+ displayTypeButton->setToolTip(
+ tr("Change how cards are displayed within zones (i.e. overlapped or fully visible.)"));
}
void VisualDeckEditorWidget::updateZoneWidgets()
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
index b048b2372..ef59e90ff 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
@@ -47,6 +47,7 @@ void DeckPreviewColorIdentityFilterWidget::retranslateUi()
{
// Set the toggle button text based on the current mode
toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
+ toggleButton->setToolTip(tr("Color identity filter mode (AND/OR/NOT conjunctions of filters)"));
}
void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar color, bool active)
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
index 4e879bd65..5a27728a3 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
@@ -194,6 +194,9 @@ void VisualDeckStorageWidget::retranslateUi()
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
+
+ refreshButton->setToolTip(tr("Refresh loaded files"));
+ quickSettingsWidget->setToolTip(tr("Visual Deck Storage Settings"));
}
/**
From 5b9cb4fc8daad11a14af04f29442a14d75b6475b Mon Sep 17 00:00:00 2001
From: tooomm
Date: Wed, 7 May 2025 03:29:09 +0200
Subject: [PATCH 21/26] Small changes related to docker image build+upload
(#5907)
* ci label
* naming
* downloads
* run
* fix toc
---
.github/workflows/docker-release.yml | 6 +++---
README.md | 17 +++++++++--------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
index 439ea24cd..5a03b86c8 100644
--- a/.github/workflows/docker-release.yml
+++ b/.github/workflows/docker-release.yml
@@ -1,4 +1,4 @@
-name: Build Docker Container
+name: Build Docker Image
on:
push:
@@ -48,7 +48,7 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- - name: Set up Docker Buildx
+ - name: Set up Docker buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
@@ -59,7 +59,7 @@ jobs:
username: ${{ github.actor }}
password: ${{ github.token }}
- - name: Build and push Docker Image
+ - name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
diff --git a/README.md b/README.md
index 48cacff78..acc2e4110 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
Related|Community|Contribute|
- Build|
+ Build|Run
@@ -38,8 +38,8 @@ Latest stable release:
Latest beta version:
[](https://github.com/cockatrice/cockatrice/releases)  [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice&search=0) [](https://github.com/Cockatrice/Cockatrice/pulls?q=is%3Apr+is%3Aclosed)
-While incorporating the latest fixes and features, beta builds may not be stable and/or contain new bugs!
-Please report any findings when testing them!
+While incorporating the latest fixes and features, beta builds may not be stable or contain new bugs!
+Please report any findings and open new issues when testing them!
# Related Repositories
@@ -79,10 +79,11 @@ Cockatrice tries to use the [Google Developer Documentation Style Guide](https:/
Kudos to our amazing contributors ❤️
+
- Made with contrib.rocks.
+ Made with contrib.rocks
### Translations [](https://transifex.com/cockatrice/cockatrice/)
@@ -92,7 +93,7 @@ Cockatrice uses Transifex to manage translations. You can help us bring Coc
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about getting invovled, and join a group of hundreds of others!
-# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
+# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/docker-release.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
Dependencies: *(for minimum versions search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
- [Qt](https://www.qt.io/developers/)
@@ -149,10 +150,10 @@ The following flags (with their non-default values) can be passed to `cmake`:
#### Docker
-You can run an instance of Servatrice (the Cockatrice server) using [Docker](https://www.docker.com/resources/what-container/) and our Dockerfile.
+You can build an image & deploy a Servatrice (Cockatrice server) container using [Docker](https://www.docker.com/resources/what-container/) and our Dockerfile yourself.
-For more information, have a look in our wiki section on [Setting up Servatrice](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
-There, you'll also find more hints on our **docker-compose** file which will configure and run both a MySQL server and Servatrice.
+For more details, look into our wiki section on [Setting up Servatrice](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
+You'll also find more hints on our **pre-build image** there, or the **docker-compose** file which will configure and run both a MySQL server and Servatrice.
# License [](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE)
From c4e42b94f97300d6d1a3fec2b37989bc7f237b2f Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Tue, 6 May 2025 18:31:01 -0700
Subject: [PATCH 22/26] Refactor CardSizeWidget: don't update setting directly
(#5903)
---
.../src/client/ui/widgets/cards/card_size_widget.cpp | 9 +--------
.../src/client/ui/widgets/cards/card_size_widget.h | 10 +++++++++-
.../ui/widgets/printing_selector/printing_selector.cpp | 2 ++
.../visual_deck_storage/visual_deck_storage_widget.cpp | 2 ++
4 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp
index be231e67a..7ce8e71c4 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/cards/card_size_widget.cpp
@@ -34,14 +34,7 @@ CardSizeWidget::CardSizeWidget(QWidget *parent, FlowWidget *_flowWidget, int def
// Debounce setup
debounceTimer.setSingleShot(true);
- connect(&debounceTimer, &QTimer::timeout, this, [this]() {
- // Check the type of the parent widget
- if (qobject_cast(parentWidget())) {
- SettingsCache::instance().setPrintingSelectorCardSize(pendingValue);
- } else if (qobject_cast(parentWidget())) {
- SettingsCache::instance().setVisualDeckStorageCardSize(pendingValue);
- }
- });
+ connect(&debounceTimer, &QTimer::timeout, this, [this] { emit cardSizeSettingUpdated(pendingValue); });
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardSizeWidget::updateCardSizeSetting);
}
diff --git a/cockatrice/src/client/ui/widgets/cards/card_size_widget.h b/cockatrice/src/client/ui/widgets/cards/card_size_widget.h
index d79359f23..1631fa562 100644
--- a/cockatrice/src/client/ui/widgets/cards/card_size_widget.h
+++ b/cockatrice/src/client/ui/widgets/cards/card_size_widget.h
@@ -17,9 +17,17 @@ public:
explicit CardSizeWidget(QWidget *parent, FlowWidget *flowWidget = nullptr, int defaultValue = 100);
[[nodiscard]] QSlider *getSlider() const;
-public slots:
+private slots:
void updateCardSizeSetting(int newValue);
+signals:
+ /**
+ * Emitted when the slider value changes, but on a debounce timer.
+ * Any parents that care about saving the value to settings should use this signal to indicate when to save the new
+ * value to settings.
+ */
+ void cardSizeSettingUpdated(int newValue);
+
private:
QWidget *parent;
FlowWidget *flowWidget;
diff --git a/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp b/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp
index ef3816049..b75ca213e 100644
--- a/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp
+++ b/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp
@@ -70,6 +70,8 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
cardSizeWidget =
new CardSizeWidget(displayOptionsWidget, flowWidget, SettingsCache::instance().getPrintingSelectorCardSize());
+ connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
+ &SettingsCache::setPrintingSelectorCardSize);
displayOptionsWidget->addSettingsWidget(sortToolBar);
displayOptionsWidget->addSettingsWidget(navigationCheckBox);
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
index 5a27728a3..34dd4c808 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
@@ -104,6 +104,8 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
// card size slider
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
+ connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageCardSize);
quickSettingsWidget = new SettingsButtonWidget(this);
quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
From 033c8b269d73ebdf6c6996c3078b34a9cd445219 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Tue, 6 May 2025 20:00:11 -0700
Subject: [PATCH 23/26] [VDS] Refactor: move quick settings to separate class
(#5905)
---
cockatrice/CMakeLists.txt | 1 +
...ual_deck_storage_folder_display_widget.cpp | 4 +-
...ual_deck_storage_quick_settings_widget.cpp | 155 ++++++++++++++++++
...isual_deck_storage_quick_settings_widget.h | 55 +++++++
.../visual_deck_storage_widget.cpp | 99 ++---------
.../visual_deck_storage_widget.h | 14 +-
6 files changed, 232 insertions(+), 96 deletions(-)
create mode 100644 cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
create mode 100644 cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 2b9a10113..50c721a6f 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -135,6 +135,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+ src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
index 319244f85..319393775 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
@@ -90,9 +90,9 @@ void VisualDeckStorageFolderDisplayWidget::createWidgetsForFiles()
&VisualDeckStorageWidget::deckLoadRequested);
connect(display, &DeckPreviewWidget::openDeckEditor, visualDeckStorageWidget,
&VisualDeckStorageWidget::openDeckEditor);
- connect(visualDeckStorageWidget->cardSizeWidget->getSlider(), &QSlider::valueChanged,
+ connect(visualDeckStorageWidget->settings(), &VisualDeckStorageQuickSettingsWidget::cardSizeChanged,
display->bannerCardDisplayWidget, &CardInfoPictureWidget::setScaleFactor);
- display->bannerCardDisplayWidget->setScaleFactor(visualDeckStorageWidget->cardSizeWidget->getSlider()->value());
+ display->bannerCardDisplayWidget->setScaleFactor(visualDeckStorageWidget->settings()->getCardSize());
allDecks.append(display);
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
new file mode 100644
index 000000000..3b9063a9b
--- /dev/null
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
@@ -0,0 +1,155 @@
+#include "visual_deck_storage_quick_settings_widget.h"
+
+#include "../../../../settings/cache_settings.h"
+#include "visual_deck_storage_widget.h"
+
+#include
+#include
+
+VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidget *parent)
+ : SettingsButtonWidget(parent)
+{
+ // show folders checkbox
+ showFoldersCheckBox = new QCheckBox(this);
+ showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
+ connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showFoldersChanged);
+ connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowFolders);
+
+ // show tag filter widget checkbox
+ showTagFilterCheckBox = new QCheckBox(this);
+ showTagFilterCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagFilter());
+ connect(showTagFilterCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged);
+ connect(showTagFilterCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowTagFilter);
+
+ // show tags on DeckPreviewWidget checkbox
+ showTagsOnDeckPreviewsCheckBox = new QCheckBox(this);
+ showTagsOnDeckPreviewsCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews());
+ connect(showTagsOnDeckPreviewsCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showTagsOnDeckPreviewsChanged);
+ connect(showTagsOnDeckPreviewsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowTagsOnDeckPreviews);
+
+ // show banner card selector checkbox
+ showBannerCardComboBoxCheckBox = new QCheckBox(this);
+ showBannerCardComboBoxCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox());
+ connect(showBannerCardComboBoxCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::showBannerCardComboBoxChanged);
+ connect(showBannerCardComboBoxCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageShowBannerCardComboBox);
+
+ // search folder names checkbox
+ searchFolderNamesCheckBox = new QCheckBox(this);
+ searchFolderNamesCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageSearchFolderNames());
+ connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::searchFolderNamesChanged);
+ connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageSearchFolderNames);
+
+ // draw unused color identities checkbox
+ drawUnusedColorIdentitiesCheckBox = new QCheckBox(this);
+ drawUnusedColorIdentitiesCheckBox->setChecked(
+ SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities());
+ connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &VisualDeckStorageQuickSettingsWidget::drawUnusedColorIdentitiesChanged);
+ connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
+
+ // color identity opacity selector
+ auto unusedColorIdentityOpacityWidget = new QWidget(this);
+
+ unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget);
+ unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget);
+
+ unusedColorIdentitiesOpacitySpinBox->setMinimum(0);
+ unusedColorIdentitiesOpacitySpinBox->setMaximum(100);
+ unusedColorIdentitiesOpacitySpinBox->setValue(
+ SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
+ connect(unusedColorIdentitiesOpacitySpinBox, QOverload::of(&QSpinBox::valueChanged), this,
+ &VisualDeckStorageQuickSettingsWidget::unusedColorIdentitiesOpacityChanged);
+ connect(unusedColorIdentitiesOpacitySpinBox, QOverload::of(&QSpinBox::valueChanged),
+ &SettingsCache::instance(), &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
+
+ unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox);
+
+ auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget);
+ unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0);
+ unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
+ unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
+
+ // card size slider
+ cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
+ connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
+ &VisualDeckStorageQuickSettingsWidget::cardSizeChanged);
+ connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
+ &SettingsCache::setVisualDeckStorageCardSize);
+
+ // putting everything together
+ this->addSettingsWidget(showFoldersCheckBox);
+ this->addSettingsWidget(showTagFilterCheckBox);
+ this->addSettingsWidget(showTagsOnDeckPreviewsCheckBox);
+ this->addSettingsWidget(showBannerCardComboBoxCheckBox);
+ this->addSettingsWidget(searchFolderNamesCheckBox);
+ this->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
+ this->addSettingsWidget(unusedColorIdentityOpacityWidget);
+ this->addSettingsWidget(cardSizeWidget);
+
+ connect(&SettingsCache::instance(), &SettingsCache::langChanged, this,
+ &VisualDeckStorageQuickSettingsWidget::retranslateUi);
+ retranslateUi();
+}
+
+void VisualDeckStorageQuickSettingsWidget::retranslateUi()
+{
+ showFoldersCheckBox->setText(tr("Show Folders"));
+ showTagFilterCheckBox->setText(tr("Show Tag Filter"));
+ showTagsOnDeckPreviewsCheckBox->setText(tr("Show Tags On Deck Previews"));
+ showBannerCardComboBoxCheckBox->setText(tr("Show Banner Card Selection Option"));
+ searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
+ drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
+ unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
+ unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowFolders() const
+{
+ return showFoldersCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getDrawUnusedColorIdentities() const
+{
+ return drawUnusedColorIdentitiesCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowBannerCardComboBox() const
+{
+ return showBannerCardComboBoxCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowTagFilter() const
+{
+ return showTagFilterCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getShowTagsOnDeckPreviews() const
+{
+ return showTagsOnDeckPreviewsCheckBox->isChecked();
+}
+
+bool VisualDeckStorageQuickSettingsWidget::getSearchFolderNames() const
+{
+ return searchFolderNamesCheckBox->isChecked();
+}
+
+int VisualDeckStorageQuickSettingsWidget::getUnusedColorIdentitiesOpacity() const
+{
+ return unusedColorIdentitiesOpacitySpinBox->value();
+}
+
+int VisualDeckStorageQuickSettingsWidget::getCardSize() const
+{
+ return cardSizeWidget->getSlider()->value();
+}
\ No newline at end of file
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h
new file mode 100644
index 000000000..da82b177b
--- /dev/null
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h
@@ -0,0 +1,55 @@
+#ifndef VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H
+#define VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H
+
+#include "../quick_settings/settings_button_widget.h"
+
+class CardSizeWidget;
+class QLabel;
+class QSpinBox;
+class QCheckBox;
+
+/**
+ * The VDS's quick settings menu.
+ * Manages the widgets in the quick settings menu dropdown, as well as syncing their values with SettingsCache.
+ * The current values of the settings are exposed through getters and signals.
+ */
+class VisualDeckStorageQuickSettingsWidget : public SettingsButtonWidget
+{
+ Q_OBJECT
+
+ QCheckBox *showFoldersCheckBox;
+ QCheckBox *drawUnusedColorIdentitiesCheckBox;
+ QCheckBox *showBannerCardComboBoxCheckBox;
+ QCheckBox *showTagFilterCheckBox;
+ QCheckBox *showTagsOnDeckPreviewsCheckBox;
+ QCheckBox *searchFolderNamesCheckBox;
+ QLabel *unusedColorIdentitiesOpacityLabel;
+ QSpinBox *unusedColorIdentitiesOpacitySpinBox;
+ CardSizeWidget *cardSizeWidget;
+
+public:
+ explicit VisualDeckStorageQuickSettingsWidget(QWidget *parent = nullptr);
+
+ void retranslateUi();
+
+ bool getShowFolders() const;
+ bool getDrawUnusedColorIdentities() const;
+ bool getShowBannerCardComboBox() const;
+ bool getShowTagFilter() const;
+ bool getShowTagsOnDeckPreviews() const;
+ bool getSearchFolderNames() const;
+ int getUnusedColorIdentitiesOpacity() const;
+ int getCardSize() const;
+
+signals:
+ void showFoldersChanged(bool enabled);
+ void drawUnusedColorIdentitiesChanged(bool enabled);
+ void showBannerCardComboBoxChanged(bool enabled);
+ void showTagFilterChanged(bool enabled);
+ void showTagsOnDeckPreviewsChanged(bool enabled);
+ void searchFolderNamesChanged(bool enabled);
+ void unusedColorIdentitiesOpacityChanged(int opacity);
+ void cardSizeChanged(int scale);
+};
+
+#endif // VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H
\ No newline at end of file
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
index 34dd4c808..e82f0c8d6 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
@@ -41,81 +41,13 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
refreshButton->setFixedSize(32, 32);
connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible);
- // quick settings menu
- showFoldersCheckBox = new QCheckBox(this);
- showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
- connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &VisualDeckStorageWidget::updateShowFolders);
- connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowFolders);
-
- tagFilterVisibilityCheckBox = new QCheckBox(this);
- tagFilterVisibilityCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagFilter());
- connect(tagFilterVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ quickSettingsWidget = new VisualDeckStorageQuickSettingsWidget(this);
+ connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showFoldersChanged, this,
+ &VisualDeckStorageWidget::updateShowFolders);
+ connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged, this,
&VisualDeckStorageWidget::updateTagsVisibility);
- connect(tagFilterVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowTagFilter);
-
- tagsOnWidgetsVisibilityCheckBox = new QCheckBox(this);
- tagsOnWidgetsVisibilityCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews());
- connect(tagsOnWidgetsVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowTagsOnDeckPreviews);
-
- drawUnusedColorIdentitiesCheckBox = new QCheckBox(this);
- drawUnusedColorIdentitiesCheckBox->setChecked(
- SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities());
- connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
-
- bannerCardComboBoxVisibilityCheckBox = new QCheckBox(this);
- bannerCardComboBoxVisibilityCheckBox->setChecked(
- SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox());
- connect(bannerCardComboBoxVisibilityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageShowBannerCardComboBox);
-
- searchFolderNamesCheckBox = new QCheckBox(this);
- searchFolderNamesCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageSearchFolderNames());
- connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::searchFolderNamesChanged, this,
&VisualDeckStorageWidget::updateSearchFilter);
- connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageSearchFolderNames);
-
- // color identity opacity selector
- auto unusedColorIdentityOpacityWidget = new QWidget(this);
-
- unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget);
- unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget);
-
- unusedColorIdentitiesOpacitySpinBox->setMinimum(0);
- unusedColorIdentitiesOpacitySpinBox->setMaximum(100);
- unusedColorIdentitiesOpacitySpinBox->setValue(
- SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
- connect(unusedColorIdentitiesOpacitySpinBox, QOverload::of(&QSpinBox::valueChanged),
- &SettingsCache::instance(), &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
-
- unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox);
-
- unusedColorIdentitiesOpacitySpinBox->setValue(
- SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
-
- auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget);
- unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0);
- unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
- unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
-
- // card size slider
- cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
- connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
- &SettingsCache::setVisualDeckStorageCardSize);
-
- quickSettingsWidget = new SettingsButtonWidget(this);
- quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
- quickSettingsWidget->addSettingsWidget(tagFilterVisibilityCheckBox);
- quickSettingsWidget->addSettingsWidget(tagsOnWidgetsVisibilityCheckBox);
- quickSettingsWidget->addSettingsWidget(bannerCardComboBoxVisibilityCheckBox);
- quickSettingsWidget->addSettingsWidget(searchFolderNamesCheckBox);
- quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
- quickSettingsWidget->addSettingsWidget(unusedColorIdentityOpacityWidget);
- quickSettingsWidget->addSettingsWidget(cardSizeWidget);
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
searchAndSortLayout->addWidget(sortWidget);
@@ -188,19 +120,18 @@ void VisualDeckStorageWidget::retranslateUi()
{
databaseLoadIndicator->setText(tr("Loading database ..."));
- showFoldersCheckBox->setText(tr("Show Folders"));
- tagFilterVisibilityCheckBox->setText(tr("Show Tag Filter"));
- tagsOnWidgetsVisibilityCheckBox->setText(tr("Show Tags On Deck Previews"));
- bannerCardComboBoxVisibilityCheckBox->setText(tr("Show Banner Card Selection Option"));
- searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
- drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
- unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
- unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
-
refreshButton->setToolTip(tr("Refresh loaded files"));
quickSettingsWidget->setToolTip(tr("Visual Deck Storage Settings"));
}
+/**
+ * Gets a const pointer to the quick settings so that the values can be accessed.
+ */
+const VisualDeckStorageQuickSettingsWidget *VisualDeckStorageWidget::settings() const
+{
+ return quickSettingsWidget;
+}
+
/**
* Reapplies all sort and filter options by calling the appropriate update methods.
*/
@@ -215,7 +146,7 @@ void VisualDeckStorageWidget::reapplySortAndFilters()
void VisualDeckStorageWidget::createRootFolderWidget()
{
folderWidget = new VisualDeckStorageFolderDisplayWidget(this, this, SettingsCache::instance().getDeckPath(), false,
- showFoldersCheckBox->isChecked());
+ quickSettingsWidget->getShowFolders());
scrollArea->setWidget(folderWidget); // this automatically destroys the old folderWidget
scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width());
@@ -266,7 +197,7 @@ void VisualDeckStorageWidget::updateSearchFilter()
{
if (folderWidget) {
searchWidget->filterWidgets(folderWidget->findChildren(), searchWidget->getSearchText(),
- searchFolderNamesCheckBox->isChecked());
+ quickSettingsWidget->getSearchFolderNames());
folderWidget->updateVisibility();
}
}
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h
index b52086a4f..755243fdf 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_widget.h
@@ -8,6 +8,7 @@
#include "deck_preview/deck_preview_color_identity_filter_widget.h"
#include "deck_preview/deck_preview_widget.h"
#include "visual_deck_storage_folder_display_widget.h"
+#include "visual_deck_storage_quick_settings_widget.h"
#include "visual_deck_storage_search_widget.h"
#include "visual_deck_storage_sort_widget.h"
#include "visual_deck_storage_tag_filter_widget.h"
@@ -29,10 +30,11 @@ public:
void refreshIfPossible();
void retranslateUi();
- CardSizeWidget *cardSizeWidget;
VisualDeckStorageTagFilterWidget *tagFilterWidget;
bool deckPreviewSelectionAnimationEnabled;
+ const VisualDeckStorageQuickSettingsWidget *settings() const;
+
public slots:
void createRootFolderWidget(); // Refresh the display of cards based on the current sorting option
void updateShowFolders(bool enabled);
@@ -60,15 +62,7 @@ private:
VisualDeckStorageSearchWidget *searchWidget;
DeckPreviewColorIdentityFilterWidget *deckPreviewColorIdentityFilterWidget;
QToolButton *refreshButton;
- SettingsButtonWidget *quickSettingsWidget;
- QCheckBox *showFoldersCheckBox;
- QCheckBox *drawUnusedColorIdentitiesCheckBox;
- QCheckBox *bannerCardComboBoxVisibilityCheckBox;
- QCheckBox *tagFilterVisibilityCheckBox;
- QCheckBox *tagsOnWidgetsVisibilityCheckBox;
- QCheckBox *searchFolderNamesCheckBox;
- QLabel *unusedColorIdentitiesOpacityLabel;
- QSpinBox *unusedColorIdentitiesOpacitySpinBox;
+ VisualDeckStorageQuickSettingsWidget *quickSettingsWidget;
QScrollArea *scrollArea;
VisualDeckStorageFolderDisplayWidget *folderWidget;
From 9cf979d154949e811f70d591db37f2460a09fab9 Mon Sep 17 00:00:00 2001
From: BruebachL <44814898+BruebachL@users.noreply.github.com>
Date: Fri, 9 May 2025 03:32:00 +0200
Subject: [PATCH 24/26] [GDE/VDE] More granular modification signals. (#5927)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* More granular modification signals.
* Bruh.
---------
Co-authored-by: Lukas Brübach
---
.../client/tabs/abstract_tab_deck_editor.cpp | 5 +++++
.../client/tabs/abstract_tab_deck_editor.h | 1 +
.../tab_deck_editor_visual.cpp | 2 +-
.../deck_editor_deck_dock_widget.cpp | 21 ++++++++++++-------
.../deck_editor_deck_dock_widget.h | 4 ++++
5 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
index 1c599034b..eba0bfb0f 100644
--- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
+++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
@@ -50,6 +50,7 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
printingSelectorDockWidget = new DeckEditorPrintingSelectorDockWidget(this);
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckChanged, this, &AbstractTabDeckEditor::onDeckChanged);
+ connect(deckDockWidget, &DeckEditorDeckDockWidget::deckModified, this, &AbstractTabDeckEditor::onDeckModified);
connect(deckDockWidget, &DeckEditorDeckDockWidget::cardChanged, this, &AbstractTabDeckEditor::updateCard);
connect(this, &AbstractTabDeckEditor::decrementCard, deckDockWidget, &DeckEditorDeckDockWidget::actDecrementCard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
@@ -77,6 +78,10 @@ void AbstractTabDeckEditor::updateCard(CardInfoPtr _card)
}
void AbstractTabDeckEditor::onDeckChanged()
+{
+}
+
+void AbstractTabDeckEditor::onDeckModified()
{
setModified(!isBlankNewDeck());
deckMenu->setSaveStatus(!isBlankNewDeck());
diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h
index 796213d27..1642ac107 100644
--- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h
+++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h
@@ -70,6 +70,7 @@ public:
public slots:
virtual void onDeckChanged();
+ virtual void onDeckModified();
void updateCard(CardInfoPtr _card);
void actAddCard(CardInfoPtr info);
void actAddCardToSideboard(CardInfoPtr info);
diff --git a/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp b/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
index 224c4db15..68f1eee17 100644
--- a/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
+++ b/cockatrice/src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
@@ -80,7 +80,7 @@ void TabDeckEditorVisual::createCentralFrame()
void TabDeckEditorVisual::onDeckChanged()
{
- AbstractTabDeckEditor::onDeckChanged();
+ AbstractTabDeckEditor::onDeckModified();
tabContainer->visualDeckView->decklistDataChanged(QModelIndex(), QModelIndex());
tabContainer->deckAnalytics->refreshDisplays(deckDockWidget->deckModel);
tabContainer->sampleHandWidget->setDeckModel(deckDockWidget->deckModel);
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index af717fa36..3683666a2 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -228,19 +228,22 @@ void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*¤t*/, const
void DeckEditorDeckDockWidget::updateName(const QString &name)
{
deckModel->getDeckList()->setName(name);
- emit deckChanged();
+ emit nameChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateComments()
{
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
- emit deckChanged();
+ emit commentsChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateHash()
{
hashLabel->setText(deckModel->getDeckList()->getDeckHash());
- emit deckChanged();
+ emit hashChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
@@ -318,7 +321,7 @@ void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
QVariantMap itemData = bannerCardComboBox->itemData(bannerCardComboBox->currentIndex()).toMap();
deckModel->getDeckList()->setBannerCard(
QPair(itemData["name"].toString(), itemData["uuid"].toString()));
- emit deckChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
@@ -366,8 +369,12 @@ void DeckEditorDeckDockWidget::cleanDeck()
{
deckModel->cleanList();
nameEdit->setText(QString());
+ emit nameChanged();
commentsEdit->setText(QString());
+ emit commentsChanged();
hashLabel->setText(QString());
+ emit hashChanged();
+ emit deckModified();
emit deckChanged();
updateBannerCardComboBox();
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
@@ -426,7 +433,7 @@ void DeckEditorDeckDockWidget::actSwapCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
update();
@@ -521,7 +528,7 @@ void DeckEditorDeckDockWidget::actRemoveCard()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
- emit deckChanged();
+ emit deckModified();
}
}
@@ -539,7 +546,7 @@ void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, int of
else
deckModel->setData(numberIndex, new_count, Qt::EditRole);
- emit deckChanged();
+ emit deckModified();
}
void DeckEditorDeckDockWidget::decklistCustomMenu(QPoint point)
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
index 0a9ebcd65..c81b4a6fa 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h
@@ -49,7 +49,11 @@ public slots:
void offsetCountAtIndex(const QModelIndex &idx, int offset);
signals:
+ void nameChanged();
+ void commentsChanged();
+ void hashChanged();
void deckChanged();
+ void deckModified();
void cardChanged(CardInfoPtr _card);
private:
From b423edf2b56635cdd048dafc665d80d8ee4a0389 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Sat, 10 May 2025 16:44:32 -0700
Subject: [PATCH 25/26] Fix segfault when multiple cards are dragged from view
zone (#5934)
---
cockatrice/src/game/board/abstract_card_drag_item.cpp | 7 +------
cockatrice/src/game/board/abstract_card_drag_item.h | 1 -
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/cockatrice/src/game/board/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp
index a7234c3d4..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))};
@@ -43,12 +44,6 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
}
-AbstractCardDragItem::~AbstractCardDragItem()
-{
- for (int i = 0; i < childDrags.size(); i++)
- delete childDrags[i];
-}
-
QPainterPath AbstractCardDragItem::shape() const
{
QPainterPath shape;
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);
From 48b6e1590c887ba487f303f5a756b10c378fcf3a Mon Sep 17 00:00:00 2001
From: ebbit1q
Date: Sun, 11 May 2025 11:48:58 +0200
Subject: [PATCH 26/26] increase cache size for ccache on linux ci (#5935)
---
.github/workflows/desktop-build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index bd7fd37e2..7fb403549 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -133,7 +133,7 @@ jobs:
CACHE: /tmp/${{matrix.distro}}${{matrix.version}}-cache # ${{runner.temp}} does not work?
# Cache size over the entire repo is 10Gi:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
- CCACHE_SIZE: 200M
+ CCACHE_SIZE: 500M
steps:
- name: Checkout