diff --git a/.ci/Arch/Dockerfile b/.ci/Arch/Dockerfile
index b08e568f3..f37315262 100644
--- a/.ci/Arch/Dockerfile
+++ b/.ci/Arch/Dockerfile
@@ -8,7 +8,6 @@ RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
gtest \
mariadb-libs \
ninja \
- openssl \
protobuf \
qt6-base \
qt6-declarative \
diff --git a/.ci/Debian12/Dockerfile b/.ci/Debian12/Dockerfile
index e3df94ab5..0fa227d6f 100644
--- a/.ci/Debian12/Dockerfile
+++ b/.ci/Debian12/Dockerfile
@@ -15,7 +15,6 @@ RUN apt-get update && \
libprotobuf-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
- libssl-dev \
ninja-build \
protobuf-compiler \
qt6-image-formats-plugins \
diff --git a/.ci/Debian13/Dockerfile b/.ci/Debian13/Dockerfile
index 60e490c98..13e8b35c7 100644
--- a/.ci/Debian13/Dockerfile
+++ b/.ci/Debian13/Dockerfile
@@ -16,7 +16,6 @@ RUN apt-get update && \
libprotobuf-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
- libssl-dev \
ninja-build \
protobuf-compiler \
qt6-image-formats-plugins \
diff --git a/.ci/Fedora43/Dockerfile b/.ci/Fedora43/Dockerfile
index 4005bbf67..68e894543 100644
--- a/.ci/Fedora43/Dockerfile
+++ b/.ci/Fedora43/Dockerfile
@@ -7,7 +7,6 @@ RUN dnf install -y \
git \
mariadb-devel \
ninja-build \
- openssl-devel \
protobuf-devel \
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
qt6-qtimageformats \
diff --git a/.ci/Fedora44/Dockerfile b/.ci/Fedora44/Dockerfile
index e0224cdc6..ffd7c1b9b 100644
--- a/.ci/Fedora44/Dockerfile
+++ b/.ci/Fedora44/Dockerfile
@@ -7,7 +7,6 @@ RUN dnf install -y \
git \
mariadb-devel \
ninja-build \
- openssl-devel \
protobuf-devel \
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
qt6-qtimageformats \
diff --git a/.ci/Servatrice_Debian12/Dockerfile b/.ci/Servatrice_Debian12/Dockerfile
index 321aa7c0f..21f6a036e 100644
--- a/.ci/Servatrice_Debian12/Dockerfile
+++ b/.ci/Servatrice_Debian12/Dockerfile
@@ -12,7 +12,6 @@ RUN apt-get update && \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6sql6-mysql \
- libssl-dev \
ninja-build \
protobuf-compiler \
qt6-tools-dev \
diff --git a/.ci/Ubuntu24.04/Dockerfile b/.ci/Ubuntu24.04/Dockerfile
index 10adc5e64..12320c276 100644
--- a/.ci/Ubuntu24.04/Dockerfile
+++ b/.ci/Ubuntu24.04/Dockerfile
@@ -15,7 +15,6 @@ RUN apt-get update && \
libprotobuf-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
- libssl-dev \
ninja-build \
protobuf-compiler \
qt6-image-formats-plugins \
diff --git a/.ci/Ubuntu26.04/Dockerfile b/.ci/Ubuntu26.04/Dockerfile
index 1b6cf825f..ce3d9cd6c 100644
--- a/.ci/Ubuntu26.04/Dockerfile
+++ b/.ci/Ubuntu26.04/Dockerfile
@@ -16,7 +16,6 @@ RUN apt-get update && \
libprotobuf-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
- libssl-dev \
ninja-build \
protobuf-compiler \
qt6-image-formats-plugins \
diff --git a/.ci/compile.sh b/.ci/compile.sh
index bd8c900c8..8a16d3243 100755
--- a/.ci/compile.sh
+++ b/.ci/compile.sh
@@ -149,9 +149,6 @@ if [[ $MAKE_TEST ]]; then
fi
if [[ $USE_CCACHE ]]; then
flags+=("-DUSE_CCACHE=1")
- # PCH-aware caching is required or ccache refuses to cache any TU that
- # consumes a precompiled header, silently recompiling everything on every run.
- ccache --set-config sloppiness=pch_defines,time_macros
if [[ $CCACHE_SIZE ]]; then
# note, this setting persists after running the script
ccache --max-size "$CCACHE_SIZE"
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 6ca634389..04037a74e 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -152,7 +152,7 @@ jobs:
env:
CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }} # directory for caching docker image and ccache
CCACHE_EVICTION_AGE: 7d
- CCACHE_SIZE: 600M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
+ CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CMAKE_GENERATOR: 'Ninja'
NAME: ${{ matrix.distro }}${{ matrix.version }}
@@ -176,12 +176,8 @@ jobs:
shell: bash
run: |
source .ci/docker.sh
- args=()
- [[ $GITHUB_REF == "refs/heads/master" ]] && args+=(--evict-ccache "$CCACHE_EVICTION_AGE")
- args+=(--ccache "$CCACHE_SIZE")
- args+=(--cmake-generator "$CMAKE_GENERATOR")
-
- RUN --server --debug --test "${args[@]}"
+ RUN --server --debug --test --ccache "$CCACHE_SIZE" \
+ --cmake-generator "$CMAKE_GENERATOR"
- name: "Build release package"
id: build
@@ -342,7 +338,7 @@ jobs:
timeout-minutes: 100
env:
CCACHE_DIR: ${{ github.workspace }}/.cache/
- CCACHE_SIZE: 600M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
+ CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
steps:
- name: "Checkout"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0da073464..bac46c2bc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,11 +5,11 @@
# This file sets all the variables shared between the projects
# like the installation path, compilation flags etc..
-# 3.16 required for Qt6 and target_precompile_headers()
-cmake_minimum_required(VERSION 3.16)
+# cmake 3.16 is required if using qt6
+cmake_minimum_required(VERSION 3.10)
# Use compiler cache (ccache)
-option(USE_CCACHE "Cache the build results with ccache" ON)
+option(USE_CCACHE "Cache the build results with ccache" OFF)
# Treat warnings as errors (Debug builds only)
option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON)
# Check for translation updates
@@ -39,24 +39,13 @@ else()
)
endif()
-# ccache does not support MSVC and must not auto-engage on Windows
-# (it is installed unintentionally on the Windows CI runner).
-# NOTE: this keys off the target OS, so a mingw/Ninja configuration on Windows
-# also opts out of ccache even though the GNUCXX branch below supports it.
-if(USE_CCACHE AND NOT WIN32)
+if(USE_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
# Support Unix Makefiles and Ninja
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
- # PCH-aware caching, matching .ci/compile.sh: without this ccache refuses
- # to cache any TU that consumes a precompiled header, so every PCH-backed
- # target recompiles from scratch on each build.
- execute_process(COMMAND ${CCACHE_PROGRAM} --set-config sloppiness=pch_defines,time_macros)
message(STATUS "Found CCache ${CCACHE_PROGRAM}")
endif()
-elseif(USE_CCACHE AND WIN32)
- # An explicit opt-in must not disappear silently on Windows.
- message(STATUS "ccache disabled: not supported for the MSVC toolchain on Windows")
endif()
if(WIN32 OR USE_VCPKG)
@@ -195,9 +184,6 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
endif()
endforeach()
-
- # Reduce compiler I/O by using pipes between stages instead of temp files
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
else()
# other: osx/llvm, bsd/llvm
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
@@ -206,9 +192,6 @@ else()
else()
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra")
endif()
-
- # Reduce compiler I/O by using pipes between stages instead of temp files
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
endif()
# GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning
@@ -256,6 +239,11 @@ if(WIN32)
find_package(OpenSSL REQUIRED)
if(OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIRS})
+ else()
+ message(
+ WARNING
+ "Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime."
+ )
endif()
endif()
diff --git a/Dockerfile b/Dockerfile
index 7d3deb5fb..382309d47 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,7 +14,6 @@ RUN apt-get update \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6sql6-mysql \
- libssl-dev \
qt6-websockets-dev \
protobuf-compiler \
qt6-tools-dev \
@@ -43,7 +42,6 @@ RUN apt-get update \
libprotobuf32t64 \
libqt6sql6-mysql \
libqt6websockets6 \
- libssl3 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
diff --git a/README.md b/README.md
index 5935bb540..f22df461f 100644
--- a/README.md
+++ b/README.md
@@ -149,15 +149,15 @@ You can then
The following flags (with their non-default values) can be passed to `cmake`:
-| Flag | Description |
-| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
-| `-DWITH_SERVER=1` | Build Servatrice server |
-| `-DWITH_CLIENT=0` | Don't build Cockatrice client |
-| `-DWITH_ORACLE=0` | Don't build Oracle card database tool |
-| `-DCMAKE_BUILD_TYPE=Debug` | Compile in debug mode
Enables extra logging output, debug symbols, and much more verbose compiler warnings |
-| `-DWARNING_AS_ERROR=0` | Don't treat compilation warnings as errors in debug mode |
-| `-DUPDATE_TRANSLATIONS=1` | Configure `make` to update the translation .ts files for new strings in the source code
**Note:** `make clean` will remove the .ts files |
-| `-DTEST=1` | Enable regression tests
**Note:** `make test` to run tests, *googletest* will be downloaded if not available |
+| Flag | Description |
+| --- | --- |
+| `-DWITH_SERVER=1` | Build Servatrice server |
+| `-DWITH_CLIENT=0` | Don't build Cockatrice client |
+| `-DWITH_ORACLE=0` | Don't build Oracle card database tool |
+| `-DCMAKE_BUILD_TYPE=Debug` | Compile in debug mode
Enables extra logging output, debug symbols, and much more verbose compiler warnings |
+| `-DWARNING_AS_ERROR=0` | Don't treat compilation warnings as errors in debug mode |
+| `-DUPDATE_TRANSLATIONS=1` | Configure `make` to update the translation .ts files for new strings in the source code
**Note:** `make clean` will remove the .ts files |
+| `-DTEST=1` | Enable regression tests
**Note:** `make test` to run tests, *googletest* will be downloaded if not available |
# Run
diff --git a/cmake/pch/qtcore_pch.h b/cmake/pch/qtcore_pch.h
deleted file mode 100644
index cc3dd12ee..000000000
--- a/cmake/pch/qtcore_pch.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/** @file qtcore_pch.h
- * @brief Precompiled header for all Qt targets (Qt Core only).
- *
- * Safe for every target that links Qt Core, including the headless
- * Servatrice binary. Keep this header free of any widget/gui types.
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
diff --git a/cmake/pch/qtwidgets_pch.h b/cmake/pch/qtwidgets_pch.h
deleted file mode 100644
index 2c63f450e..000000000
--- a/cmake/pch/qtwidgets_pch.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/** @file qtwidgets_pch.h
- * @brief Precompiled header for GUI targets (Cockatrice client, Oracle).
- *
- * Includes the Qt Core precompiled header plus the heavy Gui, Widgets and
- * Network layers that virtually every client translation unit re-parses.
- * Do not use on Servatrice (headless, QT_DONT_USE_QTGUI).
- */
-
-#include "qtcore_pch.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 63ccc4e9c..a171bb32e 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -166,7 +166,6 @@ set(cockatrice_SOURCES
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
src/interface/widgets/cards/art_crop_attribution.cpp
- src/interface/widgets/cards/card_art_utils.cpp
src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
src/interface/widgets/cards/card_group_display_widgets/flat_card_group_display_widget.cpp
src/interface/widgets/cards/card_group_display_widgets/overlapped_card_group_display_widget.cpp
@@ -215,7 +214,6 @@ set(cockatrice_SOURCES
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
src/interface/widgets/deck_editor/deck_state_manager.cpp
- src/interface/widgets/deck_editor/deck_zone_dialog.cpp
src/interface/widgets/deck_editor/printing_disabled_info_widget.cpp
src/interface/widgets/general/background_sources.cpp
src/interface/widgets/general/display/background_plate_widget.cpp
@@ -519,8 +517,6 @@ qt6_add_executable(
MANUAL_FINALIZATION
)
-target_precompile_headers(cockatrice PRIVATE "${CMAKE_SOURCE_DIR}/cmake/pch/qtwidgets_pch.h")
-
qt6_add_shaders(
cockatrice
"onboarding_shaders"
diff --git a/cockatrice/resources/help/search.md b/cockatrice/resources/help/search.md
index fd0a12507..0c8bdb450 100644
--- a/cockatrice/resources/help/search.md
+++ b/cockatrice/resources/help/search.md
@@ -52,7 +52,6 @@ In this list of examples below, each entry has an explanation and can be clicked
Edition:
[set:lea](#set:lea) (Cards that appear in Alpha, which has the set code LEA)
[e:lea OR e:leb](#e:lea OR e:leb) (Cards that appear in Alpha or Beta)
-[e<8ED](#e<8ED) (Cards that appear before 8th edition)
Negate:
[c:wu -c:m](#c:wu -c:m) (Any card that is white or blue, but not multicolored)
diff --git a/cockatrice/src/game/board/counter_state.cpp b/cockatrice/src/game/board/counter_state.cpp
index 0970e4272..6da18b662 100644
--- a/cockatrice/src/game/board/counter_state.cpp
+++ b/cockatrice/src/game/board/counter_state.cpp
@@ -13,12 +13,12 @@ CounterState *CounterState::fromProto(const ServerInfo_Counter &counter, QObject
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count(), parent);
}
-void CounterState::setValue(int newValue, bool skipDamageAnimation)
+void CounterState::setValue(int newValue)
{
if (newValue == value) {
return;
}
int old = value;
value = newValue;
- emit valueChanged(old, newValue, skipDamageAnimation);
+ emit valueChanged(old, newValue);
}
\ No newline at end of file
diff --git a/cockatrice/src/game/board/counter_state.h b/cockatrice/src/game/board/counter_state.h
index 4c7b34473..0f2f16b55 100644
--- a/cockatrice/src/game/board/counter_state.h
+++ b/cockatrice/src/game/board/counter_state.h
@@ -35,23 +35,10 @@ public:
return value;
}
- /**
- * @brief Set the counter value.
- * @param newValue The new value.
- * @param skipDamageAnimation When true, valueChanged is emitted with skipDamageAnimation=true, letting views
- * suppress damage-related feedback (e.g. battlefield shimmer, life counter flash) for values set during replay
- * rewinds.
- */
- void setValue(int newValue, bool skipDamageAnimation = false);
+ void setValue(int newValue);
signals:
- /**
- * @brief Emitted whenever the value changes.
- * @param oldValue The previous value.
- * @param newValue The new value.
- * @param skipDamageAnimation True when the change should not trigger damage/life-change feedback in views.
- */
- void valueChanged(int oldValue, int newValue, bool skipDamageAnimation);
+ void valueChanged(int oldValue, int newValue);
private:
int id;
diff --git a/cockatrice/src/game/game_event_handler.cpp b/cockatrice/src/game/game_event_handler.cpp
index f146cdbb4..bc68d4d7c 100644
--- a/cockatrice/src/game/game_event_handler.cpp
+++ b/cockatrice/src/game/game_event_handler.cpp
@@ -430,13 +430,12 @@ void GameEventHandler::eventJoin(const Event_Join &event, int /*eventPlayerId*/,
QString playerName = QString::fromStdString(playerInfo.user_info().name());
emit addPlayerToAutoCompleteList(playerName);
- PlayerManager *playerManager = game->getPlayerManager();
- if (playerManager->getPlayers().contains(playerId) || playerManager->getSpectators().contains(playerId)) {
+ if (game->getPlayerManager()->getPlayers().contains(playerId)) {
return;
}
if (playerInfo.spectator()) {
- playerManager->addSpectator(playerId, playerInfo);
+ game->getPlayerManager()->addSpectator(playerId, playerInfo);
emit logJoinSpectator(playerName);
emit spectatorJoined(playerInfo);
} else {
diff --git a/cockatrice/src/game/player/event_processing_options.h b/cockatrice/src/game/player/event_processing_options.h
index 06238d77e..4c7663789 100644
--- a/cockatrice/src/game/player/event_processing_options.h
+++ b/cockatrice/src/game/player/event_processing_options.h
@@ -13,8 +13,7 @@
enum EventProcessingOption
{
SKIP_REVEAL_WINDOW = 0x0001,
- SKIP_TAP_ANIMATION = 0x0002,
- SKIP_DAMAGE_ANIMATION = 0x0004
+ SKIP_TAP_ANIMATION = 0x0002
};
// Wrap it in a QFlags typedef
diff --git a/cockatrice/src/game/player/player_event_handler.cpp b/cockatrice/src/game/player/player_event_handler.cpp
index 277b8b1d4..bc48298f7 100644
--- a/cockatrice/src/game/player/player_event_handler.cpp
+++ b/cockatrice/src/game/player/player_event_handler.cpp
@@ -262,15 +262,14 @@ void PlayerEventHandler::eventCreateCounter(const Event_CreateCounter &event)
player->addCounter(event.counter_info());
}
-void PlayerEventHandler::eventSetCounter(const Event_SetCounter &event, EventProcessingOptions options)
+void PlayerEventHandler::eventSetCounter(const Event_SetCounter &event)
{
CounterState *ctr = player->getCounters().value(event.counter_id(), nullptr);
if (!ctr) {
return;
}
int oldValue = ctr->getValue();
- const bool skipDamageAnimation = options.testFlag(SKIP_DAMAGE_ANIMATION);
- ctr->setValue(event.value(), skipDamageAnimation);
+ ctr->setValue(event.value());
emit logSetCounter(player, ctr->getName(), event.value(), oldValue);
}
@@ -626,7 +625,7 @@ void PlayerEventHandler::processGameEvent(GameEvent::GameEventType type,
eventCreateCounter(event.GetExtension(Event_CreateCounter::ext));
break;
case GameEvent::SET_COUNTER:
- eventSetCounter(event.GetExtension(Event_SetCounter::ext), options);
+ eventSetCounter(event.GetExtension(Event_SetCounter::ext));
break;
case GameEvent::DEL_COUNTER:
eventDelCounter(event.GetExtension(Event_DelCounter::ext));
diff --git a/cockatrice/src/game/player/player_event_handler.h b/cockatrice/src/game/player/player_event_handler.h
index 300cacd08..48ad85e88 100644
--- a/cockatrice/src/game/player/player_event_handler.h
+++ b/cockatrice/src/game/player/player_event_handler.h
@@ -153,7 +153,7 @@ public:
void eventCreateCounter(const Event_CreateCounter &event);
/// Set a player-level counter value.
- void eventSetCounter(const Event_SetCounter &event, EventProcessingOptions options);
+ void eventSetCounter(const Event_SetCounter &event);
/// Delete a player-level counter.
void eventDelCounter(const Event_DelCounter &event);
diff --git a/cockatrice/src/game/player/player_logic.cpp b/cockatrice/src/game/player/player_logic.cpp
index 143df5c57..45ba09aac 100644
--- a/cockatrice/src/game/player/player_logic.cpp
+++ b/cockatrice/src/game/player/player_logic.cpp
@@ -175,15 +175,7 @@ void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info)
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
auto *card = new CardItem(this);
card->processCardInfo(cardInfo);
- // Zones without coordinates (hand, piles, stack) preserve the order
- // they arrive in on the server in the positions of their cards list.
- // The x coordinate of such cards is always 0, so inserting at it
- // would reverse the list on reconnect. Append instead.
- if (zoneInfo.with_coords()) {
- zone->addCard(card, false, cardInfo.x(), cardInfo.y());
- } else {
- zone->addCard(card, false, -1);
- }
+ zone->addCard(card, false, cardInfo.x(), cardInfo.y());
}
}
if (zoneInfo.has_always_reveal_top_card()) {
diff --git a/cockatrice/src/game/player/player_manager.cpp b/cockatrice/src/game/player/player_manager.cpp
index 8486efbeb..6772d3ff1 100644
--- a/cockatrice/src/game/player/player_manager.cpp
+++ b/cockatrice/src/game/player/player_manager.cpp
@@ -75,14 +75,6 @@ PlayerLogic *PlayerManager::getPlayer(int playerId) const
return player;
}
-void PlayerManager::clearSpectators()
-{
- const QList spectatorIds = spectators.keys();
- for (int spectatorId : spectatorIds) {
- removeSpectator(spectatorId);
- }
-}
-
void PlayerManager::onPlayerConceded(int playerId, bool conceded)
{
// Everything else cares about this
diff --git a/cockatrice/src/game/player/player_manager.h b/cockatrice/src/game/player/player_manager.h
index 504e65396..2f8b87af8 100644
--- a/cockatrice/src/game/player/player_manager.h
+++ b/cockatrice/src/game/player/player_manager.h
@@ -100,9 +100,6 @@ public:
emit spectatorRemoved(spectatorId, spectatorInfo);
}
- /** @brief Remove all spectators, emitting the removal signal for each. */
- void clearSpectators();
-
[[nodiscard]] AbstractGame *getGame() const
{
return game;
diff --git a/cockatrice/src/game_graphics/board/abstract_counter.cpp b/cockatrice/src/game_graphics/board/abstract_counter.cpp
index 4ba04804f..e63117e13 100644
--- a/cockatrice/src/game_graphics/board/abstract_counter.cpp
+++ b/cockatrice/src/game_graphics/board/abstract_counter.cpp
@@ -29,9 +29,9 @@ AbstractCounter::AbstractCounter(CounterState *state,
{
setAcceptHoverEvents(true);
- connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue, bool skipDamageAnimation) {
+ connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
value = newValue;
- onValueChanged(oldValue, newValue, skipDamageAnimation);
+ onValueChanged(oldValue, newValue);
update();
});
@@ -230,7 +230,7 @@ void AbstractCounterDialog::changeValue(int diff)
setTextValue(QString::number(curValue));
}
-void AbstractCounter::onValueChanged(int /*oldValue*/, int /*newValue*/, bool /*skipDamageAnimation*/)
+void AbstractCounter::onValueChanged(int /*oldValue*/, int /*newValue*/)
{
// Default: no feedback. Subclasses such as PlayerCounter override this to
// flash the counter on meaningful changes (life gain/loss).
diff --git a/cockatrice/src/game_graphics/board/abstract_counter.h b/cockatrice/src/game_graphics/board/abstract_counter.h
index 67b5b4074..9ddcc6d58 100644
--- a/cockatrice/src/game_graphics/board/abstract_counter.h
+++ b/cockatrice/src/game_graphics/board/abstract_counter.h
@@ -39,9 +39,8 @@ protected:
* @brief Hook for subclasses that need per-value-change feedback (e.g. life-total flash).
*
* Called whenever the counter's value changes, before the item repaints.
- * @param skipDamageAnimation True when damage-related feedback should be suppressed (replay rewinds).
*/
- virtual void onValueChanged(int oldValue, int newValue, bool skipDamageAnimation);
+ virtual void onValueChanged(int oldValue, int newValue);
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
diff --git a/cockatrice/src/game_graphics/board/card_item.cpp b/cockatrice/src/game_graphics/board/card_item.cpp
index c2dc455cc..c40c8c214 100644
--- a/cockatrice/src/game_graphics/board/card_item.cpp
+++ b/cockatrice/src/game_graphics/board/card_item.cpp
@@ -316,7 +316,7 @@ void CardItem::drawAttachArrow()
for (const auto &item : scene()->selectedItems()) {
CardItem *card = qgraphicsitem_cast(item);
- if (card == nullptr || card == this) {
+ if (card == nullptr) {
continue;
}
if (card->getZone() != state->getZone()) {
diff --git a/cockatrice/src/game_graphics/deckview/deck_view.cpp b/cockatrice/src/game_graphics/deckview/deck_view.cpp
index 1acd02a75..1278737a0 100644
--- a/cockatrice/src/game_graphics/deckview/deck_view.cpp
+++ b/cockatrice/src/game_graphics/deckview/deck_view.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item,
@@ -380,10 +381,12 @@ void DeckViewScene::rebuildTree()
addItem(container);
}
- // Cards in custom zones nested under a board are regular board cards in-game.
- // They are collected recursively (like every other consumer) and reported with
- // the top-level board zone as their origin, so that sideboard plans keep working.
- for (auto *currentCard : deck->getCardNodes({currentZone->getName()})) {
+ for (int j = 0; j < currentZone->size(); j++) {
+ auto *currentCard = dynamic_cast(currentZone->at(j));
+ if (!currentCard) {
+ continue;
+ }
+
for (int k = 0; k < currentCard->getNumber(); ++k) {
auto *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName());
container->addCard(newCard);
diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp
index 17af7618b..87af4c73c 100644
--- a/cockatrice/src/game_graphics/game_scene.cpp
+++ b/cockatrice/src/game_graphics/game_scene.cpp
@@ -44,16 +44,11 @@ GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent)
GameScene::~GameScene()
{
- // Sever all destroyed->removeAnimatedItem connections before the members below
- // are destroyed: the base QGraphicsScene destructor destroys the remaining items,
- // and their destroyed() signals must not reach slots that reference members that
- // no longer exist. The connection handle overload is used because the string-based
- // disconnect(nullptr, nullptr, this, nullptr) is invalid (the sender must never be
- // nullptr) and would otherwise fail to sever these pointer-to-member connections.
- for (auto it = animationItemConnections.constBegin(); it != animationItemConnections.constEnd(); ++it) {
- QObject::disconnect(*it);
- }
- animationItemConnections.clear();
+ // Sever all incoming connections (animated item destroy-tracking) before the
+ // members below are destroyed: the base QGraphicsScene destructor destroys the
+ // remaining items, and their destroyed() signals must not reach slots that
+ // reference members that no longer exist.
+ QObject::disconnect(nullptr, nullptr, this, nullptr);
delete animationTimer;
animationTimer = nullptr;
@@ -221,12 +216,7 @@ void GameScene::removePlayer(PlayerLogic *player)
clearArrowsForPlayer(player->getPlayerInfo()->getId());
- // Closing a view removes it from zoneViews synchronously, so iterate over a
- // copy: otherwise a player with several open views (e.g. library and hand)
- // only has the first one closed here and the remaining views are left
- // pointing at a player that is about to be deleted.
- const QList zoneViewCopy = zoneViews;
- for (ZoneViewWidget *zone : zoneViewCopy) {
+ for (ZoneViewWidget *zone : zoneViews) {
if (zone->getPlayer() == player) {
zone->close();
}
@@ -669,10 +659,7 @@ CardItem *GameScene::findTopmostCardInZone(const QList &items,
*/
void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed)
{
- // Closing a view removes it from zoneViews synchronously, so iterate over a
- // copy to make sure every already-open matching view is closed.
- const QList zoneViewCopy = zoneViews;
- for (auto *view : zoneViewCopy) {
+ for (auto &view : zoneViews) {
ZoneViewZone *temp = view->getZone();
if (temp->getLogic()->getName() == zoneName && temp->getLogic()->getPlayer() == player &&
qobject_cast(temp->getLogic())->getNumberCards() == numberCards) {
@@ -790,15 +777,8 @@ void GameScene::registerAnimationItem(IAnimatedItem *item)
if (!object) {
return;
}
- // Guard against duplicate connections using the connection map, not
- // animatedItems: the animation timer removes entries from animatedItems when an
- // animation completes, but the destroyed->removeAnimatedItem connection must
- // persist until the object is destroyed. Relying on animatedItems here would let
- // a re-registered item (e.g. a life counter that flashes repeatedly) accumulate
- // duplicate destroyed connections, the older ones of which would survive teardown.
- if (!animationItemConnections.contains(object)) {
- animationItemConnections.insert(object,
- connect(object, &QObject::destroyed, this, &GameScene::removeAnimatedItem));
+ if (!animatedItems.contains(object)) {
+ connect(object, &QObject::destroyed, this, &GameScene::removeAnimatedItem);
}
animatedItems.insert(object, item);
if (animationTimer && !animationTimer->isActive()) {
@@ -817,7 +797,6 @@ void GameScene::unregisterAnimationItem(IAnimatedItem *item)
void GameScene::removeAnimatedItem(QObject *item)
{
animatedItems.remove(item);
- animationItemConnections.remove(item);
if (animationTimer && animatedItems.isEmpty()) {
animationTimer->stop();
}
diff --git a/cockatrice/src/game_graphics/game_scene.h b/cockatrice/src/game_graphics/game_scene.h
index 859d7a6eb..c12696189 100644
--- a/cockatrice/src/game_graphics/game_scene.h
+++ b/cockatrice/src/game_graphics/game_scene.h
@@ -54,11 +54,9 @@ private:
QPointer hoveredCard; ///< Currently hovered card
QBasicTimer *animationTimer; ///< Timer for scene animations
QHash animatedItems; ///< Items currently animating
- QHash
- animationItemConnections; ///< destroyed->removeAnimatedItem handles per animated item
- int playerRotation; ///< Rotation offset for player layout
- bool rearranging = false; ///< Guard against re-entrant rearrange
- bool needsReArrange = false; ///< Pending rearrange requested during a pass
+ int playerRotation; ///< Rotation offset for player layout
+ bool rearranging = false; ///< Guard against re-entrant rearrange
+ bool needsReArrange = false; ///< Pending rearrange requested during a pass
/**
* @brief Updates which card is currently hovered based on scene coordinates.
diff --git a/cockatrice/src/game_graphics/player/menu/tally_menu.cpp b/cockatrice/src/game_graphics/player/menu/tally_menu.cpp
index 08cb6cac9..7eb3945b3 100644
--- a/cockatrice/src/game_graphics/player/menu/tally_menu.cpp
+++ b/cockatrice/src/game_graphics/player/menu/tally_menu.cpp
@@ -12,13 +12,11 @@ TallyMenu::TallyMenu()
aTallyNone = createTallyAction(TallyType::None);
aTallySubtypes = createTallyAction(TallyType::Subtypes);
aTallyTotalPower = createTallyAction(TallyType::TotalPower);
- aTallyTotalToughness = createTallyAction(TallyType::TotalToughness);
addAction(aTallyNone);
addSeparator();
addAction(aTallySubtypes);
addAction(aTallyTotalPower);
- addAction(aTallyTotalToughness);
retranslateUi();
}
@@ -56,5 +54,4 @@ void TallyMenu::retranslateUi()
aTallyNone->setText(tr("None"));
aTallySubtypes->setText(tr("Subtypes"));
aTallyTotalPower->setText(tr("Total Power"));
- aTallyTotalToughness->setText(tr("Total Toughness"));
}
diff --git a/cockatrice/src/game_graphics/player/menu/tally_menu.h b/cockatrice/src/game_graphics/player/menu/tally_menu.h
index 11802fd20..acd1daf67 100644
--- a/cockatrice/src/game_graphics/player/menu/tally_menu.h
+++ b/cockatrice/src/game_graphics/player/menu/tally_menu.h
@@ -24,7 +24,6 @@ private:
QAction *aTallyNone = nullptr;
QAction *aTallySubtypes = nullptr;
QAction *aTallyTotalPower = nullptr;
- QAction *aTallyTotalToughness = nullptr;
QAction *createTallyAction(TallyType tallyType);
};
diff --git a/cockatrice/src/game_graphics/player/player_graphics_item.cpp b/cockatrice/src/game_graphics/player/player_graphics_item.cpp
index 122ab83be..8bf2703e1 100644
--- a/cockatrice/src/game_graphics/player/player_graphics_item.cpp
+++ b/cockatrice/src/game_graphics/player/player_graphics_item.cpp
@@ -3,7 +3,6 @@
#include "../../game/player/player_actions.h"
#include "../../interface/card_picture_loader/card_picture_loader.h"
#include "../../interface/widgets/cards/art_crop_attribution.h"
-#include "../../interface/widgets/cards/card_art_utils.h"
#include "../../interface/widgets/playmat/playmat_utils.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../board/abstract_card_item.h"
@@ -252,8 +251,8 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
AbstractCounter *widget;
if (state->getName() == "life") {
widget = playerTarget->addCounter(state);
- connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue, bool skipDamageAnimation) {
- if (newValue < oldValue && !skipDamageAnimation) {
+ connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
+ if (newValue < oldValue) {
tableZoneGraphicsItem->triggerDamageShimmer();
}
});
@@ -443,7 +442,7 @@ void PlayerGraphicsItem::updatePlaymat()
hasPlaymat = true;
emit playmatChanged(true);
}
- playmatPixmap = CardArtUtils::rotateSidewaysLayoutArt(fullRes, card);
+ playmatPixmap = fullRes;
update();
}
diff --git a/cockatrice/src/game_graphics/player/player_list_widget.cpp b/cockatrice/src/game_graphics/player/player_list_widget.cpp
index 13a077af8..4268e1019 100644
--- a/cockatrice/src/game_graphics/player/player_list_widget.cpp
+++ b/cockatrice/src/game_graphics/player/player_list_widget.cpp
@@ -92,11 +92,6 @@ void PlayerListWidget::retranslateUi()
void PlayerListWidget::addPlayer(const ServerInfo_PlayerProperties &player)
{
- if (players.contains(player.player_id())) {
- updatePlayerProperties(player);
- return;
- }
-
QTreeWidgetItem *newPlayer = new PlayerListTWI;
players.insert(player.player_id(), newPlayer);
updatePlayerProperties(player);
@@ -181,17 +176,6 @@ void PlayerListWidget::removePlayer(int playerId)
delete takeTopLevelItem(indexOfTopLevelItem(player));
}
-void PlayerListWidget::clearSpectators()
-{
- const QList playerIds = players.keys();
- for (int playerId : playerIds) {
- QTreeWidgetItem *player = players.value(playerId, 0);
- if (player && !player->data(1, Qt::UserRole).toBool()) {
- removePlayer(playerId);
- }
- }
-}
-
void PlayerListWidget::setActivePlayer(int playerId)
{
QMapIterator i(players);
diff --git a/cockatrice/src/game_graphics/player/player_list_widget.h b/cockatrice/src/game_graphics/player/player_list_widget.h
index f2f0be5fd..a53cfa989 100644
--- a/cockatrice/src/game_graphics/player/player_list_widget.h
+++ b/cockatrice/src/game_graphics/player/player_list_widget.h
@@ -66,7 +66,6 @@ public slots:
void addPlayer(const ServerInfo_PlayerProperties &player);
void removePlayer(int playerId);
void updatePlayerProperties(const ServerInfo_PlayerProperties &prop, int playerId = -1);
- void clearSpectators();
};
#endif
diff --git a/cockatrice/src/game_graphics/player/player_target.cpp b/cockatrice/src/game_graphics/player/player_target.cpp
index d6c28370d..910ee9c17 100644
--- a/cockatrice/src/game_graphics/player/player_target.cpp
+++ b/cockatrice/src/game_graphics/player/player_target.cpp
@@ -69,7 +69,7 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
}
}
-void PlayerCounter::onValueChanged(int oldValue, int newValue, bool skipDamageAnimation)
+void PlayerCounter::onValueChanged(int oldValue, int newValue)
{
flashDelta = newValue - oldValue;
if (flashDelta == 0) {
@@ -81,11 +81,6 @@ void PlayerCounter::onValueChanged(int oldValue, int newValue, bool skipDamageAn
return;
}
- if (skipDamageAnimation) {
- flashAlpha = 0.0;
- return;
- }
-
flashAlpha = 1.0;
flashClock.start();
if (scene()) {
@@ -137,18 +132,8 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
QRectF translatedRect = painter->combinedTransform().mapRect(avatarBoundingRect);
QSize translatedSize = translatedRect.size().toSize();
QPixmap cachedPixmap;
- // The key must cover everything the generated pawn depends on: the rendered
- // size, the user level, and the pixmap being drawn. fullPixmap.cacheKey() is
- // 0 for every null pixmap, so the default-pawn branch additionally needs the
- // pawn's privlevel (lowercased, matching UserLevelPixmapGenerator) and colors
- // in the key — otherwise two players without a custom avatar (and the same
- // user level) would share one cached pawn.
const QString cacheKey = "avatar" + QString::number(translatedSize.width()) + "_" +
- QString::number(translatedSize.height()) + "_" + QString::number(info->user_level()) +
- "_" + QString::number(fullPixmap.cacheKey()) + "_" +
- QString::fromStdString(info->privlevel()).toLower() + "_" +
- QString::fromStdString(info->pawn_colors().left_side()) + "_" +
- QString::fromStdString(info->pawn_colors().right_side());
+ QString::number(info->user_level()) + "_" + QString::number(fullPixmap.cacheKey());
if (!QPixmapCache::find(cacheKey, &cachedPixmap)) {
cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height());
diff --git a/cockatrice/src/game_graphics/player/player_target.h b/cockatrice/src/game_graphics/player/player_target.h
index 1d06c6274..af0e9c8b7 100644
--- a/cockatrice/src/game_graphics/player/player_target.h
+++ b/cockatrice/src/game_graphics/player/player_target.h
@@ -21,7 +21,7 @@ class PlayerCounter : public AbstractCounter, public IAnimatedItem
{
Q_OBJECT
protected:
- void onValueChanged(int oldValue, int newValue, bool skipDamageAnimation) override;
+ void onValueChanged(int oldValue, int newValue) override;
private:
static constexpr qreal flashDurationMs = 450.0;
diff --git a/cockatrice/src/game_graphics/tally/stats_tally.cpp b/cockatrice/src/game_graphics/tally/stats_tally.cpp
index 7e05c3fb1..e7a6621fa 100644
--- a/cockatrice/src/game_graphics/tally/stats_tally.cpp
+++ b/cockatrice/src/game_graphics/tally/stats_tally.cpp
@@ -34,31 +34,3 @@ QList StatsTally::computeTotalPower(const QList &cards)
QString name = QCoreApplication::translate("StatsTally", "Total Power");
return {TallyRow{name, QString::number(total)}};
}
-
-static int sumToughness(const QList &cards)
-{
- int total = 0;
- for (auto card : cards) {
- QVariantList parsed = CardItem::parsePT(card->getPT());
- if (parsed.size() == 2) {
- int toughness = parsed.at(1).toInt(); // toInt will default to 0 if it's not an int
- total += qMax(toughness, 0);
- }
- }
- return total;
-}
-
-QList StatsTally::computeTotalToughness(const QList &cards)
-{
- // don't bother if none of the cards have pt
- bool hasPT =
- std::any_of(cards.cbegin(), cards.cend(), [](const CardItem *card) { return !card->getPT().isEmpty(); });
- if (!hasPT) {
- return {};
- }
-
- int total = sumToughness(cards);
-
- QString name = QCoreApplication::translate("StatsTally", "Total Toughness");
- return {TallyRow{name, QString::number(total)}};
-}
diff --git a/cockatrice/src/game_graphics/tally/stats_tally.h b/cockatrice/src/game_graphics/tally/stats_tally.h
index e499587eb..4c3d93b56 100644
--- a/cockatrice/src/game_graphics/tally/stats_tally.h
+++ b/cockatrice/src/game_graphics/tally/stats_tally.h
@@ -16,14 +16,6 @@ namespace StatsTally
*/
QList computeTotalPower(const QList &cards);
-/**
- * @brief Sums the toughness of all selected cards
- *
- * @param cards The list of selected card items to analyze.
- * @return A single row containing the total, or an empty list if none of the cards have pt
- */
-QList computeTotalToughness(const QList &cards);
-
} // namespace StatsTally
#endif // COCKATRICE_STATS_TALLY_H
diff --git a/cockatrice/src/game_graphics/tally/tally.cpp b/cockatrice/src/game_graphics/tally/tally.cpp
index 21806ee84..aa2cae024 100644
--- a/cockatrice/src/game_graphics/tally/tally.cpp
+++ b/cockatrice/src/game_graphics/tally/tally.cpp
@@ -21,8 +21,6 @@ QList Tally::compute(const QList &cards, const TallyType t
return SubtypeTally::countSubtypes(cards);
case TallyType::TotalPower:
return StatsTally::computeTotalPower(cards);
- case TallyType::TotalToughness:
- return StatsTally::computeTotalToughness(cards);
}
return {};
}
diff --git a/cockatrice/src/game_graphics/tally/tally.h b/cockatrice/src/game_graphics/tally/tally.h
index 84c54918f..97406cddb 100644
--- a/cockatrice/src/game_graphics/tally/tally.h
+++ b/cockatrice/src/game_graphics/tally/tally.h
@@ -21,8 +21,7 @@ enum class TallyType
None,
Subtypes,
TotalPower,
- TotalToughness,
- MaxValue = TotalToughness // sentinel value
+ MaxValue = TotalPower // sentinel value
};
namespace Tally
diff --git a/cockatrice/src/game_graphics/zones/hand_zone.cpp b/cockatrice/src/game_graphics/zones/hand_zone.cpp
index 1a8f7a910..b52a4955a 100644
--- a/cockatrice/src/game_graphics/zones/hand_zone.cpp
+++ b/cockatrice/src/game_graphics/zones/hand_zone.cpp
@@ -41,8 +41,7 @@ void HandZone::handleDropEvent(const QList &dragItems,
}
}
} else {
- bool sameZone = startZone == getLogic();
- x = calcDropIndexFromY(dropPoint.y(), !sameZone);
+ x = calcDropIndexFromY(dropPoint.y());
}
Command_MoveCard cmd;
diff --git a/cockatrice/src/game_graphics/zones/select_zone.cpp b/cockatrice/src/game_graphics/zones/select_zone.cpp
index 470c70fcf..c58c41b92 100644
--- a/cockatrice/src/game_graphics/zones/select_zone.cpp
+++ b/cockatrice/src/game_graphics/zones/select_zone.cpp
@@ -83,7 +83,7 @@ SelectZone::StackLayoutParams SelectZone::buildStackParams(qreal minOffset) cons
return {cardCount, boundingRect().height(), cardHeight, offset, minOffset};
}
-int SelectZone::calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal minOffset) const
+int SelectZone::calcDropIndexFromY(qreal dropY, qreal minOffset) const
{
const auto &cards = getLogic()->getCards();
if (cards.isEmpty()) {
@@ -94,8 +94,7 @@ int SelectZone::calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal min
if (effectiveOffset <= 0.0) {
return 0;
}
- int max = allowCountExpand ? params.cardCount : params.cardCount - 1;
- return qBound(0, qRound((dropY - start) / effectiveOffset), max);
+ return qBound(0, qRound((dropY - start) / effectiveOffset), params.cardCount - 1);
}
void SelectZone::restoreStaleEscapedCards()
diff --git a/cockatrice/src/game_graphics/zones/select_zone.h b/cockatrice/src/game_graphics/zones/select_zone.h
index b5d3ca37a..7408f29b6 100644
--- a/cockatrice/src/game_graphics/zones/select_zone.h
+++ b/cockatrice/src/game_graphics/zones/select_zone.h
@@ -104,12 +104,8 @@ protected:
/**
* @brief Computes the card index at a given y-coordinate within the zone's vertical layout.
* Returns 0 if the zone has no cards or the offset is zero.
- *
- * @param dropY The y-coordinate that the card was dropped at
- * @param allowCountExpand If false, clamps the index at the number of cards minus 1
- * @param minOffset Minimum offset to preserve
*/
- int calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal minOffset = 0.0) const;
+ int calcDropIndexFromY(qreal dropY, qreal minOffset = 0.0) const;
/**
* @brief Positions cards vertically with alternating left/right x-offsets.
diff --git a/cockatrice/src/game_graphics/zones/stack_zone.cpp b/cockatrice/src/game_graphics/zones/stack_zone.cpp
index ff62097c7..e9b14f13d 100644
--- a/cockatrice/src/game_graphics/zones/stack_zone.cpp
+++ b/cockatrice/src/game_graphics/zones/stack_zone.cpp
@@ -57,14 +57,18 @@ void StackZone::handleDropEvent(const QList &dragItems,
return;
}
- bool sameZone = startZone == getLogic();
- int index = calcDropIndexFromY(dropPoint.y(), !sameZone, MIN_CARD_VISIBLE);
- if (sameZone) {
+ const auto &cards = getLogic()->getCards();
+ int index;
+ if (startZone == getLogic()) {
+ // Reordering within the zone: use drop position
+ index = calcDropIndexFromY(dropPoint.y(), MIN_CARD_VISIBLE);
// Same-zone no-op: don't move a card onto itself
- const auto &cards = getLogic()->getCards();
if (!cards.isEmpty() && cards.at(index)->getId() == dragItems.at(0)->getId()) {
return;
}
+ } else {
+ // Coming from another zone: append at end (top of stack, rendered on top)
+ index = static_cast(cards.size());
}
Command_MoveCard cmd;
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
index 7daafb610..2f46e7941 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
@@ -138,8 +138,7 @@ void CardPictureLoader::getPixmap(QPixmap &pixmap, const ExactCard &card, QSize
QPixmap bigPixmap;
if (QPixmapCache::find(key, &bigPixmap)) {
if (bigPixmap.isNull()) {
- // Leave the pixmap null so callers fall back to a solid color
- // instead of showing the card back.
+ getCardBackLoadingFailedPixmap(pixmap, size);
QDateTime failedAtTime = getInstance().failedAt.value(key);
if (!failedAtTime.isValid() ||
failedAtTime.addSecs(RETRY_FAILED_CARDS_SECS) < QDateTime::currentDateTime()) {
diff --git a/cockatrice/src/interface/deck_loader/deck_loader.cpp b/cockatrice/src/interface/deck_loader/deck_loader.cpp
index f03339da8..39a0c1071 100644
--- a/cockatrice/src/interface/deck_loader/deck_loader.cpp
+++ b/cockatrice/src/interface/deck_loader/deck_loader.cpp
@@ -375,32 +375,15 @@ void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList &deckL
void DeckLoader::saveToStream_DeckZone(QTextStream &out,
const InnerDecklistNode *zoneNode,
bool addComments,
- bool addSetNameAndNumber,
- const QString &boardZoneName)
+ bool addSetNameAndNumber)
{
- // Nested sub-zones keep their owning board's identity: the top-level call
- // passes no board, so the zone's own name is used; recursive calls carry the
- // owning board down so the sideboard marker survives sub-zone nesting.
- const QString owningBoardZoneName = boardZoneName.isEmpty() ? zoneNode->getName() : boardZoneName;
-
// group cards by card type and count the subtotals
QMultiMap cardsByType;
QMap cardTotalByType;
int cardTotal = 0;
- QList subZones;
for (int j = 0; j < zoneNode->size(); j++) {
auto *card = dynamic_cast(zoneNode->at(j));
- if (!card) {
- // Cards collected in nested sub-zones are exported by recursion so
- // they don't end up invisible in the plain text output. They are
- // deferred until after this zone's own header and cards so they read
- // as part of this zone's block.
- if (auto *subZone = dynamic_cast(zoneNode->at(j))) {
- subZones.append(subZone);
- }
- continue;
- }
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(card->getName());
QString cardType = info ? info->getMainCardType() : "unknown";
@@ -428,30 +411,25 @@ void DeckLoader::saveToStream_DeckZone(QTextStream &out,
QList cards = cardsByType.values(cardType);
- saveToStream_DeckZoneCards(out, cards, addComments, addSetNameAndNumber, owningBoardZoneName);
+ saveToStream_DeckZoneCards(out, zoneNode, cards, addComments, addSetNameAndNumber);
if (addComments) {
out << "\n";
}
}
-
- // Nested sub-zones come last, after the parent's own header and cards.
- for (const auto *subZone : subZones) {
- saveToStream_DeckZone(out, subZone, addComments, addSetNameAndNumber, owningBoardZoneName);
- }
}
void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
+ const InnerDecklistNode *zoneNode,
QList cards,
bool addComments,
- bool addSetNameAndNumber,
- const QString &boardZoneName)
+ bool addSetNameAndNumber)
{
// QMultiMap sorts values in reverse order
for (int i = cards.size() - 1; i >= 0; --i) {
DecklistCardNode *card = cards[i];
- if (boardZoneName == DECK_ZONE_SIDE && addComments) {
+ if (zoneNode->getName() == DECK_ZONE_SIDE && addComments) {
out << "SB: ";
}
@@ -532,26 +510,9 @@ bool DeckLoader::convertToCockatriceFormat(LoadedDeck &deck)
void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node)
{
- if (!node || node->isEmpty()) {
- return;
- }
-
const int totalColumns = 2;
- // Dispatch children by type instead of trusting a whole-node height: a deck
- // node may hold direct cards and nested zones side by side (custom zones),
- // and an empty node would previously crash on at(0).
- QVector cards;
- QVector subZones;
- for (int i = 0; i < node->size(); i++) {
- if (auto *card = dynamic_cast(node->at(i))) {
- cards.append(card);
- } else if (auto *zone = dynamic_cast(node->at(i))) {
- subZones.append(zone);
- }
- }
-
- if (!cards.isEmpty()) {
+ if (node->height() == 1) {
QTextBlockFormat blockFormat;
QTextCharFormat charFormat;
charFormat.setFontPointSize(11);
@@ -562,9 +523,9 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
tableFormat.setCellPadding(0);
tableFormat.setCellSpacing(0);
tableFormat.setBorder(0);
- QTextTable *table = cursor->insertTable(cards.size() + 1, totalColumns, tableFormat);
- for (int i = 0; i < cards.size(); i++) {
- const AbstractDecklistCardNode *card = cards[i];
+ QTextTable *table = cursor->insertTable(node->size() + 1, totalColumns, tableFormat);
+ for (int i = 0; i < node->size(); i++) {
+ auto *card = dynamic_cast(node->at(i));
QTextCharFormat cellCharFormat;
cellCharFormat.setFontPointSize(9);
@@ -579,13 +540,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
cellCursor = cell.firstCursorPosition();
cellCursor.insertText(card->getName());
}
- }
-
- for (const InnerDecklistNode *subZone : subZones) {
- if (subZone->isEmpty()) {
- continue;
- }
-
+ } else if (node->height() == 2) {
QTextBlockFormat blockFormat;
QTextCharFormat charFormat;
charFormat.setFontPointSize(14);
@@ -604,8 +559,10 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
tableFormat.setColumnWidthConstraints(constraints);
QTextTable *table = cursor->insertTable(1, totalColumns, tableFormat);
- QTextCursor cellCursor = table->cellAt(0, 0).firstCursorPosition();
- printDeckListNode(&cellCursor, subZone);
+ for (int i = 0; i < node->size(); i++) {
+ QTextCursor cellCursor = table->cellAt(0, (i * totalColumns) / node->size()).lastCursorPosition();
+ printDeckListNode(&cellCursor, dynamic_cast(node->at(i)));
+ }
}
cursor->movePosition(QTextCursor::End);
diff --git a/cockatrice/src/interface/deck_loader/deck_loader.h b/cockatrice/src/interface/deck_loader/deck_loader.h
index b851c6895..ac23e1ee0 100644
--- a/cockatrice/src/interface/deck_loader/deck_loader.h
+++ b/cockatrice/src/interface/deck_loader/deck_loader.h
@@ -159,13 +159,12 @@ private:
static void saveToStream_DeckZone(QTextStream &out,
const InnerDecklistNode *zoneNode,
bool addComments = true,
- bool addSetNameAndNumber = true,
- const QString &boardZoneName = QString());
+ bool addSetNameAndNumber = true);
static void saveToStream_DeckZoneCards(QTextStream &out,
+ const InnerDecklistNode *zoneNode,
QList cards,
bool addComments = true,
- bool addSetNameAndNumber = true,
- const QString &boardZoneName = QString());
+ bool addSetNameAndNumber = true);
};
#endif
diff --git a/cockatrice/src/interface/pixel_map_generator.cpp b/cockatrice/src/interface/pixel_map_generator.cpp
index 674f3dd4c..d7d67c6bf 100644
--- a/cockatrice/src/interface/pixel_map_generator.cpp
+++ b/cockatrice/src/interface/pixel_map_generator.cpp
@@ -14,7 +14,7 @@
#define DEFAULT_COLOR_MODERATOR_LEFT "#ffffff";
#define DEFAULT_COLOR_MODERATOR_RIGHT "#000000";
#define DEFAULT_COLOR_ADMIN "#ff2701";
-#define DEFAULT_COLOR_DEVELOPER "#B8B8B8"
+#define DEFAULT_COLOR_DEVELOPER "#800020"
/**
* Clamps an svg render size so that rendering does not exceed a multiple of the requested size.
diff --git a/cockatrice/src/interface/widgets/cards/card_art_utils.cpp b/cockatrice/src/interface/widgets/cards/card_art_utils.cpp
deleted file mode 100644
index b26b73593..000000000
--- a/cockatrice/src/interface/widgets/cards/card_art_utils.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "card_art_utils.h"
-
-#include
-#include
-
-namespace CardArtUtils
-{
-QPixmap rotateSidewaysLayoutArt(const QPixmap &art, const ExactCard &card)
-{
- if (!card.getInfo().getUiAttributes().landscapeOrientation) {
- return art;
- }
-
- QTransform transform;
- transform.rotate(90);
- return art.transformed(transform, Qt::SmoothTransformation);
-}
-} // namespace CardArtUtils
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/cards/card_art_utils.h b/cockatrice/src/interface/widgets/cards/card_art_utils.h
deleted file mode 100644
index 5c331a12c..000000000
--- a/cockatrice/src/interface/widgets/cards/card_art_utils.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef CARD_ART_UTILS_H
-#define CARD_ART_UTILS_H
-
-#include
-
-class ExactCard;
-
-namespace CardArtUtils
-{
-/**
- * @brief Rotates a card's art upright when its layout shows sideways.
- *
- * Sideways-layout cards (planes, sieges/battles, split cards) store their
- * landscape artwork rotated 90° inside a portrait frame. Art-crop displays,
- * playmat art, and the card-info picture must show such art upright before
- * sampling or painting. Portrait cards are returned unchanged.
- *
- * @param art The card pixmap to orient.
- * @param card The card describing the art orientation.
- * @return @p art rotated 90° clockwise for sideways-layout cards, else @p art.
- */
-QPixmap rotateSidewaysLayoutArt(const QPixmap &art, const ExactCard &card);
-} // namespace CardArtUtils
-
-#endif // CARD_ART_UTILS_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp b/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
index bfbdd7e42..3f36e559c 100644
--- a/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
@@ -174,18 +174,16 @@ void CardGroupDisplayWidget::updateCardDisplays()
QModelIndex sourceIndex = proxy.mapToSource(proxyIndex);
// 4. persist the source index
- addCardWidgets(QPersistentModelIndex(sourceIndex));
- }
-}
+ QPersistentModelIndex persistent(sourceIndex);
-void CardGroupDisplayWidget::addCardWidgets(const QPersistentModelIndex &persistent)
-{
- // Get the card amount
- int cardAmount = persistent.sibling(persistent.row(), DeckListModelColumns::CARD_AMOUNT).data(Qt::EditRole).toInt();
+ // Get the card amount
+ int cardAmount =
+ sourceIndex.sibling(sourceIndex.row(), DeckListModelColumns::CARD_AMOUNT).data(Qt::EditRole).toInt();
- // Create multiple widgets for the card count
- for (int copy = 0; copy < cardAmount; ++copy) {
- addToLayout(constructWidgetForIndex(persistent));
+ // Create multiple widgets for the card count
+ for (int copy = 0; copy < cardAmount; ++copy) {
+ addToLayout(constructWidgetForIndex(persistent));
+ }
}
}
diff --git a/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.h b/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.h
index a3bf70981..2308ccf8d 100644
--- a/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.h
+++ b/cockatrice/src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.h
@@ -35,7 +35,6 @@ public:
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void refreshSelectionForIndex(const QPersistentModelIndex &persistent);
void clearAllDisplayWidgets();
- void addCardWidgets(const QPersistentModelIndex &persistent);
DeckListModel *deckListModel;
QItemSelectionModel *selectionModel;
diff --git a/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp b/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp
index de622bdc8..79ae087d7 100644
--- a/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp
+++ b/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp
@@ -5,7 +5,6 @@
#include "../../../interface/card_picture_loader/card_picture_loader.h"
#include "../../../interface/widgets/tabs/tab_supervisor.h"
#include "../../window_main.h"
-#include "card_art_utils.h"
#include
#include
@@ -194,7 +193,12 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
QPixmap transformedPixmap = resizedPixmap; // Default pixmap
if (SettingsCache::instance().cardsDisplay().getAutoRotateSidewaysLayoutCards()) {
- transformedPixmap = CardArtUtils::rotateSidewaysLayoutArt(resizedPixmap, exactCard);
+ if (exactCard.getInfo().getUiAttributes().landscapeOrientation) {
+ // Rotate pixmap 90 degrees to the left
+ QTransform transform;
+ transform.rotate(90);
+ transformedPixmap = resizedPixmap.transformed(transform, Qt::SmoothTransformation);
+ }
}
// Handle DPI scaling
diff --git a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp b/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp
index b00d9db1e..eaf3a67b0 100644
--- a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp
@@ -5,7 +5,6 @@
#include "libcockatrice/card/database/card_database_manager.h"
#include
-#include
#include
DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
@@ -52,6 +51,11 @@ DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
// User Interaction
// =====================================================================================================================
+void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, const ExactCard &card)
+{
+ emit cardClicked(event, card, zoneName);
+}
+
void DeckCardZoneDisplayWidget::onHover(const ExactCard &card)
{
emit cardHovered(card);
@@ -91,18 +95,12 @@ void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex
}
auto categoryName = index.sibling(index.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- // Cards in a custom zone belong to that zone, not the board zone, so that
- // increment/decrement/swap actions target the custom zone.
- const bool isCustomZone = index.data(DeckRoles::IsCustomZoneRole).toBool();
- const QString effectiveZoneName = isCustomZone ? categoryName : zoneName;
- const auto routeCardClick = [this, effectiveZoneName](QMouseEvent *event, const ExactCard &card) {
- emit cardClicked(event, card, effectiveZoneName);
- };
if (displayType == DisplayType::Overlap) {
auto *displayWidget = new OverlappedCardGroupDisplayWidget(
- cardGroupContainer, deckListModel, selectionModel, index, effectiveZoneName, categoryName,
- activeGroupCriteria, activeSortCriteria, subBannerOpacity, cardSizeWidget);
- connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardClicked, this, routeCardClick);
+ cardGroupContainer, deckListModel, selectionModel, index, zoneName, categoryName, activeGroupCriteria,
+ activeSortCriteria, subBannerOpacity, cardSizeWidget);
+ connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardClicked, this,
+ &DeckCardZoneDisplayWidget::onClick);
connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardHovered, this,
&DeckCardZoneDisplayWidget::onHover);
connect(displayWidget, &CardGroupDisplayWidget::cleanupRequested, this,
@@ -113,9 +111,9 @@ void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex
indexToWidgetMap.insert(index, displayWidget);
} else if (displayType == DisplayType::Flat) {
auto *displayWidget = new FlatCardGroupDisplayWidget(cardGroupContainer, deckListModel, selectionModel, index,
- effectiveZoneName, categoryName, activeGroupCriteria,
+ zoneName, categoryName, activeGroupCriteria,
activeSortCriteria, subBannerOpacity, cardSizeWidget);
- connect(displayWidget, &FlatCardGroupDisplayWidget::cardClicked, this, routeCardClick);
+ connect(displayWidget, &FlatCardGroupDisplayWidget::cardClicked, this, &DeckCardZoneDisplayWidget::onClick);
connect(displayWidget, &FlatCardGroupDisplayWidget::cardHovered, this, &DeckCardZoneDisplayWidget::onHover);
connect(displayWidget, &CardGroupDisplayWidget::cleanupRequested, this,
&DeckCardZoneDisplayWidget::cleanupInvalidCardGroup);
@@ -128,18 +126,24 @@ void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex
void DeckCardZoneDisplayWidget::displayCards()
{
- if (!trackedIndex.isValid()) {
- return;
- }
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(deckListModel);
+ proxy.setSortRole(Qt::EditRole);
+ proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder);
- // Iterate the direct children of the tracked zone, keeping the tree view's row
- // order (criteria groups first, then custom zones, both in the model's sort order).
- QList rows;
- for (int i = 0; i < deckListModel->rowCount(trackedIndex); ++i) {
- rows.append(QPersistentModelIndex(deckListModel->index(i, 0, trackedIndex)));
- }
+ // 1. trackedIndex is a source index → map it to proxy space
+ QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
+
+ // 2. iterate children under the proxy parent
+ for (int i = 0; i < proxy.rowCount(proxyParent); ++i) {
+ QModelIndex proxyIndex = proxy.index(i, 0, proxyParent);
+
+ // 3. map back to source
+ QModelIndex sourceIndex = proxy.mapToSource(proxyIndex);
+
+ // 4. persist the source index
+ QPersistentModelIndex persistent(sourceIndex);
- for (const QPersistentModelIndex &persistent : rows) {
constructAppropriateWidget(persistent);
}
}
diff --git a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h b/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h
index 53f3fa7cf..b426fca30 100644
--- a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h
+++ b/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h
@@ -42,6 +42,7 @@ public:
void addCardsToOverlapWidget();
public slots:
+ void onClick(QMouseEvent *event, const ExactCard &card);
void onHover(const ExactCard &card);
void cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget);
void constructAppropriateWidget(QPersistentModelIndex index);
diff --git a/cockatrice/src/interface/widgets/deck_editor/card_database_view.cpp b/cockatrice/src/interface/widgets/deck_editor/card_database_view.cpp
index 00388a3cd..7c782b074 100644
--- a/cockatrice/src/interface/widgets/deck_editor/card_database_view.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/card_database_view.cpp
@@ -90,13 +90,6 @@ void CardDatabaseView::decrementCard(const QString &zoneName)
emit cardDecremented(currentCardName(), zoneName);
}
-void CardDatabaseView::setZoneMenuProvider(const std::function>()> &provider,
- const std::function &newZoneHandler)
-{
- zoneMenuProvider = provider;
- this->newZoneHandler = newZoneHandler;
-}
-
void CardDatabaseView::updateCard(const QModelIndex ¤t, const QModelIndex & /*previous*/)
{
if (!current.isValid()) {
@@ -149,50 +142,6 @@ void CardDatabaseView::openCustomMenu(QPoint point)
[this, card] { emit cardAdded(card->getName(), DECK_ZONE_SIDE); });
connect(selectPrinting, &QAction::triggered, this, &CardDatabaseView::selectPrintingClicked);
- if (zoneMenuProvider) {
- QMenu *addToZoneMenu = menu.addMenu(tr("Add to Zone"));
- const auto zoneBoards = zoneMenuProvider();
- for (const QString &boardName : InnerDecklistNode::boardZoneNames()) {
- // Boards with zones nest their children so no two menu entries
- // share a visible name: "Maindeck ▸ { Maindeck (whole board), … }".
- const QStringList customZones = [&zoneBoards, boardName] {
- for (const auto &zoneBoard : zoneBoards) {
- if (zoneBoard.first == boardName) {
- return zoneBoard.second;
- }
- }
- return QStringList();
- }();
- if (customZones.isEmpty()) {
- QAction *action = addToZoneMenu->addAction(InnerDecklistNode::visibleNameFromName(boardName));
- connect(action, &QAction::triggered, this,
- [this, card, boardName] { emit cardAdded(card->getName(), boardName); });
- } else {
- QMenu *boardSubmenu = addToZoneMenu->addMenu(InnerDecklistNode::visibleNameFromName(boardName));
- QAction *wholeBoardAction = boardSubmenu->addAction(InnerDecklistNode::visibleNameFromName(boardName));
- connect(wholeBoardAction, &QAction::triggered, this,
- [this, card, boardName] { emit cardAdded(card->getName(), boardName); });
- for (const QString &zoneName : customZones) {
- QAction *action = boardSubmenu->addAction(zoneName);
- connect(action, &QAction::triggered, this,
- [this, card, zoneName] { emit cardAdded(card->getName(), zoneName); });
- }
- }
- }
-
- if (newZoneHandler) {
- addToZoneMenu->addSeparator();
-
- QAction *newZoneAction = addToZoneMenu->addAction(tr("Create &new zone..."));
- connect(newZoneAction, &QAction::triggered, this, [this, card] {
- const QString zoneName = newZoneHandler();
- if (!zoneName.isEmpty()) {
- emit cardAdded(card->getName(), zoneName);
- }
- });
- }
- }
-
if (canBeCommander(*card)) {
QAction *edhRecCommander = menu.addAction(tr("Show on EDHRec (Commander)"));
connect(edhRecCommander, &QAction::triggered, this, [this, card] { emit edhrecClicked(card, true); });
diff --git a/cockatrice/src/interface/widgets/deck_editor/card_database_view.h b/cockatrice/src/interface/widgets/deck_editor/card_database_view.h
index 668444199..175ec12b9 100644
--- a/cockatrice/src/interface/widgets/deck_editor/card_database_view.h
+++ b/cockatrice/src/interface/widgets/deck_editor/card_database_view.h
@@ -4,7 +4,6 @@
#include "../../key_signals.h"
#include
-#include
#include
class CardDatabaseModel;
@@ -20,13 +19,6 @@ class CardDatabaseView : public QTreeView
KeySignals searchKeySignals;
CardDatabaseDisplayModel *databaseDisplayModel;
- /// Provides the custom zones available in the current deck, grouped by board zone.
- /// The list contains (board zone name, custom zone names) pairs for every board.
- std::function>()> zoneMenuProvider;
- /// Handler invoked when the user picks "New zone..." from the add-to-zone menu.
- /// Returns the name of the created zone, or an empty string if creation was cancelled.
- std::function newZoneHandler;
-
public:
explicit CardDatabaseView(QWidget *parent, CardDatabaseDisplayModel *model);
@@ -41,17 +33,6 @@ public:
return &searchKeySignals;
}
- /**
- * @brief Sets the provider used to populate the "Add to zone" submenu of the context menu.
- * If no provider is set, the submenu is not shown.
- *
- * @param provider Returns the custom zones of the current deck, grouped by board zone
- * @param newZoneHandler Creates a new custom zone and returns its name, or an empty string
- * if creation was cancelled. The menu entry is hidden when not provided.
- */
- void setZoneMenuProvider(const std::function>()> &provider,
- const std::function &newZoneHandler);
-
signals:
void cardChanged(const QString &cardName);
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
index 6269f0323..2a491de4f 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
@@ -1,12 +1,5 @@
#include "deck_editor_card_database_dock_widget.h"
-#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
-#include "card_database_view.h"
-#include "deck_state_manager.h"
-#include "deck_zone_dialog.h"
-
-#include
-
DeckEditorCardDatabaseDockWidget::DeckEditorCardDatabaseDockWidget(AbstractTabDeckEditor *parent) : QDockWidget(parent)
{
setObjectName("databaseDisplayDock");
@@ -22,27 +15,6 @@ void DeckEditorCardDatabaseDockWidget::createDatabaseDisplayDock(AbstractTabDeck
{
databaseDisplayWidget = new DeckEditorDatabaseDisplayWidget(this, deckEditor->databaseModel);
- databaseDisplayWidget->getDatabaseView()->setZoneMenuProvider(
- [deckEditor]() -> QList> {
- QList> result;
- auto *deckListModel = deckEditor->deckStateManager->getModel();
- for (const QString &boardName : InnerDecklistNode::boardZoneNames()) {
- result.append({boardName, deckListModel->getCustomZoneNames(boardName)});
- }
- return result;
- },
- [this, deckEditor]() -> QString {
- QString boardName;
- const QString zoneName =
- DeckZoneDialog::promptForNewZone(this, {}, &boardName, [deckEditor](const QString &candidate) {
- return deckEditor->deckStateManager->validateNewZoneName(candidate);
- });
- if (!zoneName.isEmpty()) {
- deckEditor->deckStateManager->createCustomZone(boardName, zoneName);
- }
- return zoneName;
- });
-
auto *frame = new QVBoxLayout;
frame->setObjectName("databaseDisplayFrame");
frame->addWidget(databaseDisplayWidget);
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index e2175a358..14defc8e9 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -7,18 +7,15 @@
#include "../tabs/api/commander_spellbook/commander_bracket_widget.h"
#include "deck_list_style_proxy.h"
#include "deck_state_manager.h"
-#include "deck_zone_dialog.h"
#include
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -775,213 +772,14 @@ void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, bool i
void DeckEditorDeckDockWidget::decklistCustomMenu(QPoint point)
{
- const QModelIndex sourceIndex = proxy->mapToSource(deckView->indexAt(point));
-
QMenu menu;
- const bool isCustomZoneRow = sourceIndex.isValid() && sourceIndex.data(DeckRoles::IsCustomZoneRole).toBool();
- const bool isBoardZoneRow = sourceIndex.isValid() && !isCustomZoneRow && !sourceIndex.parent().isValid();
- const bool isCardRow =
- sourceIndex.isValid() && !isCustomZoneRow && !isBoardZoneRow && !getModel()->hasChildren(sourceIndex);
-
- // Walk the row up to its top-level node to find the hosting board. Cards in
- // the tokens board cannot be moved (moveCardToZone bails for it), so the
- // move menu is skipped for them.
- QString currentBoardName;
- QModelIndex board = sourceIndex.parent();
- while (board.isValid() && board.parent().isValid()) {
- board = board.parent();
- }
- if (board.isValid()) {
- currentBoardName = board.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- }
-
- if (isCardRow) {
- if (currentBoardName != DECK_ZONE_TOKENS) {
- addMoveToZoneMenu(&menu, sourceIndex, currentBoardName);
- menu.addSeparator();
- }
- } else if (isCustomZoneRow) {
- const QString zoneName =
- sourceIndex.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
-
- QAction *renameAction = menu.addAction(tr("&Rename zone..."));
- connect(renameAction, &QAction::triggered, this, [this, zoneName] {
- // The unchanged name must not validate as a duplicate.
- const QString newName =
- DeckZoneDialog::promptForRename(this, zoneName, [this, zoneName](const QString &candidate) {
- return candidate == zoneName ? QString() : deckStateManager->validateNewZoneName(candidate);
- });
- if (!newName.isEmpty() && newName != zoneName) {
- deckStateManager->renameCustomZone(zoneName, newName);
- }
- });
-
- QMenu *boardMenu = menu.addMenu(tr("Change &board"));
- addChangeBoardMenu(boardMenu, zoneName);
-
- QAction *deleteAction = menu.addAction(tr("&Delete zone"));
- const bool zoneHasCards = getModel()->hasChildren(sourceIndex);
- deleteAction->setEnabled(!zoneHasCards);
- if (zoneHasCards) {
- deleteAction->setToolTip(tr("Move or remove all cards first."));
- menu.setToolTipsVisible(true);
- }
- connect(deleteAction, &QAction::triggered, this, [this, zoneName] {
- const auto result =
- QMessageBox::warning(this, tr("Delete zone"), tr("Delete the zone \"%1\"?").arg(zoneName),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
- if (result == QMessageBox::Yes) {
- deckStateManager->removeCustomZone(zoneName);
- }
- });
- menu.addSeparator();
- } else if (isBoardZoneRow) {
- const QString boardName =
- sourceIndex.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- // Tokens cannot host custom zones, so only offer the action on real boards.
- const bool canHostCustomZones =
- boardName == DECK_ZONE_MAIN || boardName == DECK_ZONE_SIDE || boardName == DECK_ZONE_MAYBEBOARD;
- if (canHostCustomZones) {
- addNewZoneAction(&menu, boardName);
- menu.addSeparator();
- }
- } else if (!sourceIndex.isValid()) {
- addNewZoneAction(&menu);
- menu.addSeparator();
- }
-
QAction *selectPrinting = menu.addAction(tr("Select Printing"));
connect(selectPrinting, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::showPrintingSelector);
menu.exec(deckView->mapToGlobal(point));
}
-void DeckEditorDeckDockWidget::addMoveToZoneMenu(QMenu *menu,
- const QModelIndex &sourceCardIndex,
- const QString ¤tBoardName)
-{
- // The card's current *zone*, derived with the same ancestor walk as
- // DeckStateManager::moveCardToZone (nearest custom-zone ancestor, else the
- // top-level board/zone): a card inside "Removal" under the maindeck lives in
- // "Removal", not "main". Comparing against that instead of the board keeps
- // the enabled state and the same-zone no-op consistent with the move logic.
- QString currentZoneName;
- for (QModelIndex ancestor = sourceCardIndex.parent(); ancestor.isValid(); ancestor = ancestor.parent()) {
- if (ancestor.data(DeckRoles::IsCustomZoneRole).toBool() || !ancestor.parent().isValid()) {
- currentZoneName = ancestor.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- break;
- }
- }
-
- const auto addMoveAction = [this, sourceCardIndex](QMenu *targetMenu, const QString &targetZoneName,
- const QString &label, bool enabled) {
- QAction *action = targetMenu->addAction(label);
- action->setEnabled(enabled);
- if (enabled) {
- connect(action, &QAction::triggered, this, [this, sourceCardIndex, targetZoneName] {
- deckStateManager->moveCardToZone(sourceCardIndex, targetZoneName);
- });
- }
- };
-
- const auto tree = deckStateManager->getDeckListShared()->getTree();
-
- QMenu *moveMenu = menu->addMenu(tr("Move to &zone"));
-
- for (const QString &boardName : InnerDecklistNode::boardZoneNames()) {
- const QString boardLabel = InnerDecklistNode::visibleNameFromName(boardName);
- const auto customZones = tree->getCustomZones(boardName);
-
- // Boards with zones nest their children so no two menu entries share a
- // visible name: "Maindeck ▸ { Maindeck (whole board), Removal, … }".
- // The board the card already lives on is marked instead of offered.
- if (!customZones.isEmpty()) {
- QMenu *boardSubmenu = moveMenu->addMenu(boardLabel);
- addMoveAction(boardSubmenu, boardName, boardLabel, boardName != currentZoneName);
- for (const auto *customZone : customZones) {
- addMoveAction(boardSubmenu, customZone->getName(), customZone->getName(),
- customZone->getName() != currentZoneName);
- }
- } else {
- addMoveAction(moveMenu, boardName, boardLabel, boardName != currentZoneName);
- }
- }
-
- moveMenu->addSeparator();
-
- QAction *newZoneAction = moveMenu->addAction(tr("Create new zone and move &here..."));
- connect(newZoneAction, &QAction::triggered, this, [this, sourceCardIndex, currentBoardName, currentZoneName] {
- // Resolve the card's identity before creating the zone:
- // createNewCustomZone rebuilds the model tree, so sourceCardIndex's
- // internal pointer is freed by the time it would be used.
- const QString cardName =
- sourceCardIndex.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- const QString providerId =
- sourceCardIndex.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::DisplayRole).toString();
- const QString collectorNumber = sourceCardIndex.siblingAtColumn(DeckListModelColumns::CARD_COLLECTOR_NUMBER)
- .data(Qt::DisplayRole)
- .toString();
-
- const QString zoneName = createNewCustomZone(currentBoardName);
- if (!zoneName.isEmpty()) {
- // Re-find the card: the old index is no longer safe since rows were
- // rebuilt. Mirror DeckStateManager::decrementCard's re-find pattern.
- const QModelIndex refreshed = getModel()->findCard(cardName, currentZoneName, providerId, collectorNumber);
- if (refreshed.isValid()) {
- deckStateManager->moveCardToZone(refreshed, zoneName);
- }
- }
- });
-}
-
-void DeckEditorDeckDockWidget::addChangeBoardMenu(QMenu *menu, const QString &zoneName)
-{
- const auto tree = deckStateManager->getDeckListShared()->getTree();
- for (const QString &boardName : InnerDecklistNode::boardZoneNames()) {
- QAction *action = menu->addAction(InnerDecklistNode::visibleNameFromName(boardName));
-
- // The board currently holding the zone is marked instead of offered.
- // Duplicate names cannot come up through the editor, so this doubles as
- // the uniqueness guard for imported decks.
- bool holdsTheZone = false;
- for (const auto *customZone : tree->getCustomZones(boardName)) {
- if (customZone->getName() == zoneName) {
- holdsTheZone = true;
- break;
- }
- }
- if (holdsTheZone) {
- action->setCheckable(true);
- action->setChecked(true);
- continue;
- }
-
- connect(action, &QAction::triggered, this,
- [this, zoneName, boardName] { deckStateManager->moveCustomZone(zoneName, boardName); });
- }
-}
-
-void DeckEditorDeckDockWidget::addNewZoneAction(QMenu *menu, const QString &initialBoardName)
-{
- QAction *newZoneAction = menu->addAction(tr("Create &new zone..."));
- connect(newZoneAction, &QAction::triggered, this,
- [this, initialBoardName] { createNewCustomZone(initialBoardName); });
-}
-
-QString DeckEditorDeckDockWidget::createNewCustomZone(const QString &initialBoardName)
-{
- QString boardName;
- const QString zoneName =
- DeckZoneDialog::promptForNewZone(this, initialBoardName, &boardName, [this](const QString &candidate) {
- return deckStateManager->validateNewZoneName(candidate);
- });
- if (!zoneName.isEmpty()) {
- deckStateManager->createCustomZone(boardName, zoneName);
- }
- return zoneName;
-}
-
void DeckEditorDeckDockWidget::refreshShortcuts()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h
index 1e5f4e677..9db01e2e5 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h
@@ -19,7 +19,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -103,11 +102,6 @@ private:
[[nodiscard]] QModelIndexList getSelectedCardNodeSourceIndices() const;
void offsetCountAtIndex(const QModelIndex &idx, bool isIncrement);
- void addMoveToZoneMenu(QMenu *menu, const QModelIndex &sourceCardIndex, const QString ¤tBoardName);
- void addChangeBoardMenu(QMenu *menu, const QString &zoneName);
- QString createNewCustomZone(const QString &initialBoardName = {});
- void addNewZoneAction(QMenu *menu, const QString &initialBoardName = {});
-
private slots:
void decklistCustomMenu(QPoint point);
void updateCard(QModelIndex, const QModelIndex ¤t);
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp
index e563729a4..eda741728 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp
@@ -2,7 +2,6 @@
#include
#include
-#include
DeckStateManager::DeckStateManager(QObject *parent)
: QObject(parent), deckList(QSharedPointer(new DeckList)),
@@ -308,170 +307,6 @@ bool DeckStateManager::decrementCountAtIndex(const QModelIndex &idx)
return offsetCountAtIndex(idx, -1);
}
-bool DeckStateManager::moveCardToZone(const QModelIndex &idx, const QString &targetZoneName)
-{
- if (!idx.isValid()) {
- return false;
- }
-
- // Only actual card rows can be moved. Group or zone rows report an
- // aggregate amount and must never be deleted by this operation.
- if (!idx.data(DeckRoles::IsCardRole).toBool()) {
- return false;
- }
-
- QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- QString providerId = idx.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::DisplayRole).toString();
- int copies = idx.siblingAtColumn(DeckListModelColumns::CARD_AMOUNT).data(Qt::EditRole).toInt();
-
- if (copies <= 0) {
- return false;
- }
-
- // Tokens only live in the tokens zone and cannot be moved into decks.
- CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(cardName);
- if (info && info->getIsToken()) {
- return false;
- }
-
- // Determine the zone the card currently lives in: the enclosing custom
- // zone, or the nearest top-level zone (board zone or legacy zone).
- QString currentZoneName;
- for (QModelIndex ancestor = idx.parent(); ancestor.isValid(); ancestor = ancestor.parent()) {
- bool isCustomZone = ancestor.data(DeckRoles::IsCustomZoneRole).toBool();
- if (isCustomZone || !ancestor.parent().isValid()) {
- currentZoneName = ancestor.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
- break;
- }
- }
-
- if (currentZoneName == targetZoneName) {
- return false;
- }
-
- QString reason = tr("Moved %1 × \"%2\" (%3) to %4")
- .arg(copies)
- .arg(cardName)
- .arg(providerId)
- .arg(InnerDecklistNode::visibleNameFromName(targetZoneName));
-
- return modifyDeck(reason, [&idx, &cardName, &providerId, &targetZoneName, copies](auto model) {
- if (!model->removeRow(idx.row(), idx.parent())) {
- return false;
- }
-
- if (ExactCard card = CardDatabaseManager::query()->getCard({cardName, providerId})) {
- for (int i = 0; i < copies; ++i) {
- model->addCard(card, targetZoneName);
- }
- } else {
- for (int i = 0; i < copies; ++i) {
- model->addPreferredPrintingCard(cardName, targetZoneName, true);
- }
- }
-
- return true;
- });
-}
-
-bool DeckStateManager::createCustomZone(const QString &boardZoneName, const QString &zoneName)
-{
- const QString trimmedZoneName = zoneName.trimmed();
- if (trimmedZoneName.isEmpty()) {
- return false;
- }
-
- QString reason =
- tr("Created zone \"%1\" in %2").arg(trimmedZoneName, InnerDecklistNode::visibleNameFromName(boardZoneName));
-
- return modifyTree(reason, [&boardZoneName, &trimmedZoneName](DecklistNodeTree *tree) {
- return tree->addCustomZone(boardZoneName, trimmedZoneName) != nullptr;
- });
-}
-
-bool DeckStateManager::renameCustomZone(const QString &oldZoneName, const QString &newZoneName)
-{
- const QString trimmedNewZoneName = newZoneName.trimmed();
- if (trimmedNewZoneName.isEmpty() || oldZoneName == trimmedNewZoneName) {
- return false;
- }
-
- QString reason = tr("Renamed zone \"%1\" to \"%2\"").arg(oldZoneName, trimmedNewZoneName);
-
- return modifyTree(reason, [&oldZoneName, &trimmedNewZoneName](DecklistNodeTree *tree) {
- return tree->renameCustomZone(oldZoneName, trimmedNewZoneName);
- });
-}
-
-bool DeckStateManager::moveCustomZone(const QString &zoneName, const QString &newBoardZoneName)
-{
- const auto *tree = deckList->getTree();
-
- // Locate the zone through the tree's own lookup, which walks every top-level
- // zone (not just the standard boards) and covers the same-board no-op below.
- const auto *zone = tree->findCustomZoneByName(zoneName);
- if (!zone) {
- return false;
- }
-
- // Same-board moves are no-ops and must not pollute the history.
- const QString currentBoardName = zone->getParent() ? zone->getParent()->getName() : QString();
- if (currentBoardName == newBoardZoneName) {
- return true;
- }
-
- // Zone names are deck-unique among zones created through this manager, so a
- // same-named zone on the target board can only come from an imported deck.
- // Refuse the move instead of silently stacking same-named zones.
- for (const auto *targetZone : tree->getCustomZones(newBoardZoneName)) {
- if (targetZone->getName() == zoneName) {
- return false;
- }
- }
-
- QString reason =
- tr("Moved zone \"%1\" to %2").arg(zoneName, InnerDecklistNode::visibleNameFromName(newBoardZoneName));
-
- return modifyTree(reason, [&zoneName, &newBoardZoneName](DecklistNodeTree *tree) {
- return tree->moveCustomZone(zoneName, newBoardZoneName);
- });
-}
-
-bool DeckStateManager::removeCustomZone(const QString &zoneName)
-{
- QString reason = tr("Deleted zone \"%1\"").arg(zoneName);
-
- return modifyTree(reason, [&zoneName](DecklistNodeTree *tree) { return tree->removeCustomZone(zoneName); });
-}
-
-QString DeckStateManager::validateNewZoneName(const QString &zoneName) const
-{
- if (zoneName.trimmed().isEmpty()) {
- return tr("Enter a zone name.");
- }
-
- const QString trimmedZoneName = zoneName.trimmed();
-
- // The standard zone names are reserved even before they exist.
- if (trimmedZoneName == DECK_ZONE_MAIN || trimmedZoneName == DECK_ZONE_SIDE ||
- trimmedZoneName == DECK_ZONE_MAYBEBOARD || trimmedZoneName == DECK_ZONE_TOKENS) {
- return tr("This name is reserved.");
- }
-
- const auto *tree = deckList->getTree();
-
- // Reuse the tree's own uniqueness contract: any top-level zone and any
- // custom zone on *every* board claims the name (hasZoneName also reserves
- // the standard board names, which we already rejected with a dedicated
- // message above). Scanning only the standard boards here would miss a
- // custom zone an imported deck carries under `tokens`.
- if (tree->hasZoneName(trimmedZoneName)) {
- return tr("A zone with this name already exists.");
- }
-
- return {};
-}
-
bool DeckStateManager::offsetCountAtIndex(const QModelIndex &idx, int offset)
{
if (!idx.isValid()) {
@@ -532,25 +367,6 @@ void DeckStateManager::requestHistorySave(const QString &reason)
historyManager->save(deckList->createMemento(reason));
}
-bool DeckStateManager::modifyTree(const QString &reason, const std::function &operation)
-{
- DeckListMemento memento = deckList->createMemento(reason);
- bool success = operation(deckList->getTree());
-
- if (success) {
- historyManager->save(memento);
- deckListModel->rebuildTree();
- deckList->refreshDeckHash();
- emit deckListModel->deckHashChanged();
- // removeCustomZone can drop whole card sets the model never notified
- // about (rebuildTree emits no cardNodesChanged), so tell the consumers.
- emit deckListModel->cardNodesChanged();
- doCardModified();
- }
-
- return success;
-}
-
/**
* @brief Handles updating state and emitting signals whenever the cards are modified
*/
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.h b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.h
index 2c8b34a39..b9c99903e 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.h
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.h
@@ -5,7 +5,6 @@
#include "deck_list_model.h"
#include
-#include
#include
class DeckListHistoryManager;
@@ -237,68 +236,6 @@ public:
*/
bool decrementCountAtIndex(const QModelIndex &idx);
- /**
- * @brief Moves all copies of the card at the given index to the given zone.
- * No-ops if the index is invalid, not a card node, the card is a token, or the
- * card is already in the target zone.
- * Saves the operation to history if successful.
- *
- * @param idx The model index of the card to move
- * @param targetZoneName The zone to move the card to (board zone or custom zone name)
- * @return Whether the operation was successfully performed
- */
- bool moveCardToZone(const QModelIndex &idx, const QString &targetZoneName);
-
- /**
- * @brief Creates a new custom zone nested under a board zone.
- * Saves the operation to history if successful.
- *
- * @param boardZoneName The board zone to nest the custom zone under
- * @param zoneName The name of the new custom zone. Gets trimmed and must be
- * unique across the deck.
- * @return Whether the zone was created
- */
- bool createCustomZone(const QString &boardZoneName, const QString &zoneName);
-
- /**
- * @brief Renames a custom zone.
- * Saves the operation to history if successful.
- *
- * @param oldZoneName The current name of the custom zone
- * @param newZoneName The new name. Gets trimmed and must be unique across the deck.
- * @return Whether the rename succeeded
- */
- bool renameCustomZone(const QString &oldZoneName, const QString &newZoneName);
-
- /**
- * @brief Moves a custom zone (and its cards) to a different board zone.
- * Same-board moves succeed without creating a history entry.
- * Saves the operation to history if successful.
- *
- * @param zoneName The custom zone to move
- * @param newBoardZoneName The board zone to move the custom zone under
- * @return Whether the move succeeded
- */
- bool moveCustomZone(const QString &zoneName, const QString &newBoardZoneName);
-
- /**
- * @brief Removes a custom zone and all its cards.
- * Saves the operation to history if successful.
- *
- * @param zoneName The custom zone to remove
- * @return Whether the zone was removed
- */
- bool removeCustomZone(const QString &zoneName);
-
- /**
- * @brief Checks whether a candidate name is usable for a new custom zone.
- *
- * @param zoneName The candidate name
- * @return An empty string when the name is usable, otherwise a user-facing
- * error message describing the problem
- */
- [[nodiscard]] QString validateNewZoneName(const QString &zoneName) const;
-
/**
* Undoes n steps of the history, setting the decklist state and updating the current step in the historyManager.
* @param steps Number of steps to undo.
@@ -320,7 +257,6 @@ public slots:
private:
bool offsetCountAtIndex(const QModelIndex &idx, int offset);
- bool modifyTree(const QString &reason, const std::function &operation);
void doCardModified();
void doMetadataModified();
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_zone_dialog.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_zone_dialog.cpp
deleted file mode 100644
index 9a0be2570..000000000
--- a/cockatrice/src/interface/widgets/deck_editor/deck_zone_dialog.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-#include "deck_zone_dialog.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-DeckZoneDialog::DeckZoneDialog(QWidget *parent,
- const QString &initialBoardName,
- const std::function &_nameValidator,
- bool _allowBoardSelection)
- : QDialog(parent), nameValidator(_nameValidator), allowBoardSelection(_allowBoardSelection)
-{
- nameLabel = new QLabel(this);
- nameEdit = new QLineEdit(this);
- nameEdit->setMaxLength(MAX_NAME_LENGTH);
-
- errorLabel = new QLabel(this);
- errorLabel->hide();
-
- boardLabel = new QLabel(this);
- boardCombo = new QComboBox(this);
- for (const QString &boardName : InnerDecklistNode::boardZoneNames()) {
- // Use the icon overload explicitly so `boardName` lands in the user data role
- // (visible text is applied below in retranslateUi). The two-argument form
- // addItem({}, boardName) would be ambiguous and resolve to the icon overload
- // with empty user data, yielding empty entries and an empty getBoardName().
- boardCombo->addItem({}, {}, boardName);
- }
- if (!initialBoardName.isEmpty()) {
- int idx = boardCombo->findData(initialBoardName);
- if (idx != -1) {
- boardCombo->setCurrentIndex(idx);
- }
- }
-
- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
- buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
- connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
- connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
-
- auto *layout = new QVBoxLayout(this);
- layout->addWidget(nameLabel);
- layout->addWidget(nameEdit);
- layout->addWidget(errorLabel);
- if (allowBoardSelection) {
- layout->addWidget(boardLabel);
- layout->addWidget(boardCombo);
- } else {
- boardLabel->hide();
- boardCombo->hide();
- }
- layout->addWidget(buttonBox);
-
- retranslateUi();
-
- connect(nameEdit, &QLineEdit::textChanged, this, [this] { validateName(); });
- validateName();
-
- nameEdit->setFocus();
-}
-
-QString DeckZoneDialog::getZoneName() const
-{
- return nameEdit->text().trimmed();
-}
-
-QString DeckZoneDialog::getBoardName() const
-{
- return boardCombo->currentData().toString();
-}
-
-void DeckZoneDialog::setZoneName(const QString &zoneName)
-{
- nameEdit->setText(zoneName);
- nameEdit->selectAll();
-}
-
-void DeckZoneDialog::changeEvent(QEvent *event)
-{
- QDialog::changeEvent(event);
-
- if (event->type() == QEvent::LanguageChange) {
- retranslateUi();
- }
-}
-
-void DeckZoneDialog::retranslateUi()
-{
- setWindowTitle(allowBoardSelection ? tr("New zone") : tr("Rename zone"));
-
- nameLabel->setText(tr("Zone &name:"));
- nameLabel->setBuddy(nameEdit);
-
- boardLabel->setText(tr("&Parent zone:"));
- boardLabel->setBuddy(boardCombo);
-
- for (int i = 0; i < boardCombo->count(); i++) {
- boardCombo->setItemText(i, InnerDecklistNode::visibleNameFromName(boardCombo->itemData(i).toString()));
- }
-}
-
-void DeckZoneDialog::validateName()
-{
- const QString zoneName = nameEdit->text().trimmed();
- QString error;
- if (zoneName.isEmpty()) {
- error = tr("Enter a zone name.");
- } else if (nameValidator) {
- error = nameValidator(zoneName);
- }
-
- errorLabel->setText(error);
- errorLabel->setVisible(!error.isEmpty());
- buttonBox->button(QDialogButtonBox::Ok)->setEnabled(error.isEmpty());
-}
-
-QString DeckZoneDialog::promptForNewZone(QWidget *parent,
- const QString &initialBoardName,
- QString *chosenBoardName,
- const std::function &nameValidator)
-{
- DeckZoneDialog dialog(parent, initialBoardName, nameValidator);
- if (dialog.exec() != QDialog::Accepted) {
- return {};
- }
-
- if (chosenBoardName) {
- *chosenBoardName = dialog.getBoardName();
- }
- return dialog.getZoneName();
-}
-
-QString DeckZoneDialog::promptForRename(QWidget *parent,
- const QString ¤tZoneName,
- const std::function &nameValidator)
-{
- DeckZoneDialog dialog(parent, {}, nameValidator, false);
- dialog.setZoneName(currentZoneName);
- return dialog.exec() == QDialog::Accepted ? dialog.getZoneName() : QString();
-}
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_zone_dialog.h b/cockatrice/src/interface/widgets/deck_editor/deck_zone_dialog.h
deleted file mode 100644
index 6f55617a8..000000000
--- a/cockatrice/src/interface/widgets/deck_editor/deck_zone_dialog.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * @file deck_zone_dialog.h
- * @ingroup DeckEditorWidgets
- * @brief Shared dialog for creating custom deck zones.
- */
-
-#ifndef DECK_ZONE_DIALOG_H
-#define DECK_ZONE_DIALOG_H
-
-#include
-#include
-#include
-#include
-
-class QComboBox;
-class QDialogButtonBox;
-class QLabel;
-class QLineEdit;
-class QWidget;
-
-/**
- * @brief Modal dialog asking for the name and parent zone of a new custom deck zone.
- *
- * Menus construct the dialog transiently around exec(), so validation state only
- * ever reflects the name currently typed.
- */
-class DeckZoneDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- /**
- * @brief Constructs the dialog and runs the initial validation pass.
- *
- * @param parent The parent widget for the dialog
- * @param initialBoardName The board zone to preselect in the combo. Unknown names
- * fall back to main.
- * @param _nameValidator Given the trimmed candidate name, returns an empty string
- * when it is usable, otherwise a user-facing error message. May be empty.
- * @param _allowBoardSelection When false the parent-zone combo is hidden and the
- * dialog acts as a rename prompt for an existing zone.
- */
- explicit DeckZoneDialog(QWidget *parent = nullptr,
- const QString &initialBoardName = {},
- const std::function &_nameValidator = {},
- bool _allowBoardSelection = true);
-
- /**
- * @brief The trimmed zone name entered by the user.
- */
- [[nodiscard]] QString getZoneName() const;
-
- /**
- * @brief The internal name of the board zone selected in the combo.
- */
- [[nodiscard]] QString getBoardName() const;
-
- /**
- * @brief Prefills the name field, e.g. with the current name when renaming.
- *
- * @param zoneName The text to put into the name field, selected for quick editing
- */
- void setZoneName(const QString &zoneName);
-
- /**
- * @brief Prompts the user for a new custom zone name and the board zone to nest it under.
- *
- * Convenience wrapper that runs DeckZoneDialog modally.
- *
- * @param parent The parent widget for the dialog
- * @param initialBoardName The board zone to preselect in the dialog. Unknown names fall
- * back to main.
- * @param chosenBoardName (out) The internal name of the board zone the user chose
- * @param nameValidator Optional validator forwarded to the dialog
- * @return The trimmed zone name, or an empty string if the user cancelled
- */
- static QString promptForNewZone(QWidget *parent,
- const QString &initialBoardName,
- QString *chosenBoardName,
- const std::function &nameValidator = {});
-
- /**
- * @brief Prompts the user for a new name for an existing custom zone.
- *
- * Same inline validation as promptForNewZone, but without a parent-zone picker.
- *
- * @param parent The parent widget for the dialog
- * @param currentZoneName The current name, prefilled for editing
- * @param nameValidator Validator deciding whether a candidate name is usable. It sees
- * the current name too, so callers wanting to allow unchanged names must
- * special-case that themselves.
- * @return The trimmed new name, or an empty string if the user cancelled
- */
- static QString promptForRename(QWidget *parent,
- const QString ¤tZoneName,
- const std::function &nameValidator = {});
-
-protected:
- void changeEvent(QEvent *event) override;
-
-private:
- /**
- * @brief Sets every user-visible string. Runs on construction and on runtime
- * language changes.
- */
- void retranslateUi();
-
- /**
- * @brief Validates the current input, toggling Ok and the inline error label.
- */
- void validateName();
-
- QLabel *nameLabel;
- QLineEdit *nameEdit;
- QLabel *errorLabel;
- QLabel *boardLabel;
- QComboBox *boardCombo;
- QDialogButtonBox *buttonBox;
- std::function nameValidator;
- bool allowBoardSelection;
-};
-
-#endif // DECK_ZONE_DIALOG_H
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp
index 4698b011f..883cfcd03 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp
@@ -132,7 +132,7 @@ void DlgSettings::setupUi()
pagesWidget->addWidget(makeScrollable(userInterfacePage));
pagesWidget->addWidget(makeScrollable(deckEditorPage));
pagesWidget->addWidget(makeScrollable(storagePage));
- pagesWidget->addWidget(makeScrollable(messagesPage));
+ pagesWidget->addWidget(messagesPage);
pagesWidget->addWidget(soundPage);
pagesWidget->addWidget(shortcutsPage);
diff --git a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp
index 4af02fe4f..618ac6f26 100644
--- a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp
+++ b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp
@@ -182,13 +182,6 @@ void FirstRunWizard::onCardDatabaseUpdateFinished(bool success)
}
}
-void FirstRunWizard::onCardDatabaseUpdateProgress(const QString &stage, qint64 done, qint64 total)
-{
- if (cardDatabasePage) {
- cardDatabasePage->onUpdateProgress(stage, done, total);
- }
-}
-
void FirstRunWizard::finish()
{
accept();
diff --git a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h
index 21d7b6e06..2c186ef95 100644
--- a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h
+++ b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h
@@ -37,9 +37,6 @@ public slots:
/** @brief Forwarded from MainWindow once the background card database update process exits. */
void onCardDatabaseUpdateFinished(bool success);
- /** @brief Forwarded from MainWindow while the background card database update process runs. */
- void onCardDatabaseUpdateProgress(const QString &stage, qint64 done, qint64 total);
-
protected:
void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override;
diff --git a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp
index 50e8ff63d..12116de7a 100644
--- a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp
+++ b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp
@@ -15,7 +15,6 @@
#include
#include
#include
-#include
#include
#include
@@ -180,25 +179,6 @@ void CardDatabaseSetupPage::onUpdateFinished(bool success)
}
}
-void CardDatabaseSetupPage::onUpdateProgress(const QString &stage, qint64 done, qint64 total)
-{
- if (state != State::Running) {
- return;
- }
- progressBar->setRange(0, total > 0 ? static_cast(qMin(total, INT_MAX)) : 0);
- progressBar->setValue(static_cast(qMin(done, INT_MAX)));
- if (total > 0) {
- const int percent = static_cast((100.0 * done) / total);
- if (stage == QLatin1String("download")) {
- statusLabel->setText(tr("Downloading the card database (%1%)…").arg(percent));
- } else if (stage == QLatin1String("scan")) {
- statusLabel->setText(tr("Parsing the card database (%1%)…").arg(percent));
- } else if (stage == QLatin1String("import")) {
- statusLabel->setText(tr("Importing cards (%1%)…").arg(percent));
- }
- }
-}
-
QString CardDatabaseSetupPage::nextButtonText() const
{
return state == State::NotStarted ? tr("Download") : QString();
diff --git a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h
index 870e759ea..0461d11d5 100644
--- a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h
+++ b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h
@@ -30,7 +30,6 @@ public:
void retranslateUi() override;
void onUpdateFinished(bool success);
- void onUpdateProgress(const QString &stage, qint64 done, qint64 total);
signals:
void updateRequested();
diff --git a/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp b/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp
index 9459c5ea9..57706cf93 100644
--- a/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp
+++ b/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp
@@ -2,7 +2,6 @@
#include "../../card_picture_loader/card_picture_loader.h"
#include "../cards/art_crop_attribution.h"
-#include "../cards/card_art_utils.h"
#include "../utility/completer_utils.h"
#include "card_database_display_model.h"
#include "card_database_model.h"
@@ -277,7 +276,7 @@ void PlaymatSettingsDialog::reloadPreview()
return;
}
- currentPixmap = CardArtUtils::rotateSidewaysLayoutArt(fullRes, card);
+ currentPixmap = fullRes;
preview->setPixmap(currentPixmap);
preview->setParams(currentParams);
preview->setAttribution(buildArtAttribution(card));
diff --git a/cockatrice/src/interface/widgets/replay/replay_manager.cpp b/cockatrice/src/interface/widgets/replay/replay_manager.cpp
index c51b96b6c..a2c1e0ff0 100644
--- a/cockatrice/src/interface/widgets/replay/replay_manager.cpp
+++ b/cockatrice/src/interface/widgets/replay/replay_manager.cpp
@@ -142,10 +142,8 @@ void ReplayManager::processNewEvents(PlaybackMode playbackMode)
}
// backwards skip => always skip tap animation
- // backwards skip => always skip damage animation (battlefield shimmer / life counter flash)
if (playbackMode == BACKWARD_SKIP) {
options |= SKIP_TAP_ANIMATION;
- options |= SKIP_DAMAGE_ANIMATION;
}
emit eventReplayed(replay->event_list(currentEvent), options);
diff --git a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp
index 2ba745715..3a1876fa1 100644
--- a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp
@@ -1,7 +1,6 @@
#include "user_card_art_provider.h"
#include "../../../card_picture_loader/card_picture_loader.h"
-#include "../../cards/card_art_utils.h"
#include
#include
@@ -53,25 +52,16 @@ void UserCardArtProvider::requestCardArt(const QString &userName, const QString
processQueue();
}
-QPixmap UserCardArtProvider::cropCardArt(const QPixmap &fullRes, const ExactCard &card)
+QPixmap UserCardArtProvider::cropCardArt(const QPixmap &fullRes)
{
- QPixmap source = fullRes;
-
- // Sideways-layout cards (plane, siege/battle, split) store their landscape
- // artwork rotated 90° inside a portrait frame. Rotate it upright first so
- // the crop below lands on the horizontal art, mirroring the way
- // CardInfoPictureWidget displays these cards.
- const bool landscape = card.getInfo().getUiAttributes().landscapeOrientation;
- source = CardArtUtils::rotateSidewaysLayoutArt(source, card);
-
- const QSize sz = source.size();
+ const QSize sz = fullRes.size();
const int marginX = sz.width() * 0.07;
- const int topMargin = landscape ? sz.height() * 0.05 : sz.height() * 0.11;
- const int bottomMargin = landscape ? sz.height() * 0.42 : sz.height() * 0.45;
+ const int topMargin = sz.height() * 0.11;
+ const int bottomMargin = sz.height() * 0.45;
- const QRect artRect(marginX, topMargin, sz.width() - 2 * marginX, sz.height() - topMargin - bottomMargin);
+ const QRect foilRect(marginX, topMargin, sz.width() - 2 * marginX, sz.height() - topMargin - bottomMargin);
- return source.copy(artRect.intersected(source.rect()));
+ return fullRes.copy(foilRect.intersected(fullRes.rect()));
}
void UserCardArtProvider::insertIntoCache(const QString &key, const QPixmap &pixmap)
@@ -121,7 +111,7 @@ void UserCardArtProvider::processQueue()
// Synchronous hit (already loaded/on disk)
if (!fullRes.isNull()) {
- insertIntoCache(key, cropCardArt(fullRes, card));
+ insertIntoCache(key, cropCardArt(fullRes));
pending.remove(key);
emit cardArtUpdated(userName);
@@ -145,7 +135,7 @@ void UserCardArtProvider::processQueue()
CardPictureLoader::getPixmap(fullRes, card, QSize(745, 1040));
if (!fullRes.isNull()) {
- self->insertIntoCache(key, self->cropCardArt(fullRes, card));
+ self->insertIntoCache(key, self->cropCardArt(fullRes));
}
self->pending.remove(key);
diff --git a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h
index e8283a891..2592237c4 100644
--- a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h
+++ b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h
@@ -6,7 +6,6 @@
#include
#include
#include
-#include
class UserCardArtProvider : public QObject
{
@@ -17,7 +16,7 @@ public:
void requestCardArt(const QString &userName, const QString &cardName, const QString &providerId);
const QMap &cache() const;
- static QPixmap cropCardArt(const QPixmap &fullRes, const ExactCard &card);
+ static QPixmap cropCardArt(const QPixmap &fullRes);
signals:
void cardArtUpdated(const QString &userName);
diff --git a/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp b/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp
index d49e3d540..532112964 100644
--- a/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp
@@ -560,7 +560,7 @@ void UserCardArtSettingsDialog::reloadPreview()
return;
}
- currentPixmap = UserCardArtProvider::cropCardArt(fullRes, card);
+ currentPixmap = UserCardArtProvider::cropCardArt(fullRes);
preview->setPixmap(currentPixmap);
preview->setParams(currentParams);
diff --git a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp
index 0d2267a63..72e7c41b2 100644
--- a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp
@@ -452,7 +452,7 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
}
}
aDetails->setEnabled(true);
- aChat->setEnabled(anotherUser && online && !userListProxy->isUserIgnored(userName));
+ aChat->setEnabled(anotherUser && online);
aShowGames->setEnabled(online);
aReport->setEnabled(anotherUser);
aAddToBuddyList->setEnabled(anotherUser);
@@ -625,15 +625,7 @@ void UserContextMenu::execAddToIgnore(const QString &userName)
Command_AddToList cmd;
cmd.set_list("ignore");
cmd.set_user_name(userName.toStdString());
- PendingCommand *pend = client->prepareSessionCommand(cmd);
- connect(pend, &PendingCommand::finished, this,
- [this, userName](const Response &response, const CommandContainer &, const QVariant &) {
- if (response.response_code() == Response::RespOk) {
- QMessageBox::information(static_cast(parent()), tr("Ignore list"),
- tr("%1 has been added to your ignore list.").arg(userName));
- }
- });
- client->sendCommand(pend);
+ client->sendCommand(client->prepareSessionCommand(cmd));
}
void UserContextMenu::execRemoveFromIgnore(const QString &userName)
diff --git a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp
index c8494f095..881c54167 100644
--- a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp
@@ -154,48 +154,6 @@ AppearanceSettingsPage::AppearanceSettingsPage()
homeTabGroupBox = new QGroupBox;
homeTabGroupBox->setLayout(homeTabGrid);
- // Playmat settings
- playmatVisibilityCombo.addItem(tr("Show all playmats"), PlaymatVisibilityAll);
- playmatVisibilityCombo.addItem(tr("Show own playmat only"), PlaymatVisibilityOwnOnly);
- playmatVisibilityCombo.addItem(tr("Don't use playmats"), PlaymatVisibilityNone);
- int visIdx = playmatVisibilityCombo.findData(settings.userInterface().getPlaymatVisibility());
- if (visIdx >= 0) {
- playmatVisibilityCombo.setCurrentIndex(visIdx);
- }
- connect(&playmatVisibilityCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) {
- SettingsCache::instance().userInterface().setPlaymatVisibility(playmatVisibilityCombo.itemData(index).toInt());
- });
- playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo);
-
- // Playmat mode: Override / Fallback / Deck-only
- playmatModeCombo.addItem(tr("Override deck playmat"), PlaymatModeOverrideDeck);
- playmatModeCombo.addItem(tr("Fallback if deck has none"), PlaymatModeFallback);
- playmatModeCombo.addItem(tr("Deck only, ignore collection"), PlaymatModeDeckOnly);
- int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode());
- if (modeIdx >= 0) {
- playmatModeCombo.setCurrentIndex(modeIdx);
- }
- connect(&playmatModeCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) {
- SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt());
- });
- playmatModeLabel.setBuddy(&playmatModeCombo);
-
- // User-level playmat settings: fallback collection.
- connect(&playmatDefaultEditButton, &QPushButton::clicked, this,
- &AppearanceSettingsPage::openPlaymatCollectionDialog);
-
- auto *playmatGrid = new QGridLayout;
- playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1);
- playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1);
- playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1);
- playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1);
- playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1);
- playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1);
-
- playmatGroupBox = new QGroupBox;
- playmatGroupBox->setLayout(playmatGrid);
-
- // Styling settings
styleUserListCheckBox.setChecked(settings.appearance().getStyleUserList());
connect(&styleUserListCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings.appearance(),
&AppearanceSettings::setStyleUserList);
@@ -301,6 +259,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
cardLayoutGroupBox->setLayout(cardLayoutGrid);
// Card counter colors
+
auto *cardCounterColorsLayout = new QGridLayout;
cardCounterColorsLayout->setColumnStretch(1, 1);
cardCounterColorsLayout->setColumnStretch(3, 1);
@@ -380,6 +339,47 @@ AppearanceSettingsPage::AppearanceSettingsPage()
tableGroupBox = new QGroupBox;
tableGroupBox->setLayout(tableGrid);
+ // Playmat settings
+ playmatVisibilityCombo.addItem(tr("Show all playmats"), PlaymatVisibilityAll);
+ playmatVisibilityCombo.addItem(tr("Show own playmat only"), PlaymatVisibilityOwnOnly);
+ playmatVisibilityCombo.addItem(tr("Don't use playmats"), PlaymatVisibilityNone);
+ int visIdx = playmatVisibilityCombo.findData(settings.userInterface().getPlaymatVisibility());
+ if (visIdx >= 0) {
+ playmatVisibilityCombo.setCurrentIndex(visIdx);
+ }
+ connect(&playmatVisibilityCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) {
+ SettingsCache::instance().userInterface().setPlaymatVisibility(playmatVisibilityCombo.itemData(index).toInt());
+ });
+ playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo);
+
+ // Playmat mode: Override / Fallback / Deck-only
+ playmatModeCombo.addItem(tr("Override deck playmat"), PlaymatModeOverrideDeck);
+ playmatModeCombo.addItem(tr("Fallback if deck has none"), PlaymatModeFallback);
+ playmatModeCombo.addItem(tr("Deck only, ignore collection"), PlaymatModeDeckOnly);
+ int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode());
+ if (modeIdx >= 0) {
+ playmatModeCombo.setCurrentIndex(modeIdx);
+ }
+ connect(&playmatModeCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) {
+ SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt());
+ });
+ playmatModeLabel.setBuddy(&playmatModeCombo);
+
+ // User-level playmat settings: fallback collection.
+ connect(&playmatDefaultEditButton, &QPushButton::clicked, this,
+ &AppearanceSettingsPage::openPlaymatCollectionDialog);
+
+ auto *playmatGrid = new QGridLayout;
+ playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1);
+ playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1);
+ playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1);
+ playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1);
+ playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1);
+ playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1);
+
+ playmatGroupBox = new QGroupBox;
+ playmatGroupBox->setLayout(playmatGrid);
+
// putting it all together
auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(themeGroupBox);
@@ -512,12 +512,6 @@ void AppearanceSettingsPage::retranslateUi()
homeTabButtonColorSourceBox.setToolTip(
tr("Automatic: extract from background if present, otherwise use theme default"));
- playmatGroupBox->setTitle(tr("Playmat settings"));
- playmatVisibilityLabel.setText(tr("Playmat visibility:"));
- playmatModeLabel.setText(tr("Default collection behavior:"));
- playmatDefaultLabel.setText(tr("Default playmat collection:"));
- playmatDefaultEditButton.setText(tr("Edit..."));
-
stylingGroupBox->setTitle(tr("Styling settings"));
styleUserListCheckBox.setText(tr("Style user list"));
@@ -560,4 +554,9 @@ void AppearanceSettingsPage::retranslateUi()
tableGroupBox->setTitle(tr("Table grid layout"));
invertVerticalCoordinateCheckBox.setText(tr("Invert vertical coordinate"));
minPlayersForMultiColumnLayoutLabel.setText(tr("Minimum player count for multi-column layout:"));
+ playmatGroupBox->setTitle(tr("Playmat settings"));
+ playmatVisibilityLabel.setText(tr("Playmat visibility:"));
+ playmatModeLabel.setText(tr("Default collection behavior:"));
+ playmatDefaultLabel.setText(tr("Default playmat collection:"));
+ playmatDefaultEditButton.setText(tr("Edit..."));
}
diff --git a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h
index 8db71ff8f..6b0369694 100644
--- a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h
+++ b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h
@@ -44,55 +44,46 @@ private:
QLabel homeTabButtonColorSourceLabel;
QComboBox homeTabButtonColorSourceBox;
- QLabel playmatVisibilityLabel;
- QComboBox playmatVisibilityCombo;
- QLabel playmatModeLabel;
- QComboBox playmatModeCombo;
- QLabel playmatDefaultLabel;
- QPushButton playmatDefaultEditButton;
-
QCheckBox styleUserListCheckBox;
-
QCheckBox showShortcutsCheckBox;
QCheckBox showGameSelectorFilterToolbarCheckBox;
-
+ QLabel minPlayersForMultiColumnLayoutLabel;
+ QLabel maxFontSizeForCardsLabel;
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
-
QCheckBox displayCardNamesCheckBox;
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
QCheckBox cardScalingCheckBox;
QCheckBox roundCardCornersCheckBox;
- QLabel maxFontSizeForCardsLabel;
- QSpinBox maxFontSizeForCardsEdit;
-
QLabel verticalCardOverlapPercentLabel;
QSpinBox verticalCardOverlapPercentBox;
QLabel cardViewInitialRowsMaxLabel;
QSpinBox cardViewInitialRowsMaxBox;
QLabel cardViewExpandedRowsMaxLabel;
QSpinBox cardViewExpandedRowsMaxBox;
-
- QList cardCounterNames;
-
QCheckBox horizontalHandCheckBox;
QCheckBox leftJustifiedHandCheckBox;
-
QCheckBox invertVerticalCoordinateCheckBox;
- QLabel minPlayersForMultiColumnLayoutLabel;
- QSpinBox minPlayersForMultiColumnLayoutEdit;
-
+ QLabel playmatVisibilityLabel;
+ QComboBox playmatVisibilityCombo;
+ QLabel playmatModeLabel;
+ QComboBox playmatModeCombo;
+ QLabel playmatDefaultLabel;
+ QPushButton playmatDefaultEditButton;
QGroupBox *themeGroupBox;
QGroupBox *homeTabGroupBox;
- QGroupBox *playmatGroupBox;
QGroupBox *stylingGroupBox;
QGroupBox *menuGroupBox;
QGroupBox *printingsGroupBox;
QGroupBox *cardsGroupBox;
QGroupBox *cardLayoutGroupBox;
- QGroupBox *cardCountersGroupBox;
QGroupBox *handGroupBox;
+ QGroupBox *playmatGroupBox;
QGroupBox *tableGroupBox;
+ QGroupBox *cardCountersGroupBox;
+ QList cardCounterNames;
+ QSpinBox minPlayersForMultiColumnLayoutEdit;
+ QSpinBox maxFontSizeForCardsEdit;
public:
AppearanceSettingsPage();
diff --git a/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp
index 62b06fb60..a293660f9 100644
--- a/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp
@@ -425,28 +425,29 @@ void GeneralSettingsPage::updateStartupServerControlsVisibility()
void GeneralSettingsPage::retranslateUi()
{
- const auto &settings = SettingsCache::instance();
-
languageGroupBox->setTitle(tr("Language settings"));
languageLabel.setText(tr("Language:"));
- advertiseTranslationPageLabel.setText(
- QString("%2").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations")));
versionGroupBox->setTitle(tr("Version settings"));
+ cardDatabaseGroupBox->setTitle(tr("Card database"));
+ startupGroupBox->setTitle(tr("Startup settings"));
+
+ if (SettingsCache::instance().getIsPortableBuild()) {
+ pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)"));
+ } else {
+ pathsGroupBox->setTitle(tr("Paths"));
+ }
+ advertiseTranslationPageLabel.setText(
+ QString("%2").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations")));
+ deckPathLabel.setText(tr("Decks directory:"));
+ filtersPathLabel.setText(tr("Filters directory:"));
+ replaysPathLabel.setText(tr("Replays directory:"));
+ picsPathLabel.setText(tr("Pictures directory:"));
+ cardDatabasePathLabel.setText(tr("Card database:"));
+ customCardDatabasePathLabel.setText(tr("Custom database directory:"));
+ tokenDatabasePathLabel.setText(tr("Token database:"));
updateReleaseChannelLabel.setText(tr("Update channel"));
startupUpdateCheckCheckBox.setText(tr("Check for client updates on startup"));
- updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
- newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
-
- // We can't change the strings after they're put into the QComboBox, so this is our workaround
- int oldIndex = updateReleaseChannelBox.currentIndex();
- updateReleaseChannelBox.clear();
- for (ReleaseChannel *chan : settings.getUpdateReleaseChannels()) {
- updateReleaseChannelBox.addItem(tr(chan->getName().toUtf8()));
- }
- updateReleaseChannelBox.setCurrentIndex(oldIndex);
-
- cardDatabaseGroupBox->setTitle(tr("Card database"));
startupCardUpdateCheckBehaviorLabel.setText(tr("Check for card database updates on startup"));
startupCardUpdateCheckBehaviorSelector.setItemText(startupCardUpdateCheckBehaviorIndexNone, tr("Don't check"));
startupCardUpdateCheckBehaviorSelector.setItemText(startupCardUpdateCheckBehaviorIndexPrompt,
@@ -455,13 +456,8 @@ void GeneralSettingsPage::retranslateUi()
tr("Always update in the background"));
cardUpdateCheckIntervalLabel.setText(tr("Check for card database updates every"));
cardUpdateCheckIntervalSpinBox.setSuffix(tr(" days"));
-
- QDate lastCheckDate = settings.updates().getLastCardUpdateCheck();
- int daysAgo = lastCheckDate.daysTo(QDate::currentDate());
- lastCardUpdateCheckDateLabel.setText(
- tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo));
-
- startupGroupBox->setTitle(tr("Startup settings"));
+ updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
+ newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
showTipsOnStartup.setText(tr("Show tips on startup"));
startupTabLabel.setText(tr("Startup tab:"));
startupTabSelector.setItemText(StartupTab::StartupTabHome, tr("Home"));
@@ -477,18 +473,21 @@ void GeneralSettingsPage::retranslateUi()
startupServerLabel.setText(tr("Server:"));
startupRoomLabel.setText(tr("Room:"));
startupRoomNameEdit->setPlaceholderText(tr("Room name"));
-
- if (settings.getIsPortableBuild()) {
- pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)"));
- } else {
- pathsGroupBox->setTitle(tr("Paths"));
- }
- deckPathLabel.setText(tr("Decks directory:"));
- filtersPathLabel.setText(tr("Filters directory:"));
- replaysPathLabel.setText(tr("Replays directory:"));
- picsPathLabel.setText(tr("Pictures directory:"));
- cardDatabasePathLabel.setText(tr("Card database:"));
- customCardDatabasePathLabel.setText(tr("Custom database directory:"));
- tokenDatabasePathLabel.setText(tr("Token database:"));
resetAllPathsButton->setText(tr("Reset all paths"));
-}
+
+ const auto &settings = SettingsCache::instance();
+
+ QDate lastCheckDate = settings.updates().getLastCardUpdateCheck();
+ int daysAgo = lastCheckDate.daysTo(QDate::currentDate());
+
+ lastCardUpdateCheckDateLabel.setText(
+ tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo));
+
+ // We can't change the strings after they're put into the QComboBox, so this is our workaround
+ int oldIndex = updateReleaseChannelBox.currentIndex();
+ updateReleaseChannelBox.clear();
+ for (ReleaseChannel *chan : settings.getUpdateReleaseChannels()) {
+ updateReleaseChannelBox.addItem(tr(chan->getName().toUtf8()));
+ }
+ updateReleaseChannelBox.setCurrentIndex(oldIndex);
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/settings_page/general_settings_page.h b/cockatrice/src/interface/widgets/settings_page/general_settings_page.h
index e0c1a47bf..8dd7e8798 100644
--- a/cockatrice/src/interface/widgets/settings_page/general_settings_page.h
+++ b/cockatrice/src/interface/widgets/settings_page/general_settings_page.h
@@ -42,37 +42,6 @@ private:
QGroupBox *startupGroupBox;
QGroupBox *pathsGroupBox;
- QLabel languageLabel;
- QComboBox languageBox;
- QLabel advertiseTranslationPageLabel;
-
- QLabel updateReleaseChannelLabel;
- QComboBox updateReleaseChannelBox;
- QCheckBox startupUpdateCheckCheckBox;
- QCheckBox updateNotificationCheckBox;
- QCheckBox newVersionOracleCheckBox;
-
- QLabel startupCardUpdateCheckBehaviorLabel;
- QComboBox startupCardUpdateCheckBehaviorSelector;
- QLabel cardUpdateCheckIntervalLabel;
- QSpinBox cardUpdateCheckIntervalSpinBox;
- QLabel lastCardUpdateCheckDateLabel;
-
- QCheckBox showTipsOnStartup;
- QLabel startupTabLabel;
- QComboBox startupTabSelector;
- QLabel startupServerLabel;
- QComboBox startupServerSelector;
- QLabel startupRoomLabel;
- QLineEdit *startupRoomNameEdit;
-
- QLabel deckPathLabel;
- QLabel filtersPathLabel;
- QLabel replaysPathLabel;
- QLabel picsPathLabel;
- QLabel cardDatabasePathLabel;
- QLabel customCardDatabasePathLabel;
- QLabel tokenDatabasePathLabel;
QLineEdit *deckPathEdit;
QLineEdit *filtersPathEdit;
QLineEdit *replaysPathEdit;
@@ -82,6 +51,33 @@ private:
QLineEdit *tokenDatabasePathEdit;
QPushButton *resetAllPathsButton;
QLabel *allPathsResetLabel;
+ QComboBox languageBox;
+ QCheckBox startupUpdateCheckCheckBox;
+ QLabel startupCardUpdateCheckBehaviorLabel;
+ QComboBox startupCardUpdateCheckBehaviorSelector;
+ QLabel cardUpdateCheckIntervalLabel;
+ QSpinBox cardUpdateCheckIntervalSpinBox;
+ QLabel lastCardUpdateCheckDateLabel;
+ QCheckBox updateNotificationCheckBox;
+ QCheckBox newVersionOracleCheckBox;
+ QComboBox updateReleaseChannelBox;
+ QLabel languageLabel;
+ QLabel deckPathLabel;
+ QLabel filtersPathLabel;
+ QLabel replaysPathLabel;
+ QLabel picsPathLabel;
+ QLabel cardDatabasePathLabel;
+ QLabel customCardDatabasePathLabel;
+ QLabel tokenDatabasePathLabel;
+ QLabel updateReleaseChannelLabel;
+ QLabel advertiseTranslationPageLabel;
+ QCheckBox showTipsOnStartup;
+ QLabel startupTabLabel;
+ QComboBox startupTabSelector;
+ QLabel startupServerLabel;
+ QComboBox startupServerSelector;
+ QLabel startupRoomLabel;
+ QLineEdit *startupRoomNameEdit;
};
#endif // COCKATRICE_GENERAL_SETTINGS_PAGE_H
diff --git a/cockatrice/src/interface/widgets/settings_page/messages_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/messages_settings_page.cpp
index c161030d8..e4f24ab73 100644
--- a/cockatrice/src/interface/widgets/settings_page/messages_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/messages_settings_page.cpp
@@ -59,10 +59,6 @@ MessagesSettingsPage::MessagesSettingsPage()
connect(&roomHistory, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().chat(),
&ChatSettings::setRoomHistory);
- ignoreAllPrivateMessagesCheckBox.setChecked(SettingsCache::instance().chat().getIgnoreAllPrivateMessages());
- connect(&ignoreAllPrivateMessagesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().chat(),
- &ChatSettings::setIgnoreAllPrivateMessages);
-
customAlertString = new QLineEdit();
customAlertString->setText(SettingsCache::instance().chat().getHighlightWords());
connect(customAlertString, &QLineEdit::textChanged, &SettingsCache::instance().chat(),
@@ -80,7 +76,6 @@ MessagesSettingsPage::MessagesSettingsPage()
chatGrid->addWidget(&messagePopups, 5, 0);
chatGrid->addWidget(&mentionPopups, 6, 0);
chatGrid->addWidget(&roomHistory, 7, 0);
- chatGrid->addWidget(&ignoreAllPrivateMessagesCheckBox, 8, 0);
chatGroupBox = new QGroupBox;
chatGroupBox->setLayout(chatGrid);
@@ -261,7 +256,6 @@ void MessagesSettingsPage::retranslateUi()
messagePopups.setText(tr("Enable desktop notifications for private messages"));
mentionPopups.setText(tr("Enable desktop notification for mentions"));
roomHistory.setText(tr("Enable room message history on join"));
- ignoreAllPrivateMessagesCheckBox.setText(tr("Ignore all private messages"));
hexLabel.setText(tr("(Color is hexadecimal)"));
hexHighlightLabel.setText(tr("(Color is hexadecimal)"));
customAlertStringLabel.setText(tr("Separate words with a space, alphanumeric characters only"));
diff --git a/cockatrice/src/interface/widgets/settings_page/messages_settings_page.h b/cockatrice/src/interface/widgets/settings_page/messages_settings_page.h
index 436ebbad9..e98ae0592 100644
--- a/cockatrice/src/interface/widgets/settings_page/messages_settings_page.h
+++ b/cockatrice/src/interface/widgets/settings_page/messages_settings_page.h
@@ -40,7 +40,6 @@ private:
QCheckBox messagePopups;
QCheckBox mentionPopups;
QCheckBox roomHistory;
- QCheckBox ignoreAllPrivateMessagesCheckBox;
QGroupBox *chatGroupBox;
QGroupBox *highlightGroupBox;
QGroupBox *messageGroupBox;
diff --git a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp
index 2c6e062da..182e75aac 100644
--- a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp
@@ -20,7 +20,26 @@ enum visualDeckStoragePromptForConversionIndex
UserInterfaceSettingsPage::UserInterfaceSettingsPage()
{
- // general settings
+ // general settings and notification settings
+ notificationsEnabledCheckBox.setChecked(SettingsCache::instance().userInterface().getNotificationsEnabled());
+ connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
+ &InterfaceSettings::setNotificationsEnabled);
+ connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
+ &UserInterfaceSettingsPage::setNotificationEnabled);
+
+ specNotificationsEnabledCheckBox.setChecked(
+ SettingsCache::instance().userInterface().getSpectatorNotificationsEnabled());
+ specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().userInterface().getNotificationsEnabled());
+ connect(&specNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
+ &InterfaceSettings::setSpectatorNotificationsEnabled);
+
+ buddyConnectNotificationsEnabledCheckBox.setChecked(
+ SettingsCache::instance().userInterface().getBuddyConnectNotificationsEnabled());
+ buddyConnectNotificationsEnabledCheckBox.setEnabled(
+ SettingsCache::instance().userInterface().getNotificationsEnabled());
+ connect(&buddyConnectNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED,
+ &SettingsCache::instance().userInterface(), &InterfaceSettings::setBuddyConnectNotificationsEnabled);
+
doubleClickToPlayCheckBox.setChecked(SettingsCache::instance().userInterface().getDoubleClickToPlay());
connect(&doubleClickToPlayCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
&InterfaceSettings::setDoubleClickToPlay);
@@ -84,26 +103,6 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
generalGroupBox = new QGroupBox;
generalGroupBox->setLayout(generalGrid);
- // notification settings
- notificationsEnabledCheckBox.setChecked(SettingsCache::instance().userInterface().getNotificationsEnabled());
- connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
- &InterfaceSettings::setNotificationsEnabled);
- connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
- &UserInterfaceSettingsPage::setNotificationEnabled);
-
- specNotificationsEnabledCheckBox.setChecked(
- SettingsCache::instance().userInterface().getSpectatorNotificationsEnabled());
- specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().userInterface().getNotificationsEnabled());
- connect(&specNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
- &InterfaceSettings::setSpectatorNotificationsEnabled);
-
- buddyConnectNotificationsEnabledCheckBox.setChecked(
- SettingsCache::instance().userInterface().getBuddyConnectNotificationsEnabled());
- buddyConnectNotificationsEnabledCheckBox.setEnabled(
- SettingsCache::instance().userInterface().getNotificationsEnabled());
- connect(&buddyConnectNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED,
- &SettingsCache::instance().userInterface(), &InterfaceSettings::setBuddyConnectNotificationsEnabled);
-
auto *notificationsGrid = new QGridLayout;
notificationsGrid->addWidget(¬ificationsEnabledCheckBox, 0, 0);
notificationsGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0);
@@ -356,7 +355,6 @@ void UserInterfaceSettingsPage::retranslateUi()
notificationsEnabledCheckBox.setText(tr("Enable notifications in taskbar"));
specNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar for game events while you are spectating"));
buddyConnectNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar when users in your buddy list connect"));
-
animationGroupBox->setTitle(tr("Animation settings"));
enableAllAnimationsButton.setText(tr("&Enable all animations"));
disableAllAnimationsButton.setText(tr("&Disable all animations"));
@@ -364,7 +362,6 @@ void UserInterfaceSettingsPage::retranslateUi()
arrowDrawAnimationCheckBox.setText(tr("&Arrow draw animation"));
lifeCounterAnimationsCheckBox.setText(tr("Life counter flash"));
battlefieldFlashCheckBox.setText(tr("Battlefield flash on damage"));
-
deckEditorGroupBox->setTitle(tr("Deck editor/storage settings"));
openDeckInNewTabCheckBox.setText(tr("Open deck in new tab by default"));
visualDeckStorageInGameCheckBox.setText(tr("Use visual deck storage in game lobby"));
@@ -400,8 +397,8 @@ void UserInterfaceSettingsPage::retranslateUi()
0, CommanderBracketNames::CommanderSpellbookBracketNames);
commanderSpellbookIntegrationBracketNamingSelector.setItemText(
1, CommanderBracketNames::OfficialCommanderBracketNames);
- commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer);
+ commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer);
replayGroupBox->setTitle(tr("Replay settings"));
rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:"));
rewindBufferingMsBox.setSuffix(" ms");
diff --git a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h
index e8a30fb1f..0dc4cf4e8 100644
--- a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h
+++ b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h
@@ -23,6 +23,9 @@ private slots:
void updateCommanderSpellbookUiState();
private:
+ QCheckBox notificationsEnabledCheckBox;
+ QCheckBox specNotificationsEnabledCheckBox;
+ QCheckBox buddyConnectNotificationsEnabledCheckBox;
QCheckBox doubleClickToPlayCheckBox;
QCheckBox clickPlaysAllSelectedCheckBox;
QCheckBox playToStackCheckBox;
@@ -34,18 +37,12 @@ private:
QCheckBox showTotalSelectionCountCheckBox;
QCheckBox useTearOffMenusCheckBox;
QCheckBox keepGameChatFocusCheckBox;
-
- QCheckBox notificationsEnabledCheckBox;
- QCheckBox specNotificationsEnabledCheckBox;
- QCheckBox buddyConnectNotificationsEnabledCheckBox;
-
QPushButton enableAllAnimationsButton;
QPushButton disableAllAnimationsButton;
QCheckBox tapAnimationCheckBox;
QCheckBox arrowDrawAnimationCheckBox;
QCheckBox lifeCounterAnimationsCheckBox;
QCheckBox battlefieldFlashCheckBox;
-
QCheckBox openDeckInNewTabCheckBox;
QLabel visualDeckStoragePromptForConversionLabel;
QComboBox visualDeckStoragePromptForConversionSelector;
@@ -60,10 +57,8 @@ private:
QLabel commanderSpellbookIntegrationUseOfficialBracketNamesLabel;
QToolButton commanderSpellbookIntegrationUseOfficialBracketNamesExplainer;
QComboBox commanderSpellbookIntegrationBracketNamingSelector;
-
QLabel rewindBufferingMsLabel;
QSpinBox rewindBufferingMsBox;
-
QGroupBox *generalGroupBox;
QGroupBox *notificationsGroupBox;
QGroupBox *animationGroupBox;
diff --git a/cockatrice/src/interface/widgets/tabs/tab_account.cpp b/cockatrice/src/interface/widgets/tabs/tab_account.cpp
index dbcf50966..410a48d40 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_account.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_account.cpp
@@ -137,11 +137,6 @@ void TabAccount::retranslateUi()
buddyList->retranslateUi();
ignoreList->retranslateUi();
userInfoBox->retranslateUi();
-
- buddyList->setToolTip(tr("Buddies are marked with a star in chat, a sound plays when they join or leave the "
- "server, and they can be invited to buddy-only games."));
- ignoreList->setToolTip(tr("Ignored users' chat messages are hidden from you, and they cannot send you private "
- "messages or join your games."));
}
void TabAccount::processListUsersResponse(const Response &response)
diff --git a/cockatrice/src/interface/widgets/tabs/tab_developer.cpp b/cockatrice/src/interface/widgets/tabs/tab_developer.cpp
index 39652ef7d..5456b86b0 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_developer.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_developer.cpp
@@ -6,15 +6,12 @@
#include "tab_developer.h"
-#include
#include
#include
#include
#include
#include
-#include
#include
-#include
#include
#include
#include
@@ -22,8 +19,6 @@
#include
#include
-static constexpr int DEFAULT_AUTO_REFRESH_INTERVAL_SECS = 30;
-
TabDeveloper::TabDeveloper(TabSupervisor *_tabSupervisor, AbstractClient *_client)
: Tab(_tabSupervisor), client(_client)
{
@@ -50,28 +45,12 @@ TabDeveloper::TabDeveloper(TabSupervisor *_tabSupervisor, AbstractClient *_clien
statusLabel = new QLabel;
- autoRefreshCheckBox = new QCheckBox;
- autoRefreshCheckBox->setChecked(false);
-
- refreshIntervalSpinBox = new QSpinBox;
- refreshIntervalSpinBox->setRange(5, 3600);
- refreshIntervalSpinBox->setValue(DEFAULT_AUTO_REFRESH_INTERVAL_SECS);
- refreshIntervalSpinBox->setEnabled(false);
-
- autoRefreshTimer = new QTimer(this);
- connect(autoRefreshTimer, &QTimer::timeout, this, &TabDeveloper::refreshClicked);
- connect(autoRefreshCheckBox, &QCheckBox::toggled, this, &TabDeveloper::autoRefreshToggled);
- connect(refreshIntervalSpinBox, QOverload::of(&QSpinBox::valueChanged), this,
- &TabDeveloper::refreshIntervalChanged);
-
refreshButton = new QPushButton;
refreshButton->setAutoDefault(true);
connect(refreshButton, &QPushButton::clicked, this, &TabDeveloper::refreshClicked);
auto *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(statusLabel, 1, Qt::AlignLeft);
- buttonLayout->addWidget(autoRefreshCheckBox, 0, Qt::AlignRight);
- buttonLayout->addWidget(refreshIntervalSpinBox, 0, Qt::AlignRight);
buttonLayout->addWidget(refreshButton, 0, Qt::AlignRight);
auto *tableLayout = new QHBoxLayout;
@@ -91,10 +70,6 @@ TabDeveloper::TabDeveloper(TabSupervisor *_tabSupervisor, AbstractClient *_clien
void TabDeveloper::retranslateUi()
{
- autoRefreshCheckBox->setText(tr("Auto-refresh"));
- autoRefreshCheckBox->setToolTip(tr("Automatically request fresh server statistics at a fixed interval."));
- refreshIntervalSpinBox->setSuffix(tr(" s"));
- refreshIntervalSpinBox->setToolTip(tr("Seconds between automatic refreshes."));
refreshButton->setText(tr("Refresh server stats"));
statsTable->setHorizontalHeaderLabels(QString(tr("Statistic;Value")).split(";"));
commandTable->setHorizontalHeaderLabels(QString(tr("Command;Count;Total ms;Avg ms")).split(";"));
@@ -151,37 +126,14 @@ void TabDeveloper::appendSeparatorRow(const QString §ionTitle)
void TabDeveloper::refreshClicked()
{
- if (requestPending) {
- return;
- }
- requestPending = true;
Command_GetServerStats cmd;
PendingCommand *pend = client->prepareDeveloperCommand(cmd);
connect(pend, &PendingCommand::finished, this, &TabDeveloper::serverStatsResponse);
client->sendCommand(pend);
}
-void TabDeveloper::autoRefreshToggled(bool checked)
-{
- refreshIntervalSpinBox->setEnabled(checked);
- if (checked) {
- refreshIntervalChanged();
- refreshClicked();
- } else {
- autoRefreshTimer->stop();
- }
-}
-
-void TabDeveloper::refreshIntervalChanged()
-{
- if (autoRefreshCheckBox->isChecked()) {
- autoRefreshTimer->start(refreshIntervalSpinBox->value() * 1000);
- }
-}
-
void TabDeveloper::serverStatsResponse(const Response &resp)
{
- requestPending = false;
if (resp.response_code() != Response::RespOk) {
statusLabel->setText(tr("No server statistics available yet."));
return;
diff --git a/cockatrice/src/interface/widgets/tabs/tab_developer.h b/cockatrice/src/interface/widgets/tabs/tab_developer.h
index 727a56bcb..fa142ae03 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_developer.h
+++ b/cockatrice/src/interface/widgets/tabs/tab_developer.h
@@ -10,12 +10,9 @@
#include "tab.h"
class AbstractClient;
-class QCheckBox;
class QLabel;
class QPushButton;
-class QSpinBox;
class QTableWidget;
-class QTimer;
class Response;
class TabDeveloper : public Tab
@@ -27,10 +24,6 @@ private:
QTableWidget *commandTable;
QPushButton *refreshButton;
QLabel *statusLabel;
- QCheckBox *autoRefreshCheckBox;
- QSpinBox *refreshIntervalSpinBox;
- QTimer *autoRefreshTimer;
- bool requestPending = false;
void appendStatRow(const QString &name, const QString &value);
void appendSeparatorRow(const QString §ionTitle);
@@ -40,8 +33,6 @@ private:
private slots:
void refreshClicked();
void serverStatsResponse(const Response &resp);
- void autoRefreshToggled(bool checked);
- void refreshIntervalChanged();
public:
explicit TabDeveloper(TabSupervisor *_tabSupervisor, AbstractClient *_client);
diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.cpp b/cockatrice/src/interface/widgets/tabs/tab_game.cpp
index 035ab1004..196ea4526 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_game.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_game.cpp
@@ -266,10 +266,6 @@ void TabGame::resetChatAndPhase()
// reset phase markers
game->getGameState()->setCurrentPhase(-1);
-
- // reset spectator state so the replay can rebuild it from the start
- game->getPlayerManager()->clearSpectators();
- playerListWidget->clearSpectators();
}
void TabGame::emitUserEvent()
diff --git a/cockatrice/src/interface/widgets/tabs/tab_message.cpp b/cockatrice/src/interface/widgets/tabs/tab_message.cpp
index 418843178..9506d96f3 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_message.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_message.cpp
@@ -98,12 +98,6 @@ void TabMessage::closeEvent(QCloseEvent *event)
void TabMessage::sendPrivateMessage(const QString &text)
{
- if (tabSupervisor->getUserListManager()->isUserIgnored(getUserName())) {
- chatView->appendMessage(tr("You have ignored %1; your messages are not delivered.")
- .arg(QString::fromStdString(otherUserInfo->name())));
- return;
- }
-
Command_Message cmd;
cmd.set_user_name(otherUserInfo->name());
cmd.set_message(text.toStdString());
diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp
index bb8ec719e..1b61bf80f 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp
@@ -117,10 +117,9 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/)
}
TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *parent)
- : QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabHome(nullptr),
- tabVisualDeckStorage(nullptr), tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr),
- tabReplays(nullptr), tabAdmin(nullptr), tabCardArtRules(nullptr), tabLog(nullptr), tabReport(nullptr),
- tabModeration(nullptr), tabDeveloper(nullptr), isLocalGame(false)
+ : QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabVisualDeckStorage(nullptr),
+ tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr), tabReplays(nullptr), tabAdmin(nullptr),
+ tabLog(nullptr), tabReport(nullptr), tabModeration(nullptr), tabDeveloper(nullptr), isLocalGame(false)
{
setElideMode(Qt::ElideRight);
setMovable(true);
@@ -251,7 +250,6 @@ void TabSupervisor::retranslateUi()
aTabLog->setText(tr("Logs"));
aTabReport->setText(tr("Report Queue"));
aTabModeration->setText(tr("Moderation"));
- aTabCardArtRules->setText(tr("Card Art Rules"));
aTabDeveloper->setText(tr("Developer"));
// tabs
@@ -264,7 +262,6 @@ void TabSupervisor::retranslateUi()
tabs.append(tabLog);
tabs.append(tabReport);
tabs.append(tabModeration);
- tabs.append(tabCardArtRules);
tabs.append(tabDeveloper);
QMapIterator roomIterator(roomTabs);
while (roomIterator.hasNext()) {
@@ -530,9 +527,7 @@ void TabSupervisor::start(const ServerInfo_User &_userInfo)
if (SettingsCache::instance().tabs().getTabModerationOpen()) {
openTabModeration();
}
- if (SettingsCache::instance().tabs().getTabCardArtRulesOpen()) {
- openTabCardArtRules();
- }
+ openTabCardArtRules();
}
if (userInfo->user_level() & ServerInfo_User::IsDeveloper) {
@@ -608,9 +603,6 @@ void TabSupervisor::stop()
if (tabModeration) {
tabModeration->close();
}
- if (tabCardArtRules) {
- tabCardArtRules->close();
- }
if (tabDeveloper) {
tabDeveloper->close();
}
@@ -807,7 +799,6 @@ void TabSupervisor::openTabAdmin()
void TabSupervisor::actTabCardArtRules(bool checked)
{
- SettingsCache::instance().tabs().setTabCardArtRulesOpen(checked);
if (checked && !tabCardArtRules) {
openTabCardArtRules();
setCurrentWidget(tabCardArtRules);
@@ -1114,13 +1105,6 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus
return tab;
}
- if (focus && userListManager->isUserIgnored(receiverName)) {
- QMessageBox::information(
- this, tr("Ignored user"),
- tr("You have ignored %1. Remove them from your ignore list to open a private chat.").arg(receiverName));
- return nullptr;
- }
-
tab = new TabMessage(this, client, *userInfo, otherUser, userOnline);
connect(tab, &TabMessage::talkClosing, this, &TabSupervisor::talkLeft);
connect(tab, &TabMessage::maximizeClient, this, &TabSupervisor::maximizeMainWindow);
@@ -1335,21 +1319,7 @@ void TabSupervisor::processGameEventContainer(const GameEventContainer &cont)
void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event)
{
- // "Ignore all private messages" silences every PM, including messages to
- // already-open tabs — unlike the unregistered/non-buddy filters below,
- // which only apply when creating a new tab. Messages from moderators/admins
- // are exempt to ensure warnings still reach users.
QString senderName = QString::fromStdString(event.sender_name());
- if (SettingsCache::instance().chat().getIgnoreAllPrivateMessages()) {
- const ServerInfo_User *onlineUserInfo = userListManager->getOnlineUser(senderName);
- if (!onlineUserInfo) {
- return;
- }
- const UserLevelFlags userLevel(onlineUserInfo->user_level());
- if (!userLevel.testFlag(ServerInfo_User::IsModerator) && !userLevel.testFlag(ServerInfo_User::IsAdmin)) {
- return;
- }
- }
TabMessage *tab = messageTabs.value(senderName);
if (!tab) {
tab = messageTabs.value(QString::fromStdString(event.receiver_name()));
diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
index 0f43893d3..209a30642 100644
--- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
+++ b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
@@ -4,7 +4,6 @@
#include "../../../../client/settings/shortcuts_settings.h"
#include "../../cards/card_info_display_widget.h"
#include "../../deck_editor/deck_state_manager.h"
-#include "../../deck_editor/deck_zone_dialog.h"
#include "../../filters/filter_builder.h"
#include "../../interface/pixel_map_generator.h"
#include "../../interface/widgets/cards/card_info_frame_widget.h"
@@ -85,7 +84,6 @@ void TabDeckEditorVisual::createCentralFrame()
connect(tabContainer, &TabDeckEditorVisualTabWidget::printingSelectorRequested, this,
&TabDeckEditorVisual::showPrintingSelector);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardInfoRequested, this, &TabDeckEditorVisual::updateCardInfo);
- tabContainer->visualDatabaseDisplay->setNewZoneCreator([this] { return createNewZone(); });
centralFrame->addWidget(tabContainer);
setCentralWidget(centralWidget);
@@ -271,19 +269,6 @@ bool TabDeckEditorVisual::actSaveDeckAs()
return result;
}
-/** @brief Prompts for and creates a new custom deck zone. Returns the name of the created zone. */
-QString TabDeckEditorVisual::createNewZone()
-{
- QString boardName;
- const QString zoneName = DeckZoneDialog::promptForNewZone(this, {}, &boardName, [this](const QString &candidate) {
- return deckStateManager->validateNewZoneName(candidate);
- });
- if (!zoneName.isEmpty()) {
- deckStateManager->createCustomZone(boardName, zoneName);
- }
- return zoneName;
-}
-
/** @brief Refreshes keyboard shortcuts for this tab from settings. */
void TabDeckEditorVisual::refreshShortcuts()
{
diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h
index fb09578c4..21335d2d0 100644
--- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h
+++ b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h
@@ -165,12 +165,6 @@ public slots:
*/
bool actSaveDeckAs() override;
- /**
- * @brief Prompts for and creates a new custom deck zone.
- * @return The name of the created zone, or an empty string if creation was cancelled.
- */
- QString createNewZone();
-
private:
/**
* @brief Sets the deck for this tab and selects the sub-tab to open on
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
index 76bbf344b..0cdf60d5d 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
@@ -21,7 +21,6 @@
#include
#include
#include
-#include
#include
#include
@@ -90,19 +89,6 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
databaseView->setItemDelegate(nullptr);
databaseView->setVisible(false);
- // Without a deck model there is nothing to add cards to, so the zone menu stays hidden.
- if (deckListModel) {
- databaseView->setZoneMenuProvider(
- [deckListModel]() -> QList> {
- QList> result;
- for (const QString &boardName : InnerDecklistNode::boardZoneNames()) {
- result.append({boardName, deckListModel->getCustomZoneNames(boardName)});
- }
- return result;
- },
- [this] { return newZoneCreator ? newZoneCreator() : QString(); });
- }
-
searchEdit->setTreeView(databaseView);
searchEdit->installEventFilter(databaseView->getKeySignals());
@@ -209,11 +195,6 @@ void VisualDatabaseDisplayWidget::showEvent(QShowEvent *event)
initializeFilters();
}
-void VisualDatabaseDisplayWidget::setNewZoneCreator(const std::function &creator)
-{
- newZoneCreator = creator;
-}
-
void VisualDatabaseDisplayWidget::retranslateUi()
{
databaseLoadIndicator->setText(tr("Loading database ..."));
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h
index d161ce362..6e4d87876 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h
@@ -22,7 +22,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -47,12 +46,6 @@ public:
void sortCardList(const QStringList &properties, Qt::SortOrder order) const;
void setDeckList(const DeckList &new_deck_list_model);
- /**
- * @brief Sets the callback used to create a custom zone from the add-to-zone menu.
- * The callback returns the name of the created zone, or an empty string if creation was cancelled.
- */
- void setNewZoneCreator(const std::function &creator);
-
CardDatabaseDisplayModel *getDatabaseDisplayModel()
{
return databaseDisplayModel;
@@ -113,7 +106,6 @@ private:
VisualDatabaseDisplayFilterToolbarWidget *filterContainer;
CardDatabaseDisplayModel *databaseDisplayModel;
CardDatabaseView *databaseView;
- std::function newZoneCreator;
QList *cards;
QVBoxLayout *mainLayout;
QScrollArea *scrollArea;
diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
index 22d73b604..fbaabf90f 100644
--- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
@@ -125,7 +125,9 @@ void VisualDeckStorageFolderDisplayWidget::continueDeckPass()
}
const bool matches = index.data(VisualDeckStorageRoles::FilterMatchRole).toBool();
- deckPreviewWidget->setVisible(matches);
+ if (matches == deckPreviewWidget->isHidden()) {
+ deckPreviewWidget->setVisible(matches);
+ }
if (matches) {
++visibleDeckCount;
}
diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp
index 43f1de9dd..4567991c8 100644
--- a/cockatrice/src/interface/window_main.cpp
+++ b/cockatrice/src/interface/window_main.cpp
@@ -682,7 +682,6 @@ void MainWindow::runFirstRunWizard()
connect(wizard, &FirstRunWizard::cardDatabaseUpdateRequested, this, &MainWindow::actCheckCardUpdatesBackground);
connect(wizard, &FirstRunWizard::manualCardDatabaseSetupRequested, this, &MainWindow::actCheckCardUpdates);
connect(this, &MainWindow::cardDatabaseUpdateFinished, wizard, &FirstRunWizard::onCardDatabaseUpdateFinished);
- connect(this, &MainWindow::cardDatabaseUpdateProgress, wizard, &FirstRunWizard::onCardDatabaseUpdateProgress);
connect(wizard, &FirstRunWizard::registerRequested, connectionController, &ConnectionController::registerToServer);
connect(wizard, &FirstRunWizard::connectRequested, connectionController, &ConnectionController::connectToServer);
@@ -844,17 +843,6 @@ void MainWindow::closeEvent(QCloseEvent *event)
}
bClosingDown = true;
- if (cardUpdateProcess && cardUpdateProcess->state() != QProcess::NotRunning) {
- if (QMessageBox::question(this, tr("Are you sure?"),
- tr("A card database update is still running. Quitting now will cancel it.\n"
- "Are you sure you want to quit?"),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
- event->ignore();
- bClosingDown = false;
- return;
- }
- }
-
if (!tabSupervisor->close()) {
event->ignore();
bClosingDown = false;
@@ -1069,45 +1057,11 @@ void MainWindow::createCardUpdateProcess(bool background)
if (!background) {
cardUpdateProcess->start(updaterCmd, QStringList());
} else {
- cardUpdateOutputBuffer.clear();
- connect(cardUpdateProcess, &QProcess::readyReadStandardOutput, this, &MainWindow::cardUpdateProgressOutput);
cardUpdateProcess->start(updaterCmd, QStringList("-b"));
statusBar()->showMessage(tr("Card database update running."));
}
}
-void MainWindow::cardUpdateProgressOutput()
-{
- if (!cardUpdateProcess) {
- return;
- }
- cardUpdateOutputBuffer.append(cardUpdateProcess->readAllStandardOutput());
- while (true) {
- const int newline = cardUpdateOutputBuffer.indexOf('\n');
- if (newline < 0) {
- break;
- }
- const QByteArray line = cardUpdateOutputBuffer.left(newline).trimmed();
- cardUpdateOutputBuffer.remove(0, newline + 1);
- // Protocol emitted by `oracle -b`: "PROGRESS "
- if (!line.startsWith("PROGRESS ")) {
- continue;
- }
- const QList parts = line.split(' ');
- if (parts.size() != 4) {
- continue;
- }
- bool doneOk = false;
- bool totalOk = false;
- const qint64 done = parts.at(2).toLongLong(&doneOk);
- const qint64 total = parts.at(3).toLongLong(&totalOk);
- if (!doneOk || !totalOk || done < 0 || total < 0) {
- continue;
- }
- emit cardDatabaseUpdateProgress(QString::fromLatin1(parts.at(1)), done, total);
- }
-}
-
void MainWindow::exitCardDatabaseUpdate()
{
if (!cardUpdateProcess) {
@@ -1155,8 +1109,6 @@ void MainWindow::cardUpdateError(QProcess::ProcessError err)
void MainWindow::cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
- cardUpdateProgressOutput(); // drain any progress lines not yet parsed
-
const bool success = (exitStatus == QProcess::NormalExit) && (exitCode == 0);
if (exitStatus == QProcess::NormalExit) {
SettingsCache::instance().updates().setLastCardUpdateCheck(QDateTime::currentDateTime().date());
diff --git a/cockatrice/src/interface/window_main.h b/cockatrice/src/interface/window_main.h
index 08481fd36..920145552 100644
--- a/cockatrice/src/interface/window_main.h
+++ b/cockatrice/src/interface/window_main.h
@@ -68,11 +68,6 @@ signals:
/** @brief Emitted after the background card-database update subprocess exits. */
void cardDatabaseUpdateFinished(bool success);
- /** @brief Emitted while the background card-database update subprocess runs.
- * @p stage is one of "download", "scan" or "import"; @p done/@p total
- * are byte counts for the first two stages and set indices for "import". */
- void cardDatabaseUpdateProgress(const QString &stage, qint64 done, qint64 total);
-
public slots:
void actCheckCardUpdates();
void actCheckCardUpdatesBackground();
@@ -101,7 +96,6 @@ private slots:
void cardUpdateError(QProcess::ProcessError err);
void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus);
- void cardUpdateProgressOutput();
void refreshShortcuts();
void cardDatabaseLoadingFailed();
void cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames);
@@ -165,7 +159,6 @@ private:
LatencyStatusWidget *latencyStatus = nullptr; ///< status bar widget with live round-trip stats and history graph
bool bHasActivated, askedForDbUpdater;
QProcess *cardUpdateProcess;
- QByteArray cardUpdateOutputBuffer;
DlgViewLog *logviewDialog;
GameReplay *replay;
DlgTipOfTheDay *tip;
diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp
index d8aa1cd08..84d5d175f 100644
--- a/cockatrice/src/main.cpp
+++ b/cockatrice/src/main.cpp
@@ -53,7 +53,6 @@
#include
#include
#include
-#include
QTranslator *translator, *qtTranslator;
RNG_Abstract *rng;
@@ -293,7 +292,7 @@ int main(int argc, char *argv[])
}
}
- rng = new RNG_SFMT(CryptoUtil::randomUInt64());
+ rng = new RNG_SFMT;
themeManager = new ThemeManager;
soundEngine = new SoundEngine;
diff --git a/format.sh b/format.sh
index 9e3a6069b..3fa435be1 100755
--- a/format.sh
+++ b/format.sh
@@ -18,11 +18,11 @@ include=("cockatrice/src" \
libcockatrice_* \
"oracle/src" \
"servatrice/src" \
-"cmake/pch" \
"tests")
exclude=("libcockatrice_rng/libcockatrice/rng/sfmt/" \
"libcockatrice_utility/libcockatrice/utility/peglib.h" \
"oracle/src/lzma/" \
+"oracle/src/qt-json/" \
"oracle/src/zip/" \
"servatrice/src/smtp/")
exts=("cpp" "h" "proto")
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h
index 5d91cd233..af1193f26 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.h
@@ -115,25 +115,6 @@ public:
*/
QList getCustomZones(const QString &boardZoneName) const;
- /**
- * @brief Checks whether a zone name is taken anywhere in the deck.
- *
- * Covers the standard board names and any top-level or nested custom zone.
- * @param zoneName The checked name.
- * @return true if the name is reserved or already in use.
- */
- bool hasZoneName(const QString &zoneName) const;
-
- /**
- * @brief Finds a custom zone anywhere in the deck by name.
- *
- * Walks the children of every top-level zone, so a zone nested under any
- * board (and not just the standard ones) is found.
- * @param zoneName The zone name to find.
- * @return The matching zone node, or nullptr if none exists.
- */
- InnerDecklistNode *findCustomZoneByName(const QString &zoneName) const;
-
/**
* @brief Applies a function to every card in the deck tree. This can modify the cards.
*
@@ -147,6 +128,8 @@ private:
InnerDecklistNode *getZoneObjFromName(const QString &zoneName) const;
InnerDecklistNode *findBoardZone(const QString &boardZoneName) const;
InnerDecklistNode *findOrCreateBoardZone(const QString &boardZoneName);
+ InnerDecklistNode *findCustomZoneByName(const QString &zoneName) const;
+ bool hasZoneName(const QString &zoneName) const;
};
#endif // COCKATRICE_DECKLIST_NODE_TREE_H
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp
index d082b3cca..ec860dc56 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.cpp
@@ -43,13 +43,6 @@ void InnerDecklistNode::setSortMethod(DeckSortMethod method)
}
}
-const QList &InnerDecklistNode::boardZoneNames()
-{
- static const QList names = {QString(DECK_ZONE_MAIN), QString(DECK_ZONE_SIDE),
- QString(DECK_ZONE_MAYBEBOARD)};
- return names;
-}
-
QString InnerDecklistNode::getVisibleName() const
{
return visibleNameFromName(name);
@@ -94,9 +87,6 @@ AbstractDecklistNode *InnerDecklistNode::findCardChildByNameProviderIdAndNumber(
int InnerDecklistNode::height() const
{
- if (isEmpty()) {
- return 1;
- }
return at(0)->height() + 1;
}
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h
index 0d454c11e..906ed6cb5 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/tree/inner_deck_list_node.h
@@ -18,9 +18,6 @@
#include "abstract_deck_list_node.h"
-#include
-#include
-
/** @brief Constant for the "main" deck zone name. */
#define DECK_ZONE_MAIN "main"
/** @brief Constant for the "sideboard" zone name. */
@@ -121,13 +118,6 @@ public:
*/
static QString visibleNameFromName(const QString &_name);
- /**
- * @brief The standard board zone names, in display order.
- *
- * @return main, side and maybeboard.
- */
- static const QList &boardZoneNames();
-
/**
* @brief Get this node’s display-friendly name.
* @return Human-readable name (zone/group name).
diff --git a/libcockatrice_filters/libcockatrice/filters/filter_string.cpp b/libcockatrice_filters/libcockatrice/filters/filter_string.cpp
index aaf391c03..25e8e97db 100644
--- a/libcockatrice_filters/libcockatrice/filters/filter_string.cpp
+++ b/libcockatrice_filters/libcockatrice/filters/filter_string.cpp
@@ -5,7 +5,6 @@
#include
#include
#include
-#include
#include
static peg::parser search(R"(
@@ -20,7 +19,7 @@ SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQuery / ToughnessQuery / ColorQuery / TypeQuery / OracleQuery / FieldQuery / GenericQuery
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
-SetQuery <- ('e'/'set') SetExpression / ([:] FlexStringValue)
+SetQuery <- ('e'/'set') [:] FlexStringValue
OracleQuery <- 'o' [:] MatcherString
@@ -65,8 +64,6 @@ RegexMatcherString <- ('\\/' / !'/' .)+
FlexStringValue <- CompactStringSet / String / [(] StringList [)]
CompactStringSet <- StringListString ([,+] StringListString)+
-SetExpression <- NumericOperator ws? String
-
NumericExpression <- NumericOperator ws? NumericValue
NumericOperator <- [=:] / <[>
NumericValue <- [0-9]+
@@ -104,25 +101,12 @@ static void setupParserRules()
return [=](const CardData &x) -> bool { return matcher(x->getCardType()); };
};
search["SetQuery"] = [](const peg::SemanticValues &sv) -> Filter {
- if (sv.choice() == 1) {
- auto matcher = std::any_cast(sv[0]);
- return [=](const CardData &x) -> bool {
- QList sets = x->getSets().keys();
-
- auto matchesSet = [&matcher](const QString &set) { return matcher(set); };
- return std::any_of(sets.begin(), sets.end(), matchesSet);
- };
- }
-
- auto matcher = std::any_cast(sv[0]);
+ auto matcher = std::any_cast(sv[0]);
return [=](const CardData &x) -> bool {
- const auto &sets = x->getSets().values();
- auto matchesSet = [&](const PrintingInfo &printing) {
- return printing.getSet()->getEnabled() && matcher(printing.getSet()->getReleaseDate().toJulianDay());
- };
- return std::any_of(sets.begin(), sets.end(), [&](const auto &printings) {
- return std::any_of(printings.begin(), printings.end(), matchesSet);
- });
+ QList sets = x->getSets().keys();
+
+ auto matchesSet = [&matcher](const QString &set) { return matcher(set); };
+ return std::any_of(sets.begin(), sets.end(), matchesSet);
};
};
search["Rarity"] = [](const peg::SemanticValues &sv) -> QString {
@@ -263,54 +247,40 @@ static void setupParserRules()
return QString::fromStdString(std::string(sv.sv()));
};
- search["NumericOperator"] = [](const peg::SemanticValues &sv) -> NumberComparer {
- const auto op = QString::fromStdString(std::string(sv.sv()));
+ search["NumericExpression"] = [](const peg::SemanticValues &sv) -> NumberMatcher {
+ const auto arg = std::any_cast(sv[1]);
+ const auto op = std::any_cast(sv[0]);
if (op == ">") {
- return [=](const int s, const int arg) { return s > arg; };
+ return [=](const int s) { return s > arg; };
}
if (op == ">=") {
- return [=](const int s, const int arg) { return s >= arg; };
+ return [=](const int s) { return s >= arg; };
}
if (op == "<") {
- return [=](const int s, const int arg) { return s < arg; };
+ return [=](const int s) { return s < arg; };
}
if (op == "<=") {
- return [=](const int s, const int arg) { return s <= arg; };
+ return [=](const int s) { return s <= arg; };
}
if (op == "=") {
- return [=](const int s, const int arg) { return s == arg; };
+ return [=](const int s) { return s == arg; };
}
if (op == ":") {
- return [=](const int s, const int arg) { return s == arg; };
+ return [=](const int s) { return s == arg; };
}
if (op == "!=") {
- return [=](const int s, const int arg) { return s != arg; };
+ return [=](const int s) { return s != arg; };
}
- return [](int, int) { return false; };
+ return [](int) { return false; };
};
search["NumericValue"] = [](const peg::SemanticValues &sv) -> int {
return QString::fromStdString(std::string(sv.sv())).toInt();
};
- search["NumericExpression"] = [](const peg::SemanticValues &sv) -> NumberMatcher {
- const auto comparer = std::any_cast(sv[0]);
- const auto arg = std::any_cast(sv[1]);
- return [=](int s) { return comparer(s, arg); };
- };
-
- search["SetExpression"] = [](const peg::SemanticValues &sv) -> NumberMatcher {
- const auto comparer = std::any_cast(sv[0]);
- const auto setCode = std::any_cast(sv[1]);
- const auto allSets = CardDatabaseManager::getInstance()->getSetList();
- for (auto &set : allSets) {
- if (set->getShortName() == setCode) {
- const int releaseDate = set->getReleaseDate().toJulianDay();
- return [=](int s) { return comparer(s, releaseDate); };
- }
- }
- return [](int) { return false; };
+ search["NumericOperator"] = [](const peg::SemanticValues &sv) -> QString {
+ return QString::fromStdString(std::string(sv.sv()));
};
search["NormalMatcher"] = [](const peg::SemanticValues &sv) -> StringMatcher {
diff --git a/libcockatrice_filters/libcockatrice/filters/filter_string.h b/libcockatrice_filters/libcockatrice/filters/filter_string.h
index a058f7d07..71a99f7b5 100644
--- a/libcockatrice_filters/libcockatrice/filters/filter_string.h
+++ b/libcockatrice_filters/libcockatrice/filters/filter_string.h
@@ -22,7 +22,6 @@ typedef CardInfoPtr CardData;
typedef std::function Filter;
typedef std::function StringMatcher;
typedef std::function NumberMatcher;
-typedef std::function NumberComparer;
namespace peg
{
diff --git a/libcockatrice_interfaces/libcockatrice/interfaces/interface_chat_settings_provider.h b/libcockatrice_interfaces/libcockatrice/interfaces/interface_chat_settings_provider.h
index cdf2da5eb..cd9ad29e1 100644
--- a/libcockatrice_interfaces/libcockatrice/interfaces/interface_chat_settings_provider.h
+++ b/libcockatrice_interfaces/libcockatrice/interfaces/interface_chat_settings_provider.h
@@ -20,7 +20,6 @@ public:
[[nodiscard]] virtual bool getShowMessagePopup() const = 0;
[[nodiscard]] virtual bool getShowMentionPopup() const = 0;
[[nodiscard]] virtual bool getRoomHistory() const = 0;
- [[nodiscard]] virtual bool getIgnoreAllPrivateMessages() const = 0;
[[nodiscard]] virtual QString getHighlightWords() const = 0;
};
diff --git a/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h b/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h
index 054c4cd72..a81616cb0 100644
--- a/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h
+++ b/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h
@@ -21,7 +21,6 @@ public:
[[nodiscard]] virtual bool getTabLogOpen() const = 0;
[[nodiscard]] virtual bool getTabReportOpen() const = 0;
[[nodiscard]] virtual bool getTabModerationOpen() const = 0;
- [[nodiscard]] virtual bool getTabCardArtRulesOpen() const = 0;
};
#endif // COCKATRICE_INTERFACE_TABS_SETTINGS_PROVIDER_H
diff --git a/libcockatrice_models/libcockatrice/models/deck_list/CMakeLists.txt b/libcockatrice_models/libcockatrice/models/deck_list/CMakeLists.txt
index a6ab2a204..d4aee3686 100644
--- a/libcockatrice_models/libcockatrice/models/deck_list/CMakeLists.txt
+++ b/libcockatrice_models/libcockatrice/models/deck_list/CMakeLists.txt
@@ -7,8 +7,7 @@ set(HEADERS deck_list_model.h deck_list_sort_filter_proxy_model.h)
qt6_wrap_cpp(MOC_SOURCES ${HEADERS})
add_library(
- libcockatrice_models_deck_list STATIC ${MOC_SOURCES} deck_list_model.cpp deck_list_model_custom_zones.cpp
- deck_list_sort_filter_proxy_model.cpp
+ libcockatrice_models_deck_list STATIC ${MOC_SOURCES} deck_list_model.cpp deck_list_sort_filter_proxy_model.cpp
)
target_include_directories(libcockatrice_models_deck_list PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp b/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp
index 76afca0c4..9b43281c1 100644
--- a/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp
+++ b/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp
@@ -66,8 +66,7 @@ void DeckListModel::rebuildTree()
for (int j = 0; j < currentZone->size(); j++) {
auto *currentCard = dynamic_cast(currentZone->at(j));
- // Non-card children are custom zones; they are mirrored in a single
- // pass below so each is mirrored exactly once.
+ //! \todo Better sanity checking.
if (currentCard == nullptr) {
continue;
}
@@ -83,19 +82,8 @@ void DeckListModel::rebuildTree()
new DecklistModelCardNode(currentCard, groupNode);
}
-
- // Custom zones nested under the board zone are mirrored as-is, with their
- // cards as direct children (no further grouping).
- DeckListModelCustomZones::mirrorCustomZones(currentZone, node);
}
- // The shadow tree was built in deck file order. Apply the active sort while
- // the reset is still open so every consumer (tree view and visual editor)
- // sees the canonical order from the start. sortShadowTree emits no signals,
- // which is only valid before endResetModel closes the reset.
- root->setSortMethod(lastKnownColumn == 0 ? DeckSortMethod::ByNumber : DeckSortMethod::ByName);
- sortShadowTree(root, lastKnownOrder);
-
endResetModel();
refreshCardFormatLegalities();
@@ -166,9 +154,6 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const
case DeckRoles::IsLegalRole:
return true;
- case DeckRoles::IsCustomZoneRole:
- return DeckListModelCustomZones::isCustomZone(group);
-
default:
return {};
}
@@ -205,10 +190,6 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const
return card->getFormatLegality();
}
- case DeckRoles::IsCustomZoneRole: {
- return false;
- }
-
default: {
return {};
}
@@ -346,13 +327,6 @@ bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent)
return false;
}
- // Custom zone rows are managed through the deck tree, never removed as model rows.
- for (int i = 0; i < count; i++) {
- if (DeckListModelCustomZones::isCustomZone(node->at(row + i))) {
- return false;
- }
- }
-
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++) {
AbstractDecklistNode *toDelete = node->takeAt(row);
@@ -363,8 +337,7 @@ bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent)
}
endRemoveRows();
- // Empty criteria groups get pruned, but custom zones stay until explicitly deleted.
- if (node->empty() && (node != root) && !DeckListModelCustomZones::isCustomZone(node)) {
+ if (node->empty() && (node != root)) {
removeRows(parent.row(), 1, parent.parent());
} else {
emitRecursiveUpdates(parent);
@@ -378,8 +351,7 @@ bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent)
InnerDecklistNode *DeckListModel::createNodeIfNeeded(const QString &name, InnerDecklistNode *parent)
{
- // Group lookups must not resolve a mirrored custom zone that shares the name.
- auto *newNode = DeckListModelCustomZones::findGroupChild(parent, name);
+ auto *newNode = dynamic_cast(parent->findChild(name));
if (!newNode) {
beginInsertRows(nodeToIndex(parent), parent->size(), parent->size());
newNode = new InnerDecklistNode(name, parent);
@@ -393,44 +365,24 @@ DecklistModelCardNode *DeckListModel::findCardNode(const QString &cardName,
const QString &providerId,
const QString &cardNumber) const
{
+ InnerDecklistNode *zoneNode = dynamic_cast(root->findChild(zoneName));
+ if (!zoneNode) {
+ return nullptr;
+ }
+
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(cardName);
if (!info) {
return nullptr;
}
- // 1. Board zone lookup: search the criteria groups, then the custom zones
- // nested under the board.
- if (auto *zoneNode = dynamic_cast(root->findChild(zoneName))) {
- QString groupCriteria = extractGroupCriteriaValue(info, activeGroupCriteria);
- if (auto *groupNode = DeckListModelCustomZones::findGroupChild(zoneNode, groupCriteria)) {
- if (auto *card = dynamic_cast(
- groupNode->findCardChildByNameProviderIdAndNumber(cardName, providerId, cardNumber))) {
- return card;
- }
- }
-
- for (auto *child : *zoneNode) {
- if (!DeckListModelCustomZones::isCustomZone(child)) {
- continue;
- }
- auto *customZone = dynamic_cast(child);
- if (!customZone) {
- continue;
- }
- if (auto *card = dynamic_cast(
- customZone->findCardChildByNameProviderIdAndNumber(cardName, providerId, cardNumber))) {
- return card;
- }
- }
+ QString groupCriteria = extractGroupCriteriaValue(info, activeGroupCriteria);
+ InnerDecklistNode *groupNode = dynamic_cast(zoneNode->findChild(groupCriteria));
+ if (!groupNode) {
+ return nullptr;
}
- // 2. Custom zone lookup by name (custom zone names are deck-unique).
- if (auto *customZone = DeckListModelCustomZones::findSubZoneByName(root, zoneName)) {
- return dynamic_cast(
- customZone->findCardChildByNameProviderIdAndNumber(cardName, providerId, cardNumber));
- }
-
- return nullptr;
+ return dynamic_cast