diff --git a/.ci/compile.sh b/.ci/compile.sh
index ee846897b..8a16d3243 100755
--- a/.ci/compile.sh
+++ b/.ci/compile.sh
@@ -159,6 +159,7 @@ if [[ $PACKAGE_TYPE ]]; then
fi
if [[ $USE_VCPKG ]]; then
flags+=("-DUSE_VCPKG=1")
+ flags+=("-DVCPKG_INSTALL_OPTIONS=--x-abi-tools-use-exact-versions")
fi
# Add cmake --build flags
diff --git a/.codacy.yml b/.codacy.yml
deleted file mode 100644
index f9482da2f..000000000
--- a/.codacy.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-exclude_paths:
- - '**/translations/*.ts'
-
-# codacy config documentation: https://support.codacy.com/hc/en-us/articles/115002130625-Codacy-Configuration-File
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 56ad64283..589cae1d8 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -334,7 +334,7 @@ the tr() call, also you can add an extra string as a hint for translators:
QString message = tr("Everyone draws %n cards", "english hint for translators", amount);
```
See [Qt's wiki on translations](
-https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
+https://doc.qt.io/qt-6/i18n-source-translation.html#handling-plurals)
If you're about to propose a change that adds or modifies any translatable
string in the code, you don't need to take care of adding the new strings to
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index e18892fa5..c5526049c 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -3,7 +3,7 @@ name: Build Desktop
permissions:
actions: write # needed to delete entries in GHA cache (update ccache)
attestations: write # needed to persist the attestation.
- contents: write
+ contents: write # needed for e.g. vcpkg dependency graph updates
id-token: write # needed for signing certificate in attestation
on:
@@ -42,7 +42,7 @@ concurrency:
jobs:
configure:
name: Configure
- runs-on: ubuntu-slim
+ runs-on: ubuntu-slim # https://github.com/actions/runner-images/blob/main/images/ubuntu-slim/ubuntu-slim-Readme.md
outputs:
tag: ${{ steps.configure.outputs.tag }}
sha: ${{ steps.configure.outputs.sha }}
@@ -146,7 +146,7 @@ jobs:
name: ${{ matrix.distro }} ${{ matrix.version }}
needs: configure
- runs-on: ubuntu-latest
+ runs-on: ubuntu-latest # https://github.com/actions/runner-images
continue-on-error: ${{ matrix.allow-failure == 'yes' }}
timeout-minutes: 70
env:
@@ -262,84 +262,80 @@ jobs:
matrix:
include:
- os: macOS
- target: 13
- runner: macos-15-intel
+ target: 13 # EOL 2025-09-15
+ runner: macos-15-intel # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
override_target: 13
package_suffix: "-macOS13_Intel"
- qt_arch: clang_64
qt_archives: qtbase qtimageformats qtmultimedia qtsvg qttools qttranslations
qt_modules: qtwebsockets
- qt_version: 6.11.0
+ qt_version: 6.11.1
soc: Intel
type: Release
use_ccache: 1
- xcode: "16.4"
+ xcode: "26.3"
- os: macOS
- target: 14
- runner: macos-14
+ target: 14 # EOL 2026-??
+ runner: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
+ override_target: 14
package_suffix: "-macOS14"
- qt_arch: clang_64
qt_archives: qtbase qtimageformats qtmultimedia qtsvg qttools qttranslations
qt_modules: qtwebsockets
- qt_version: 6.11.0
+ qt_version: 6.11.1
soc: Apple
type: Release
use_ccache: 1
- xcode: "15.4"
+ xcode: "26.3"
- os: macOS
target: 15
- runner: macos-15
+ runner: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
package_suffix: "-macOS15"
- qt_arch: clang_64
qt_archives: qtbase qtimageformats qtmultimedia qtsvg qttools qttranslations
qt_modules: qtwebsockets
- qt_version: 6.11.0
+ qt_version: 6.11.1
soc: Apple
type: Release
use_ccache: 1
- xcode: "16.4"
+ xcode: "26.3"
- os: macOS
target: 15
- runner: macos-15
+ runner: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
- qt_arch: clang_64
qt_archives: qtbase qtimageformats qtmultimedia qtsvg qttools qttranslations
qt_modules: qtwebsockets
- qt_version: 6.11.0
+ qt_version: 6.11.1
soc: Apple
type: Debug
use_ccache: 1
- xcode: "16.4"
+ xcode: "26.3"
- os: Windows
target: 10
- runner: windows-2025
+ runner: windows-2025 # https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-VS2026-Readme.md
cmake_generator: "Visual Studio 18 2026"
cmake_generator_platform: x64
make_package: 1
package_suffix: "-Win10"
- qt_arch: win64_msvc2022_64
qt_archives: qtbase qtimageformats qtmultimedia qtsvg qttools qttranslations
qt_modules: qtwebsockets
- qt_version: 6.11.0
+ qt_version: 6.11.1
type: Release
name: ${{ matrix.os }} ${{ matrix.target }}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
@@ -403,7 +399,6 @@ jobs:
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
uses: jurplel/install-qt-action@v4
with:
- arch: ${{ matrix.qt_arch }}
archives: ${{ matrix.qt_archives }}
cache: false
dir: ${{ github.workspace }}
@@ -427,7 +422,6 @@ jobs:
with:
# Qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released
aqtsource: git+https://github.com/miurahr/aqtinstall.git
- arch: ${{ matrix.qt_arch }}
archives: ${{ matrix.qt_archives }}
cache: true
modules: ${{ matrix.qt_modules }}
@@ -454,6 +448,7 @@ jobs:
CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
CMAKE_GENERATOR_PLATFORM: ${{ matrix.cmake_generator_platform }}
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
+ GITHUB_TOKEN: ${{ github.token }} # needed for vcpkg dependency graph updates, see VCPKG_FEATURE_FLAGS
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
@@ -464,6 +459,7 @@ jobs:
USE_CCACHE: ${{ matrix.use_ccache }}
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
VCPKG_DISABLE_METRICS: 1
+ VCPKG_FEATURE_FLAGS: dependencygraph
run: .ci/compile.sh --server --test --vcpkg
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
index b479322d0..5384c9e64 100644
--- a/.github/workflows/docker-release.yml
+++ b/.github/workflows/docker-release.yml
@@ -56,8 +56,9 @@ jobs:
- name: "Set up Docker buildx"
uses: docker/setup-buildx-action@v4
- - name: "Login to GitHub Container Registry"
- if: contains(github.event.release.tag_name, 'Release') && github.event.release.target_commitish == 'master'
+ - name: "Login to GitHub Container Registry (GHCR)"
+ if: github.event_name == 'release' && github.event.release.prerelease == false
+ id: login
uses: docker/login-action@v4
with:
password: ${{ github.token }}
@@ -73,5 +74,5 @@ jobs:
context: .
labels: ${{ steps.metadata.outputs.labels }}
platforms: linux/amd64,linux/arm64
- push: ${{ github.ref_type == 'tag' }}
+ push: ${{ steps.login.outcome == 'success' }}
tags: ${{ steps.metadata.outputs.tags }}
diff --git a/.gitignore b/.gitignore
index 33c1ae31d..54939bdcf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ mysql.cnf
.DS_Store
.idea/
*.aps
+*.cache
cmake-build*
preferences
compile_commands.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c10e1db68..27fecc979 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,10 +64,11 @@ if(WIN32 OR USE_VCPKG)
else()
set(QTDIR
""
- CACHE PATH "Path to Qt (e.g. C:/Qt/5.7/msvc2015_64)"
+ CACHE PATH "Path to Qt (e.g. C:/Qt/6.4.2/msvc2019_64)"
)
message(
- WARNING "QTDIR variable is missing. Please set this variable to specify path to Qt (e.g. C:/Qt/5.7/msvc2015_64)"
+ WARNING
+ "QTDIR variable is missing. Please set this variable to specify path to Qt (e.g. C:/Qt/6.4.2/msvc2019_64)"
)
endif()
endif()
@@ -174,7 +175,7 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
-Wno-error=delete-non-virtual-dtor
-Wno-error=sign-compare
-Wno-error=missing-declarations
- -Wno-error=sfinae-incomplete # GCC 16+: Qt MOC + protobuf forward decls trigger this
+ -Wno-error=sfinae-incomplete # GCC 16+: Qt MOC + protobuf forward decls trigger this
)
foreach(FLAG ${ADDITIONAL_DEBUG_FLAGS})
@@ -280,11 +281,7 @@ if(UNIX)
if(CPACK_GENERATOR STREQUAL "RPM")
set(CPACK_RPM_PACKAGE_LICENSE "GPLv2")
set(CPACK_RPM_MAIN_COMPONENT "cockatrice")
- if(Qt6_FOUND)
- set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt6-qttools, qt6-qtsvg, qt6-qtmultimedia, qt6-qtimageformats")
- elseif(Qt5_FOUND)
- set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt5-qttools, qt5-qtsvg, qt5-qtmultimedia")
- endif()
+ set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt6-qttools, qt6-qtsvg, qt6-qtmultimedia, qt6-qtimageformats")
set(CPACK_RPM_PACKAGE_GROUP "Amusements/Games")
set(CPACK_RPM_PACKAGE_URL "http://github.com/Cockatrice/Cockatrice")
# stop directories from making package conflicts
@@ -302,12 +299,8 @@ if(UNIX)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_PACKAGE_SECTION "games")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice")
- if(Qt6_FOUND)
- set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins")
- set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libqt6sql6-mysql") # for connecting servatrice to a mysql db
- elseif(Qt5_FOUND)
- set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
- endif()
+ set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins")
+ set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libqt6sql6-mysql") # for connecting servatrice to a mysql db
endif()
endif()
elseif(WIN32)
diff --git a/Doxyfile b/Doxyfile
index fc96b5f22..9b05682cc 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -349,7 +349,7 @@ OPTIMIZE_OUTPUT_SLICE = NO
#
# Note see also the list of default file extension mappings.
-EXTENSION_MAPPING =
+EXTENSION_MAPPING = proto=C++
# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
@@ -1086,7 +1086,8 @@ FILE_PATTERNS = *.cc \
*.h++ \
*.markdown \
*.md \
- *.dox
+ *.dox \
+ *.proto
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
@@ -1103,6 +1104,7 @@ RECURSIVE = YES
EXCLUDE = build/ \
cmake/ \
+ cmake-build-debug/ \
doc/doxygen/theme/docs/ \
doc/doxygen/theme/include/ \
vcpkg/
@@ -1195,7 +1197,7 @@ INPUT_FILTER =
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by Doxygen.
-FILTER_PATTERNS =
+FILTER_PATTERNS = "*.proto=python doc/doxygen/filters/proto2cpp.py"
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will also be used to filter the input files that are used for
diff --git a/README.md b/README.md
index 9a27601cd..f22df461f 100644
--- a/README.md
+++ b/README.md
@@ -158,7 +158,6 @@ The following flags (with their non-default values) can be passed to `cmake`:
| `-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 |
-| `-DFORCE_USE_QT5=1` | Skip looking for Qt6 before trying to find Qt5 |
# Run
diff --git a/cmake/FindQtRuntime.cmake b/cmake/FindQtRuntime.cmake
index 485affe52..8a3050813 100644
--- a/cmake/FindQtRuntime.cmake
+++ b/cmake/FindQtRuntime.cmake
@@ -1,8 +1,7 @@
# Find a compatible Qt version
-# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, FORCE_USE_QT5
+# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE
# Optional Input: QT6_DIR -- Hint as to where Qt6 lives on the system
-# Optional Input: QT5_DIR -- Hint as to where Qt5 lives on the system
-# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt5, Qt6
+# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt6
# Output: SERVATRICE_QT_MODULES
# Output: COCKATRICE_QT_MODULES
# Output: ORACLE_QT_MODULES
@@ -39,69 +38,37 @@ set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_CO
)
list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS)
-if(NOT FORCE_USE_QT5)
- # Linguist is now a component in Qt6 instead of an external package
- find_package(
- Qt6 6.4.2
- COMPONENTS ${REQUIRED_QT_COMPONENTS} Linguist
- QUIET HINTS ${Qt6_DIR}
- )
+# Linguist is now a component in Qt6 instead of an external package
+find_package(
+ Qt6 6.4.2
+ COMPONENTS ${REQUIRED_QT_COMPONENTS} Linguist
+ QUIET HINTS ${Qt6_DIR}
+)
+if(NOT Qt6_FOUND)
+ message(FATAL_ERROR "No suitable version of Qt was found")
endif()
-if(Qt6_FOUND)
- set(COCKATRICE_QT_VERSION_NAME Qt6)
+set(COCKATRICE_QT_VERSION_NAME Qt6)
- list(FIND Qt6LinguistTools_TARGETS Qt6::lrelease QT6_LRELEASE_INDEX)
- if(QT6_LRELEASE_INDEX EQUAL -1)
- message(WARNING "Qt6 lrelease not found.")
- endif()
-
- list(FIND Qt6LinguistTools_TARGETS Qt6::lupdate QT6_LUPDATE_INDEX)
- if(QT6_LUPDATE_INDEX EQUAL -1)
- message(WARNING "Qt6 lupdate not found.")
- endif()
-else()
- find_package(
- Qt5 5.15.2
- COMPONENTS ${REQUIRED_QT_COMPONENTS}
- QUIET HINTS ${Qt5_DIR}
- )
- if(Qt5_FOUND)
- set(COCKATRICE_QT_VERSION_NAME Qt5)
- else()
- message(FATAL_ERROR "No suitable version of Qt was found")
- endif()
-
- # Qt5 Linguist is in a separate package
- find_package(Qt5LinguistTools QUIET)
- if(Qt5LinguistTools_FOUND)
- if(NOT Qt5_LRELEASE_EXECUTABLE)
- message(WARNING "Qt5 lrelease not found.")
- endif()
- if(NOT Qt5_LUPDATE_EXECUTABLE)
- message(WARNING "Qt5 lupdate not found.")
- endif()
- else()
- message(WARNING "Linguist Tools not found, cannot handle translations")
- endif()
+list(FIND Qt6LinguistTools_TARGETS Qt6::lrelease QT6_LRELEASE_INDEX)
+if(QT6_LRELEASE_INDEX EQUAL -1)
+ message(WARNING "Qt6 lrelease not found.")
endif()
-if(Qt5_POSITION_INDEPENDENT_CODE OR Qt6_FOUND)
- set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+list(FIND Qt6LinguistTools_TARGETS Qt6::lupdate QT6_LUPDATE_INDEX)
+if(QT6_LUPDATE_INDEX EQUAL -1)
+ message(WARNING "Qt6 lupdate not found.")
endif()
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
# Establish Qt Plugins directory & Library directories
get_target_property(QT_LIBRARY_DIR ${COCKATRICE_QT_VERSION_NAME}::Core LOCATION)
get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} DIRECTORY)
-if(Qt6_FOUND)
- get_filename_component(QT_PLUGINS_DIR "${Qt6Core_DIR}/../../../${QT6_INSTALL_PLUGINS}" ABSOLUTE)
- get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/../../.." ABSOLUTE)
- if(UNIX AND APPLE)
- # Mac needs a bit more help finding all necessary components
- list(APPEND QT_LIBRARY_DIR "/usr/local/lib")
- endif()
-elseif(Qt5_FOUND)
- get_filename_component(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins" ABSOLUTE)
- get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE)
+get_filename_component(QT_PLUGINS_DIR "${Qt6Core_DIR}/../../../${QT6_INSTALL_PLUGINS}" ABSOLUTE)
+get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/../../.." ABSOLUTE)
+if(UNIX AND APPLE)
+ # Mac needs a bit more help finding all necessary components
+ list(APPEND QT_LIBRARY_DIR "/usr/local/lib")
endif()
message(DEBUG "QT_PLUGINS_DIR = ${QT_PLUGINS_DIR}")
message(DEBUG "QT_LIBRARY_DIR = ${QT_LIBRARY_DIR}")
diff --git a/cmake/Info.plist b/cmake/Info.plist
index 614d82509..7f01befcb 100644
--- a/cmake/Info.plist
+++ b/cmake/Info.plist
@@ -1,38 +1,118 @@
-
+
+
+
+
+
+
CFBundleDevelopmentRegion
English
+
CFBundleExecutable
${MACOSX_BUNDLE_EXECUTABLE_NAME}
+
CFBundleGetInfoString
${MACOSX_BUNDLE_INFO_STRING}
+
CFBundleIconFile
${MACOSX_BUNDLE_ICON_FILE}
+
CFBundleIdentifier
${MACOSX_BUNDLE_GUI_IDENTIFIER}
+
CFBundleInfoDictionaryVersion
6.0
+
CFBundleLongVersionString
${MACOSX_BUNDLE_LONG_VERSION_STRING}
+
CFBundleName
${MACOSX_BUNDLE_BUNDLE_NAME}
+
CFBundlePackageType
APPL
+
CFBundleShortVersionString
${MACOSX_BUNDLE_SHORT_VERSION_STRING}
+
CFBundleSignature
????
+
CFBundleVersion
${MACOSX_BUNDLE_BUNDLE_VERSION}
- CSResourcesFileMapped
-
- LSRequiresCarbon
-
+
NSHumanReadableCopyright
${MACOSX_BUNDLE_COPYRIGHT}
+
NSHighResolutionCapable
+
+
+
+
+
+ UTExportedTypeDeclarations
+
+
+ UTTypeIdentifier
+ org.cockatrice.deck
+
+ UTTypeDescription
+ Cockatrice Deck
+
+ UTTypeConformsTo
+
+ public.data
+
+
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ cod
+
+
+
+
+
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ Cockatrice Deck
+
+ CFBundleTypeRole
+ Editor
+
+ LSHandlerRank
+ Default
+
+ LSItemContentTypes
+
+ org.cockatrice.deck
+
+
+
+
+
+
+
+
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ Cockatrice URL Scheme
+
+ CFBundleURLSchemes
+
+ cockatrice
+
+
+
+
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 166b807d9..ed196e501 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -36,13 +36,16 @@ set(cockatrice_SOURCES
src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp
src/interface/widgets/dialogs/dlg_forgot_password_request.cpp
src/interface/widgets/dialogs/dlg_forgot_password_reset.cpp
+ src/interface/widgets/dialogs/dlg_invite_to_game.cpp
src/interface/widgets/dialogs/dlg_load_deck.cpp
src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp
src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp
src/interface/widgets/dialogs/dlg_load_remote_deck.cpp
src/interface/widgets/dialogs/dlg_local_game_options.cpp
src/interface/widgets/dialogs/dlg_manage_sets.cpp
+ src/interface/widgets/dialogs/dlg_my_reports.cpp
src/interface/widgets/dialogs/dlg_register.cpp
+ src/interface/widgets/dialogs/dlg_report_user.cpp
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
src/interface/widgets/dialogs/dlg_settings.cpp
src/interface/widgets/dialogs/dlg_startup_card_check.cpp
@@ -83,7 +86,6 @@ set(cockatrice_SOURCES
src/game/game_state.cpp
src/game_graphics/game_view.cpp
src/game_graphics/hand_counter.cpp
- src/game/selection_subtype_tally.cpp
src/game_graphics/log/message_log_widget.cpp
src/game/phase.cpp
src/game_graphics/phases_toolbar.cpp
@@ -98,7 +100,11 @@ set(cockatrice_SOURCES
src/game_graphics/player/menu/rfg_menu.cpp
src/game_graphics/player/menu/say_menu.cpp
src/game_graphics/player/menu/sideboard_menu.cpp
+ src/game_graphics/player/menu/tally_menu.cpp
src/game_graphics/player/menu/utility_menu.cpp
+ src/game_graphics/tally/stats_tally.cpp
+ src/game_graphics/tally/subtype_tally.cpp
+ src/game_graphics/tally/tally.cpp
src/game/player/player_actions.cpp
src/game_graphics/player/player_area.cpp
src/game_graphics/player/player_dialogs.cpp
@@ -132,9 +138,19 @@ set(cockatrice_SOURCES
src/interface/card_picture_loader/card_picture_loader_worker.cpp
src/interface/card_picture_loader/card_picture_loader_worker_work.cpp
src/interface/card_picture_loader/card_picture_to_load.cpp
+ src/interface/intents/intent.cpp
+ src/interface/intents/intent.h
+ src/interface/intents/intent_open_local_deck.cpp
+ src/interface/intents/intent_open_local_deck.h
+ src/interface/intents/intent_wait_for_database_load.cpp
+ src/interface/intents/intent_wait_for_database_load.h
src/interface/layouts/flow_layout.cpp
src/interface/layouts/overlap_layout.cpp
+ src/interface/widgets/utility/card_completer_delegate.cpp
+ src/interface/widgets/utility/card_completer_styler.cpp
+ src/interface/widgets/utility/completer_utils.cpp
src/interface/widgets/utility/line_edit_completer.cpp
+ src/interface/widgets/utility/reversed_completer_model.cpp
src/interface/pixel_map_generator.cpp
src/interface/theme_config.cpp
src/interface/theme_manager.cpp
@@ -146,6 +162,7 @@ set(cockatrice_SOURCES
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
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_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
@@ -225,12 +242,19 @@ set(cockatrice_SOURCES
src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp
src/interface/widgets/printing_selector/printing_selector_card_sorting_widget.cpp
src/interface/widgets/printing_selector/set_name_and_collectors_number_display_widget.cpp
+ src/interface/widgets/playmat/playmat_collection_dialog.cpp
+ src/interface/widgets/playmat/playmat_collection_dialog.h
+ src/interface/widgets/playmat/playmat_preview_widget.cpp
+ src/interface/widgets/playmat/playmat_settings_dialog.cpp
src/interface/widgets/quick_settings/settings_button_widget.cpp
src/interface/widgets/quick_settings/settings_popup_widget.cpp
src/interface/widgets/replay/replay_manager.cpp
+ src/interface/widgets/replay/replay_quick_settings_widget.cpp
src/interface/widgets/replay/replay_timeline_widget.cpp
+ src/interface/widgets/replay/replay_widget.cpp
src/interface/widgets/server/chat_view/chat_view.cpp
src/interface/widgets/server/game_filter_configs.cpp
+ src/interface/widgets/server/game_link.cpp
src/interface/widgets/server/game_selector.cpp
src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
src/interface/widgets/server/games_model.cpp
@@ -245,17 +269,23 @@ set(cockatrice_SOURCES
src/interface/widgets/server/user/user_info_connection.cpp
src/interface/widgets/server/user/user_list_manager.cpp
src/interface/widgets/server/user/user_list_painter.cpp
+ src/interface/widgets/server/user/user_list_panel_widget.cpp
src/interface/widgets/server/user/user_list_widget.cpp
+ src/interface/widgets/settings_page/abstract_settings_page.cpp
src/interface/widgets/settings_page/appearance_settings_page.cpp
src/interface/widgets/settings_page/deck_editor_settings_page.cpp
src/interface/widgets/settings_page/general_settings_page.cpp
src/interface/widgets/settings_page/messages_settings_page.cpp
+ src/interface/widgets/settings_page/settings_search_delegate.cpp
+ src/interface/widgets/settings_page/settings_search_model.cpp
src/interface/widgets/settings_page/shortcut_settings_page.cpp
src/interface/widgets/settings_page/sound_settings_page.cpp
src/interface/widgets/settings_page/storage_settings_page.cpp
src/interface/widgets/settings_page/user_interface_settings_page.cpp
src/interface/widgets/utility/custom_line_edit.cpp
src/interface/widgets/utility/get_text_with_max.cpp
+ src/interface/widgets/utility/report_utils.cpp
+ src/interface/widgets/utility/report_utils.h
src/interface/widgets/utility/sequence_edit.cpp
src/interface/widgets/utility/visibility_change_listener.cpp
src/interface/widgets/utility/visibility_change_listener.h
@@ -281,13 +311,16 @@ set(cockatrice_SOURCES
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp
src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp
+ src/interface/widgets/visual_deck_storage/visual_deck_storage_model.cpp
src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp
src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
+ src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_filter_proxy_model.cpp
src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
src/interface/window_main.cpp
src/main.cpp
+ src/single_instance_manager.cpp
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
@@ -303,6 +336,13 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/api_response/card_in_deck_request.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/api_response/commander_spellbook_deck_request.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/api_response/commander_spellbook_card_result.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/api_response/commander_spellbook_variant_result.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/api_response/commander_spellbook_estimate_bracket_result.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/commander_spellbook_bracket_explainer.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/commander_spellbook_api_accessor.cpp
src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
@@ -339,6 +379,8 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/tab_home.cpp
src/interface/widgets/tabs/tab_logs.cpp
src/interface/widgets/tabs/tab_message.cpp
+ src/interface/widgets/tabs/tab_moderation.cpp
+ src/interface/widgets/tabs/tab_report.cpp
src/interface/widgets/tabs/tab_replays.cpp
src/interface/widgets/tabs/tab_room.cpp
src/interface/widgets/tabs/tab_server.cpp
@@ -349,12 +391,31 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
src/interface/key_signals.cpp
src/interface/logger.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_service.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_widget.cpp
+ src/interface/widgets/tabs/api/commander_spellbook/handle_commander_brackets.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
src/interface/widgets/utility/compact_push_button.cpp
src/interface/widgets/utility/compact_push_button.h
+ src/single_instance_manager.h
+ src/client/url_scheme_event_filter.h
+ src/interface/intents/intent_connect_to_server.cpp
+ src/interface/intents/intent_connect_to_server.h
+ src/interface/intents/intent_disconnect_from_server.cpp
+ src/interface/intents/intent_disconnect_from_server.h
+ src/interface/intents/intent_join_server_game.cpp
+ src/interface/intents/intent_join_server_game.h
+ src/interface/intents/intent_join_server_room.cpp
+ src/interface/intents/intent_join_server_room.h
+ src/interface/intents/intent_login.cpp
+ src/interface/intents/intent_login.h
+ src/interface/intents/intent_open_server_room_by_name.cpp
+ src/interface/intents/intent_open_server_room_by_name.h
+ src/interface/intents/url_parser.cpp
+ src/interface/intents/url_parser.h
src/interface/widgets/server/user/user_info_popup.cpp
src/interface/widgets/server/user/user_info_popup.h
)
@@ -398,11 +459,7 @@ if(APPLE)
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
endif(APPLE)
-if(Qt6_FOUND)
- qt6_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
-elseif(Qt5_FOUND)
- qt5_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
-endif()
+qt6_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
# Declare path variables
set(ICONDIR
@@ -414,71 +471,37 @@ set(DESKTOPDIR
CACHE STRING "desktop file destination"
)
+set(MIMEDIR
+ share/mime/packages
+ CACHE STRING "mime file destination"
+)
+
set(COCKATRICE_MAC_QM_INSTALL_DIR "cockatrice.app/Contents/Resources/translations")
set(COCKATRICE_UNIX_QM_INSTALL_DIR "share/cockatrice/translations")
set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations")
-if(Qt6_FOUND)
- qt6_add_executable(
- cockatrice
- WIN32
- MACOSX_BUNDLE
- ${cockatrice_SOURCES}
- ${cockatrice_RESOURCES_RCC}
- ${cockatrice_MOC_SRCS}
- MANUAL_FINALIZATION
- )
-elseif(Qt5_FOUND)
- # Qt5 Translations need to be linked at executable creation time
- if(Qt5LinguistTools_FOUND)
- if(UPDATE_TRANSLATIONS)
- qt5_create_translation(cockatrice_QM ${translate_SRCS} ${cockatrice_TS})
- else()
- qt5_add_translation(cockatrice_QM ${cockatrice_TS})
- endif()
- endif()
- add_executable(
- cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_MOC_SRCS} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC}
- ${cockatrice_SOURCES}
- )
- if(UNIX)
- if(APPLE)
- install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_MAC_QM_INSTALL_DIR})
- else()
- install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_UNIX_QM_INSTALL_DIR})
- endif()
- elseif(WIN32)
- install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_WIN32_QM_INSTALL_DIR})
- endif()
-endif()
+qt6_add_executable(
+ cockatrice
+ WIN32
+ MACOSX_BUNDLE
+ ${cockatrice_SOURCES}
+ ${cockatrice_RESOURCES_RCC}
+ ${cockatrice_MOC_SRCS}
+ MANUAL_FINALIZATION
+)
-if(Qt5_FOUND)
- target_link_libraries(
- cockatrice
- libcockatrice_card
- libcockatrice_deck_list
- libcockatrice_filters
- libcockatrice_utility
- libcockatrice_network
- libcockatrice_models
- libcockatrice_rng
- libcockatrice_settings
- ${COCKATRICE_QT_MODULES}
- )
-else()
- target_link_libraries(
- cockatrice
- PUBLIC libcockatrice_card
- libcockatrice_deck_list
- libcockatrice_filters
- libcockatrice_utility
- libcockatrice_network
- libcockatrice_models
- libcockatrice_rng
- libcockatrice_settings
- ${COCKATRICE_QT_MODULES}
- )
-endif()
+target_link_libraries(
+ cockatrice
+ PUBLIC libcockatrice_card
+ libcockatrice_deck_list
+ libcockatrice_filters
+ libcockatrice_utility
+ libcockatrice_network
+ libcockatrice_models
+ libcockatrice_rng
+ libcockatrice_settings
+ ${COCKATRICE_QT_MODULES}
+)
if(UNIX)
if(APPLE)
@@ -498,6 +521,23 @@ if(UNIX)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.png DESTINATION ${ICONDIR}/hicolor/48x48/apps)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice.desktop DESTINATION ${DESKTOPDIR})
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice-cod.xml DESTINATION ${MIMEDIR})
+
+ # Refresh the freedesktop databases so the file associations and scheme
+ # handler register without requiring the user to run them manually. The
+ # tools may be missing on minimal systems; that is fine, packaging systems
+ # usually refresh these databases through their own triggers.
+ find_program(UPDATE_MIME_DATABASE update-mime-database)
+ if(UPDATE_MIME_DATABASE)
+ install(CODE "execute_process(COMMAND \"${UPDATE_MIME_DATABASE}\" \"${CMAKE_INSTALL_PREFIX}/share/mime\")")
+ endif()
+
+ find_program(UPDATE_DESKTOP_DATABASE update-desktop-database)
+ if(UPDATE_DESKTOP_DATABASE)
+ install(
+ CODE "execute_process(COMMAND \"${UPDATE_DESKTOP_DATABASE}\" \"${CMAKE_INSTALL_PREFIX}/share/applications\")"
+ )
+ endif()
endif()
elseif(WIN32)
install(TARGETS cockatrice RUNTIME DESTINATION ./)
@@ -508,7 +548,7 @@ if(APPLE)
set(plugin_dest_dir cockatrice.app/Contents/Plugins)
set(qtconf_dest_dir cockatrice.app/Contents/Resources)
- # Qt plugins: audio (Qt5), iconengines, imageformats, multimedia (Qt6), platforms, printsupport (Qt5), styles, tls (Qt6)
+ # Qt plugins: audio, iconengines, imageformats, multimedia, platforms, printsupport, styles, tls
install(
DIRECTORY "${QT_PLUGINS_DIR}/"
DESTINATION ${plugin_dest_dir}
@@ -575,7 +615,7 @@ if(WIN32)
PATTERN "*.ini"
)
- # Qt plugins: audio (Qt5), iconengines, imageformats, multimedia (Qt6) platforms, printsupport (Qt5), styles, tls (Qt6)
+ # Qt plugins: audio, iconengines, imageformats, multimedia, platforms, printsupport, styles, tls
install(
DIRECTORY "${QT_PLUGINS_DIR}/"
DESTINATION ${plugin_dest_dir}
@@ -631,7 +671,7 @@ Data = Resources\")
endif()
endif()
-if(Qt6_FOUND AND Qt6LinguistTools_FOUND)
+if(Qt6LinguistTools_FOUND)
#Qt6 Translations happen after the executable is built up
if(UPDATE_TRANSLATIONS)
qt6_add_translations(
@@ -658,6 +698,4 @@ if(Qt6_FOUND AND Qt6LinguistTools_FOUND)
endif()
endif()
-if(Qt6_FOUND)
- qt6_finalize_target(cockatrice)
-endif()
+qt6_finalize_target(cockatrice)
diff --git a/cockatrice/cockatrice-cod.xml b/cockatrice/cockatrice-cod.xml
new file mode 100644
index 000000000..1a0199433
--- /dev/null
+++ b/cockatrice/cockatrice-cod.xml
@@ -0,0 +1,7 @@
+
+
+
+ Cockatrice Deck File
+
+
+
diff --git a/cockatrice/cockatrice.desktop b/cockatrice/cockatrice.desktop
index 092d84ef5..4b15fa9c1 100644
--- a/cockatrice/cockatrice.desktop
+++ b/cockatrice/cockatrice.desktop
@@ -3,6 +3,8 @@
Version=1.0
Type=Application
Name=Cockatrice
-Exec=cockatrice
+Exec=cockatrice %U
Icon=cockatrice
Categories=Game;CardGame;
+MimeType=application/x-cockatrice;
+X-Scheme-Handler/cockatrice=true
diff --git a/cockatrice/cockatrice_en@source.ts b/cockatrice/cockatrice_en@source.ts
index 810b345df..e06972ddc 100644
--- a/cockatrice/cockatrice_en@source.ts
+++ b/cockatrice/cockatrice_en@source.ts
@@ -4,7 +4,7 @@
AbstractCounter
-
+
&Set counter...
@@ -12,12 +12,12 @@
AbstractCounterDialog
-
+
Set counter
-
+
New value for counter '%1':
@@ -38,60 +38,60 @@
AbstractTabDeckEditor
-
+
Open in new tab
-
+
Are you sure?
-
+
The decklist has been modified.
Do you want to save the changes?
-
-
-
-
-
-
+
+
+
+
+
+
Error
-
+
Could not open deck at %1
-
+
Could not save remote deck
-
-
+
+
The deck could not be saved.
Please check that the directory is writable and try again.
-
+
Save deck
-
+
The deck could not be saved.
-
+
There are no cards in your deck to be exported
@@ -107,12 +107,12 @@ Please check that the directory is writable and try again.
AdminNotesDialog
-
+
Update Notes
-
+
Admin Notes for %1
@@ -129,172 +129,227 @@ Please check that the directory is writable and try again.
Sideboard
+
+
+ Tokens
+
+
AppearanceSettingsPage
-
+
seconds
-
+
Error
-
+
Could not create themes directory at '%1'.
-
+
Theme settings
-
+
Current theme:
-
+
Open themes folder
-
+
Home tab background source:
-
+
Home tab background shuffle frequency:
-
+
Disabled
-
- Display card name of background in bottom right:
-
-
-
-
+
Menu settings
-
+
Show keyboard shortcuts in right-click menus
-
+
Show game filter toolbar above list in room tab
-
+
Card rendering
-
+
Display card names on cards having a picture
-
+
Auto-Rotate cards with sideways layout
-
+
Override all card art with personal set preference (Pre-ProviderID change behavior)
-
+
+ Light
+
+
+
+
+ Dark
+
+
+
+
+ System
+
+
+
+
+ Active theme palette:
+
+
+
+
+ Edit theme palette
+
+
+
+
+ Home tab settings
+
+
+
+
+ Display card name of background in bottom right
+
+
+
+
+ Styling settings
+
+
+
+
+ Style user list
+
+
+
+
+ Card printings
+
+
+
+
Bump sets that the deck contains cards from to the top in the printing selector
-
+
Scale cards on mouse over
-
+
Use rounded card corners
-
+
+ Card layout
+
+
+
+
Minimum overlap percentage of cards on the stack and in vertical hand
-
+
Maximum initial height for card view window:
-
-
+
+
rows
-
+
Maximum expanded height for card view window:
-
+
Card counters
-
+
Counter %1
-
+
Hand layout
-
+
Display hand horizontally (wastes space)
-
+
Enable left justification
-
+
Table grid layout
-
+
Invert vertical coordinate
-
+
Minimum player count for multi-column layout:
-
+
Maximum font size for information displayed on cards:
@@ -302,12 +357,12 @@ Please check that the directory is writable and try again.
ArchidektApiResponseDeckDisplayWidget
-
+
Back to results
-
+
Open Deck in Deck Editor
@@ -333,111 +388,111 @@ Please check that the directory is writable and try again.
BanDialog
-
+
ban &user name
-
+
ban &IP address
-
+
ban client I&D
-
+
Ban type
-
+
&permanent ban
-
+
&temporary ban
-
+
&Days:
-
+
&Hours:
-
+
&Minutes:
-
+
Duration of the ban
-
+
Please enter the reason for the ban.
This is only saved for moderators and cannot be seen by the banned person.
-
+
Please enter the reason for the ban that will be visible to the banned person.
-
+
Redact all messages from this user in all rooms
-
+
&OK
-
+
&Cancel
-
+
Ban user from server
-
-
-
-
+
+
+
+
Error
-
+
You have to select a name-based, IP-based, clientId based, or some combination of the three to place a ban.
-
+
You must have a value in the name ban when selecting the name ban checkbox.
-
+
You must have a value in the ip ban when selecting the ip ban checkbox.
-
+
You must have a value in the clientid ban when selecting the clientid ban checkbox.
@@ -445,59 +500,123 @@ This is only saved for moderators and cannot be seen by the banned person.
BetaReleaseChannel
-
+
Beta
-
+
No reply received from the release update server.
-
+
Invalid reply received from the release update server.
-
+
No reply received from the file update server.
+
+ CardArtPreviewWidget
+
+
+ No card selected
+
+
+
+
+ CardArtRulesModel
+
+
+ Card
+
+
+
+
+ ProviderId
+
+
+
+
+ Mode
+
+
+
+
+ Reason
+
+
+
CardDatabaseModel
-
+
Name
-
+
Sets
-
+
Mana cost
-
+
Card type
-
+
P/T
-
+
Color(s)
+
+ CardDatabaseView
+
+
+ Add to Deck
+
+
+
+
+ Add to Sideboard
+
+
+
+
+ Select Printing
+
+
+
+
+ Show on EDHRec (Commander)
+
+
+
+
+ Show on EDHRec (Card)
+
+
+
+
+ Show Related cards
+
+
+
CardFilter
@@ -626,22 +745,22 @@ This is only saved for moderators and cannot be seen by the banned person.
CardInfoPictureWidget
-
+
View related cards
-
+
Add card to deck
-
+
Mainboard
-
+
Sideboard
@@ -664,12 +783,12 @@ This is only saved for moderators and cannot be seen by the banned person.
-
+
Related cards:
-
+
Unknown card:
@@ -677,128 +796,146 @@ This is only saved for moderators and cannot be seen by the banned person.
CardMenu
-
+
Re&veal to...
-
+
&All players
-
+
View related cards
-
+
Token:
-
+
All tokens
-
+
&Select All
-
+
S&elect Row
-
+
S&elect Column
-
+
&Play
-
+
&Hide
-
+
Play &Face Down
-
+
&Tap / Untap
Turn sideways or back again
-
+
Skip &untapping
-
+
T&urn Over
Turn face up/face down
-
+
&Peek at card face
-
+
&Clone
-
+
Attac&h to card...
-
+
Unattac&h
-
+
&Draw arrow...
-
+
&Set annotation...
-
+
+ Reduce life by power
+
+
+
+
Ca&rd counters
-
+
&Add counter (%1)
-
+
&Remove counter (%1)
-
+
&Set counters (%1)...
+
+ CardPictureLoaderCacheMethod
+
+
+ Network Cache
+
+
+
+
+ Filesystem
+
+
+
CardSizeWidget
@@ -810,133 +947,133 @@ This is only saved for moderators and cannot be seen by the banned person.
CardZoneLogic
-
+
their hand
nominative
-
+
%1's hand
nominative
-
+
their library
look at zone
-
+
%1's library
look at zone
-
+
of their library
top cards of zone,
-
+
of %1's library
top cards of zone
-
+
their library
reveal zone
-
+
%1's library
reveal zone
-
+
their library
shuffle
-
+
%1's library
shuffle
-
+
their library
nominative
-
+
%1's library
nominative
-
+
their graveyard
nominative
-
+
%1's graveyard
nominative
-
+
their exile
nominative
-
+
%1's exile
nominative
-
+
their sideboard
look at zone
-
+
%1's sideboard
look at zone
-
+
their sideboard
nominative
-
+
%1's sideboard
nominative
-
+
their custom zone '%1'
nominative
-
+
%1's custom zone '%2'
nominative
@@ -958,16 +1095,424 @@ This is only saved for moderators and cannot be seen by the banned person.
+
+ ColorButton
+
+
+ Click to pick a color
+
+
+
+
+ Pick colour
+
+
+
+
+ ConnectionController
+
+
+
+ The server has reached its maximum user capacity, please check back later.
+
+
+
+
+ There are too many concurrent connections from your address.
+
+
+
+
+ Banned by moderator
+
+
+
+
+ Expected end time: %1
+
+
+
+
+ This ban lasts indefinitely.
+
+
+
+
+ Scheduled server shutdown.
+
+
+
+
+
+ Invalid username.
+
+
+
+
+ You have been logged out due to logging in at another location.
+
+
+
+
+ Connection closed
+
+
+
+
+ The server has terminated your connection.
+Reason: %1
+
+
+
+
+ The server is going to be restarted in %n minute(s).
+All running games will be lost.
+Reason for shutdown: %1
+
+
+
+
+
+
+
+ Scheduled server shutdown
+
+
+
+
+ Failed Login
+
+
+
+
+ Your client seems to be missing features this server requires for connection.
+
+
+
+
+ To update your client, go to 'Help -> Check for Client Updates'.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Error
+
+
+
+
+ Incorrect username or password. Please check your authentication information and try again.
+
+
+
+
+ There is already an active session using this user name.
+Please close that session first and re-login.
+
+
+
+
+
+ You are banned until %1.
+
+
+
+
+
+ You are banned indefinitely.
+
+
+
+
+ This server requires user registration. Do you want to register now?
+
+
+
+
+ This server requires client IDs. Your client is either failing to generate an ID or you are running a modified client.
+Please close and reopen your client to try again.
+
+
+
+
+ An internal error has occurred, please close and reopen Cockatrice before trying again.
+If the error persists, ensure you are running the latest version of the software and if needed contact the software developers.
+
+
+
+
+ Account activation
+
+
+
+
+ Your account has not been activated yet.
+You need to provide the activation token received in the activation email.
+
+
+
+
+ Server Full
+
+
+
+
+ Unknown login error: %1
+
+
+
+
+
+
+This usually means that your client version is out of date, and the server sent a reply your client doesn't understand.
+
+
+
+
+
+
+
+
+
+ Registration denied
+
+
+
+
+ Registration is currently disabled on this server
+
+
+
+
+ There is already an existing account with the same user name.
+
+
+
+
+ It's mandatory to specify a valid email address when registering.
+
+
+
+
+ It appears you are attempting to register a new account on this server yet you already have an account registered with the email provided. This server restricts the number of accounts a user can register per address. Please contact the server operator for further assistance or to obtain your credential information.
+
+
+
+
+ Password too short.
+
+
+
+
+ Registration failed for a technical problem on the server.
+
+
+
+
+ The connection to the server has been lost.
+
+
+
+
+ Unknown registration error: %1
+
+
+
+
+ Account activation failed
+
+
+
+
+ Socket error: %1
+
+
+
+
+ Server timeout
+
+
+
+
+ You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server.
+Local version is %1, remote version is %2.
+
+
+
+
+ Your Cockatrice client is obsolete. Please update your Cockatrice version.
+Local version is %1, remote version is %2.
+
+
+
+
+
+ Success
+
+
+
+
+ Registration accepted.
+Will now login.
+
+
+
+
+ Account activation accepted.
+Will now login.
+
+
+
+
+ Information
+
+
+
+
+ This server supports additional features that your client doesn't have.
+This is most likely not a problem, but this message might mean there is a new version of Cockatrice available or this server is running a custom or pre-release version.
+
+To update your client, go to Help -> Check for Updates.
+
+
+
+
+
+
+ Reset Password
+
+
+
+
+ Your password has been reset successfully, you can now log in using the new credentials.
+
+
+
+
+ Failed to reset user account password, please contact the server operator to reset your password.
+
+
+
+
+ Activation request received, please check your email for an activation token.
+
+
+
+
+ Connecting to %1...
+
+
+
+
+ Registering to %1 as %2...
+
+
+
+
+ Disconnected
+
+
+
+
+ Connected, logging in at %1
+
+
+
+
+ Requesting forgotten password to %1 as %2...
+
+
+
+
+ Your username must respect these rules:
+
+
+
+
+ is %1 - %2 characters long
+
+
+
+
+ can %1 contain lowercase characters
+
+
+
+
+
+
+
+ NOT
+
+
+
+
+ can %1 contain uppercase characters
+
+
+
+
+ can %1 contain numeric characters
+
+
+
+
+ can contain the following punctuation: %1
+
+
+
+
+ first character can %1 be a punctuation mark
+
+
+
+
+ no unacceptable language as specified by these server rules:
+ note that the following lines will not be translated
+
+
+
+
+ can not contain any of the following words: %1
+
+
+
+
+ can not match any of the following expressions: %1
+
+
+
+
+ You may only use A-Z, a-z, 0-9, _, ., and - in your username.
+
+
+
CustomZoneMenu
-
+
C&ustom Zones
-
-
+
+
View custom zone '%1'
@@ -975,30 +1520,35 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckAnalyticsWidget
-
+
Add Panel
-
+
Remove Panel
-
+
Save Layout
-
+
Load Layout
+
+
+ Include Sideboard
+
+
DeckEditorCardDatabaseDockWidget
-
+
Card Database
@@ -1014,47 +1564,17 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorDatabaseDisplayWidget
-
+
Search by card name (or search expressions)
-
- Add to Deck
-
-
-
-
- Add to Sideboard
-
-
-
-
- Select Printing
-
-
-
-
- Show on EDHRec (Commander)
-
-
-
-
- Show on EDHRec (Card)
-
-
-
-
- Show Related cards
-
-
-
-
+
Add card to &maindeck
-
+
Add card to &sideboard
@@ -1087,72 +1607,72 @@ This is only saved for moderators and cannot be seen by the banned person.
-
+
Select Printing
-
+
Deck
-
+
Deck &name:
-
+
Banner Card/Tags Visibility Settings
-
+
Show banner card selection menu
-
+
Show tags selection menu
-
+
&Comments:
-
+
Group by:
-
+
Format:
-
+
Hash:
-
+
&Increment number
-
+
&Decrement number
-
+
&Remove row
-
+
Swap card to/from sideboard
@@ -1160,17 +1680,17 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorFilterDockWidget
-
+
Filters
-
+
&Clear all filters
-
+
Delete selected
@@ -1301,169 +1821,113 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorSettingsPage
-
-
+
+
Update Spoilers
-
-
+
Success
-
+
Download URLs have been reset.
-
- Downloaded card pictures have been reset.
-
-
-
-
- Error
-
-
-
-
- One or more downloaded card pictures could not be cleared.
-
-
-
-
+
Add URL
-
-
+
+
URL:
-
-
+
+
Edit URL
-
- Network Cache Size:
-
-
-
-
- Redirect Cache TTL:
-
-
-
-
- How long cached redirects for urls are valid for.
-
-
-
-
- Picture Cache Size:
-
-
-
-
+
Add New URL
-
+
Remove URL
-
- Day(s)
-
-
-
-
+
Updating...
-
+
Choose path
-
+
URL Download Priority
-
+
Spoilers
-
+
Download Spoilers Automatically
-
+
Spoiler Location:
-
+
Last Change
-
+
Spoilers download automatically on launch
-
+
Press the button to manually update without relaunching
-
+
Do not close settings until manual update is complete
-
+
Download card pictures on the fly
-
+
How to add a custom URL
-
- Delete Downloaded Images
-
-
-
-
+
Reset Download URLs
-
-
- On-disk cache for downloaded pictures
-
-
-
-
- In-memory cache for pictures not currently on screen
-
-
DeckListHistoryManagerWidget
@@ -1529,12 +1993,12 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckLoader
-
+
Common deck formats (%1)
-
+
All files (*.*)
@@ -1756,27 +2220,27 @@ This is only saved for moderators and cannot be seen by the banned person.
-
+
Moved to %1 1 × "%2" (%3)
-
+
Removed "%1" (all copies)
-
+
%1 1 × "%2" (%3)
-
+
Added
-
+
Removed
@@ -1798,74 +2262,74 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckViewContainer
-
+
Load deck...
-
+
Load remote deck...
-
+
Load from clipboard...
-
+
Load from website...
-
+
Unload deck
-
+
Ready to start
-
+
Force start
-
+
Sideboard unlocked
-
+
Sideboard locked
-
-
+
+
Error
-
+
The selected file could not be loaded.
-
+
Deck is greater than maximum file size.
-
+
Are you sure you want to force start?
This will kick all non-ready players from the game.
-
+
Cockatrice
@@ -1964,7 +2428,7 @@ This will kick all non-ready players from the game.
-
+
Webpage
@@ -2004,37 +2468,37 @@ This will kick all non-ready players from the game.
-
+
Server URL
-
+
Communication Port
-
+
Unique Server Name
-
+
Connection Warning
-
+
You need to name your new connection profile.
-
+
Connect Warning
-
+
The player name can't be empty.
@@ -2147,17 +2611,17 @@ This will kick all non-ready players from the game.
-
+
Game information
-
+
Error
-
+
Server error.
@@ -2165,97 +2629,97 @@ This will kick all non-ready players from the game.
DlgCreateToken
-
+
&Name:
-
+
Token
-
+
C&olor:
-
+
white
-
+
blue
-
+
black
-
+
red
-
+
green
-
+
multicolor
-
+
colorless
-
+
&P/T:
-
+
&Annotation:
-
+
&Destroy token when it leaves the table
-
+
Create face-down (Only hides name)
-
+
Token data
-
+
Show &all tokens
-
+
Show tokens from this &deck
-
+
Choose token from list
-
+
Create token
@@ -2289,7 +2753,7 @@ This will kick all non-ready players from the game.
-
+
✖
@@ -2304,12 +2768,12 @@ This will kick all non-ready players from the game.
-
+
Duplicate Tag
-
+
This tag already exists.
@@ -2495,12 +2959,12 @@ To remove your current avatar, confirm without choosing a new image.
-
+
Error
-
+
The chosen name conflicts with an existing card or token.
Make sure to enable the 'Token' set in the "Manage sets" dialog to display them correctly.
@@ -2524,12 +2988,12 @@ Make sure to enable the 'Token' set in the "Manage sets" dia
-
+
Real name:
-
+
Edit user profile
@@ -2567,113 +3031,113 @@ Make sure to enable the 'Token' set in the "Manage sets" dia
-
+
Hide 'buddies only' games
-
+
Hide full games
-
+
Hide games that have started
-
+
Hide password protected games
-
+
Hide 'ignored user' games
-
+
Hide games not created by buddies
Hide games not created by buddy
-
+
Hide games with forced open decklists
-
+
&Newer than:
-
+
Game &description:
-
+
&Creator name:
-
+
General
-
+
&Game types
-
+
at &least:
-
+
at &most:
-
+
Maximum player count
-
+
Restrictions
-
+
Show games only if &spectators can watch
-
+
Show spectator password p&rotected games
-
+
Show only if spectators can ch&at
-
+
Show only if spectators can see &hands
-
+
Spectators
-
+
Filter games
@@ -2976,37 +3440,37 @@ https://tappedout.net/mtg-decks/your-deck-name/
DlgMoveTopCardsUntil
-
+
Card name (or search expressions):
-
+
Number of hits:
-
+
Auto play hits
-
+
Put top cards on stack until...
-
+
No cards matching the search expression exists in the card database. Proceed anyways?
-
+
Cockatrice
-
+
Invalid filter
@@ -3065,40 +3529,40 @@ Your email will be used to verify your account.
-
+
Real name:
-
+
Register to server
-
-
-
-
+
+
+
+
Registration Warning
-
+
Your password is too short.
-
+
Your passwords do not match, please try again.
-
+
Your email addresses do not match, please try again.
-
+
The player name can't be empty.
@@ -3106,17 +3570,17 @@ Your email will be used to verify your account.
DlgRollDice
-
+
Number of sides:
-
+
Number of dice:
-
+
Roll Dice
@@ -3167,12 +3631,12 @@ Your email will be used to verify your account.
DlgSettings
-
+
Unknown Error loading card database
-
+
Your card database is invalid.
Cockatrice may not function correctly with an invalid database
@@ -3183,7 +3647,7 @@ Would you like to change your database location setting?
-
+
Your card database version is too old.
This can cause problems loading card information or images
@@ -3194,7 +3658,7 @@ Would you like to change your database location setting?
-
+
Your card database did not finish loading
Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues with your cards.xml attached
@@ -3203,21 +3667,21 @@ Would you like to change your database location setting?
-
+
File Error loading your card database.
Would you like to change your database location setting?
-
+
Your card database was loaded but contains no cards.
Would you like to change your database location setting?
-
+
Unknown card database load status
Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues
@@ -3226,59 +3690,64 @@ Would you like to change your database location setting?
-
-
-
+
+
+
Error
-
+
The path to your deck directory is invalid. Would you like to go back and set the correct path?
-
+
The path to your card pictures directory is invalid. Would you like to go back and set the correct path?
-
+
Settings
-
+
General
-
+
Appearance
-
+
User Interface
-
+
+ Storage
+
+
+
+
Card Sources
-
+
Chat
-
+
Sound
-
+
Shortcuts
@@ -3370,9 +3839,9 @@ You can always change this behavior in the 'General' settings tab.
-
-
-
+
+
+
Error
@@ -3424,31 +3893,31 @@ Please visit the download page to update manually.
-
+
Update Available
-
+
A new version of Cockatrice is available!
-
+
New version
-
+
Released
-
+
Changelog
@@ -3458,50 +3927,50 @@ Please visit the download page to update manually.
-
+
Unfortunately, the automatic updater failed to find a compatible download.
You may have to manually download the new version.
-
+
Please check the <a href="%1">releases page</a> on our Github and download the build for your system.
-
-
-
+
+
+
Update Error
-
+
An error occurred while checking for updates:
-
+
An error occurred while downloading an update:
-
+
Installing...
-
+
Cockatrice is unable to open the installer.
-
+
Try to update manually by closing Cockatrice and running the installer.
-
+
Download location
@@ -3591,67 +4060,67 @@ You may have to manually download the new version.
DrawProbabilityWidget
-
+
Draw Probability
-
+
Probability of drawing
-
+
Card Name
-
+
Type
-
+
Subtype
-
+
Mana Value
-
+
At least
-
+
Exactly
-
+
card(s) having drawn at least
-
+
cards
-
+
Category
-
+
Qty
-
+
Odds (%)
@@ -3765,7 +4234,7 @@ You may have to manually download the new version.
FilterBuilder
-
+
Type your filter here
@@ -3796,22 +4265,22 @@ You may have to manually download the new version.
GameEventHandler
-
+
kicked by game host or moderator
-
+
player left the game
-
+
player disconnected from server
-
+
reason unknown
@@ -3819,140 +4288,140 @@ You may have to manually download the new version.
GameSelector
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Error
-
+
Please join the appropriate room first.
-
+
Wrong password.
-
+
Spectators are not allowed in this game.
-
+
The game is already full.
-
+
The game does not exist any more.
-
+
This game is only open to registered users.
-
+
This game is only open to its creator's buddies.
-
+
You are being ignored by the creator of this game.
-
+
Join Game
-
+
Spectate Game
-
+
Game Information
-
+
Join Game as Judge
-
+
Spectate Game as Judge
-
+
Join game
-
+
Password:
-
+
Please join the respective room first.
-
+
&Filter games
-
+
C&lear filter
-
+
C&reate
-
+
&Join
-
+
Join as judge
-
+
J&oin as spectator
-
+
Join as judge spectator
-
+
Games shown: %1 / %2
-
+
Games
@@ -3960,32 +4429,32 @@ You may have to manually download the new version.
GameSelectorQuickFilterToolBar
-
+
All types
-
+
Filter by game name...
-
+
Filter by game type/format
-
+
Hide games not created by buddies
-
+
Hide full games
-
+
Hide started games
@@ -3993,12 +4462,12 @@ You may have to manually download the new version.
GamesModel
-
+
>1 day
-
+
%1%2 hr
short age in hours
@@ -4007,12 +4476,12 @@ You may have to manually download the new version.
-
+
new
-
+
%1%2 min
short age in minutes
@@ -4021,83 +4490,83 @@ You may have to manually download the new version.
-
+
password
-
+
buddies only
-
+
reg. users only
-
+
open decklists
-
+
can chat
-
+
see hands
-
+
can see hands
-
+
not allowed
-
+
Room
-
+
Age
-
+
Description
-
+
Creator
-
+
Type
-
+
Restrictions
-
+
Players
-
+
Spectators
@@ -4105,143 +4574,158 @@ You may have to manually download the new version.
GeneralSettingsPage
-
+
Reset all paths
-
+
All paths have been reset
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Choose path
-
- Personal settings
+
+ Language settings
-
+
Language:
-
+
+ Version settings
+
+
+
+
+ Card database
+
+
+
+
+ Startup settings
+
+
+
+
Paths (editing disabled in portable mode)
-
+
Paths
-
+
How to help with translations
-
+
Decks directory:
-
+
Filters directory:
-
+
Replays directory:
-
+
Pictures directory:
-
+
Card database:
-
+
Custom database directory:
-
+
Token database:
-
+
Update channel
-
+
Check for client updates on startup
-
+
Check for card database updates on startup
-
+
Don't check
-
+
Prompt for update
-
+
Always update in the background
-
+
Check for card database updates every
-
+
days
-
+
Notify if a feature supported by the server is missing in my client
-
+
Automatically run Oracle when running a new version of Cockatrice
-
+
Show tips on startup
-
+
Last update check on %1 (%2 days ago)
@@ -4249,47 +4733,47 @@ You may have to manually download the new version.
GraveyardMenu
-
+
&Graveyard
-
+
&View graveyard
-
+
&Move graveyard to...
-
+
&Top of library
-
+
&Bottom of library
-
+
&All players
-
+
&Hand
-
+
&Exile
-
+
Reveal random card to...
@@ -4297,88 +4781,88 @@ You may have to manually download the new version.
HandMenu
-
+
&Hand
-
+
&View hand
-
+
Sort hand by...
-
+
Name
-
+
Type
-
+
Mana Value
-
+
Take &mulligan (Choose hand size)
-
+
Take mulligan (Same hand size)
-
+
Take mulligan (Hand size - 1)
-
+
&Move hand to...
-
+
&Top of library
-
+
&Bottom of library
-
+
&Graveyard
-
+
&Exile
-
+
&Reveal hand to...
-
-
+
+
All players
-
+
Reveal r&andom card to...
@@ -4386,52 +4870,52 @@ You may have to manually download the new version.
HomeWidget
-
+
Create New Deck
-
+
Browse Decks
-
+
Browse Card Database
-
+
Browse EDHRec
-
+
Browse Archidekt
-
+
View Replays
-
+
Quit
-
+
Connecting...
-
+
Connect
-
+
Play
@@ -4439,213 +4923,213 @@ You may have to manually download the new version.
LibraryMenu
-
+
&Library
-
+
&View library
-
+
View &top cards of library...
-
+
View bottom cards of library...
-
+
Reveal &library to...
-
+
Lend library to...
-
+
Reveal &top cards to...
-
+
&Top of library...
-
+
&Bottom of library...
-
+
&Always reveal top card
-
+
&Always look at top card
-
+
&Open deck in deck editor
-
+
&Draw card
-
+
D&raw cards...
-
+
&Undo last draw
-
+
Shuffle
-
+
&Play top card
-
+
Play top card &face down
-
+
Put top card on &bottom
-
+
Move top card to grave&yard
-
+
Move top card to e&xile
-
+
Move top cards to &graveyard...
-
+
Move top cards to graveyard face down...
-
+
Move top cards to &exile...
-
+
Move top cards to exile face down...
-
+
Put top cards on stack &until...
-
+
Shuffle top cards...
-
+
&Draw bottom card
-
+
D&raw bottom cards...
-
+
&Play bottom card
-
+
Play bottom card &face down
-
+
Move bottom card to grave&yard
-
+
Move bottom card to e&xile
-
+
Move bottom cards to &graveyard...
-
+
Move bottom cards to graveyard face down...
-
+
Move bottom cards to &exile...
-
+
Move bottom cards to exile face down...
-
+
Put bottom card on &top
-
+
Shuffle bottom cards...
-
-
+
+
&All players
-
+
Reveal top cards of library
-
+
Number of cards: (max. %1)
@@ -4653,655 +5137,300 @@ You may have to manually download the new version.
MainWindow
-
-
- The server has reached its maximum user capacity, please check back later.
-
-
-
-
- There are too many concurrent connections from your address.
-
-
-
-
- Banned by moderator
-
-
-
-
- Expected end time: %1
-
-
-
-
- This ban lasts indefinitely.
-
-
-
-
- Scheduled server shutdown.
-
-
-
-
-
- Invalid username.
-
-
-
-
- You have been logged out due to logging in at another location.
-
-
-
-
- Connection closed
-
-
-
-
- The server has terminated your connection.
-Reason: %1
-
-
-
-
- The server is going to be restarted in %n minute(s).
-All running games will be lost.
-Reason for shutdown: %1
-
-
-
-
-
-
-
- Scheduled server shutdown
-
-
-
-
-
- Success
-
-
-
-
- Registration accepted.
-Will now login.
-
-
-
-
- Account activation accepted.
-Will now login.
-
-
-
-
-
+
+
Player %1
-
+
Load replay
-
+
About Cockatrice
-
+
Version
-
+
Cockatrice Webpage
-
+
Project Manager:
-
+
Past Project Managers:
-
+
Developers:
-
+
Our Developers
-
+
Help Develop!
-
+
Translators:
-
+
Our Translators
-
+
Help Translate!
-
+
Support:
-
+
Report an Issue
-
+
Troubleshooting
-
+
F.A.Q.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
Error
-
- Server timeout
-
-
-
-
- Failed Login
-
-
-
-
- Your client seems to be missing features this server requires for connection.
-
-
-
-
- To update your client, go to 'Help -> Check for Client Updates'.
-
-
-
-
- Incorrect username or password. Please check your authentication information and try again.
-
-
-
-
- There is already an active session using this user name.
-Please close that session first and re-login.
-
-
-
-
-
- You are banned until %1.
-
-
-
-
-
- You are banned indefinitely.
-
-
-
-
- This server requires user registration. Do you want to register now?
-
-
-
-
- This server requires client IDs. Your client is either failing to generate an ID or you are running a modified client.
-Please close and reopen your client to try again.
-
-
-
-
- An internal error has occurred, please close and reopen Cockatrice before trying again.
-If the error persists, ensure you are running the latest version of the software and if needed contact the software developers.
-
-
-
-
- Account activation
-
-
-
-
- Your account has not been activated yet.
-You need to provide the activation token received in the activation email.
-
-
-
-
- Server Full
-
-
-
-
- Unknown login error: %1
-
-
-
-
-
-
-This usually means that your client version is out of date, and the server sent a reply your client doesn't understand.
-
-
-
-
- Your username must respect these rules:
-
-
-
-
- is %1 - %2 characters long
-
-
-
-
- can %1 contain lowercase characters
-
-
-
-
-
-
-
- NOT
-
-
-
-
- can %1 contain uppercase characters
-
-
-
-
- can %1 contain numeric characters
-
-
-
-
- can contain the following punctuation: %1
-
-
-
-
- first character can %1 be a punctuation mark
-
-
-
-
- no unacceptable language as specified by these server rules:
- note that the following lines will not be translated
-
-
-
-
- can not contain any of the following words: %1
-
-
-
-
- can not match any of the following expressions: %1
-
-
-
-
- You may only use A-Z, a-z, 0-9, _, ., and - in your username.
-
-
-
-
-
-
-
-
-
- Registration denied
-
-
-
-
- Registration is currently disabled on this server
-
-
-
-
- There is already an existing account with the same user name.
-
-
-
-
- It's mandatory to specify a valid email address when registering.
-
-
-
-
- It appears you are attempting to register a new account on this server yet you already have an account registered with the email provided. This server restricts the number of accounts a user can register per address. Please contact the server operator for further assistance or to obtain your credential information.
-
-
-
-
- Password too short.
-
-
-
-
- Registration failed for a technical problem on the server.
-
-
-
-
- The connection to the server has been lost.
-
-
-
-
- Unknown registration error: %1
-
-
-
-
- Account activation failed
-
-
-
-
- Socket error: %1
-
-
-
-
- You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server.
-Local version is %1, remote version is %2.
-
-
-
-
- Your Cockatrice client is obsolete. Please update your Cockatrice version.
-Local version is %1, remote version is %2.
-
-
-
-
- Connecting to %1...
-
-
-
-
- Registering to %1 as %2...
-
-
-
-
- Disconnected
-
-
-
-
- Connected, logging in at %1
-
-
-
-
-
-
- Requesting forgotten password to %1 as %2...
-
-
-
-
+
&Connect...
-
+
&Disconnect
-
+
Start &local game...
-
+
&Watch replay...
-
+
&Full screen
-
+
&Register to server...
-
+
&Restore password...
-
+
&Settings...
-
+
&Exit
-
+
A&ctions
-
+
&Cockatrice
-
+
C&ard Database
-
+
&Manage sets...
-
+
Edit custom &tokens...
-
+
Open custom image folder
-
+
Open custom sets folder
-
+
Add custom sets/cards
-
+
Reload card database
-
+
Tabs
-
+
&Help
-
+
&About Cockatrice
-
+
&Tip of the Day
-
+
Check for Client Updates
-
+
Check for Card Updates...
-
+
Check for Card Updates (Automatic)
-
+
Show Status Bar
-
+
View &Debug Log
-
+
Open Settings Folder
-
+
Show/Hide
-
+
New Version
-
+
Congratulations on updating to Cockatrice %1!
Oracle will now launch to update your card database.
-
+
Cockatrice installed
-
+
Congratulations on installing Cockatrice %1!
Oracle will now launch to install the initial card database.
-
+
Card database
-
+
Cockatrice is unable to load the card database.
Do you want to update your card database now?
If unsure or first time user, choose "Yes"
-
-
+
+
Yes
-
-
+
+
No
-
+
Open settings
-
+
New sets found
-
+
%n new set(s) found in the card database
Set code(s): %1
Do you want to enable it/them?
@@ -5311,179 +5440,153 @@ Do you want to enable it/them?
-
+
+ Yes, always enable
+
+
+
+
View sets
-
+
Welcome
-
+
Hi! It seems like you're running this version of Cockatrice for the first time.
All the sets in the card database have been enabled.
Read more about changing the set order or disabling specific sets and consequent effects in the "Manage Sets" dialog.
-
-
+
Information
-
+
A card database update is already running.
-
+
Unable to run the card database updater:
-
+
Card database update running.
-
+
Failed to start. The file might be missing, or permissions might be incorrect.
-
+
The process crashed some time after starting successfully.
-
+
Timed out. The process took too long to respond. The last waitFor...() function timed out.
-
+
An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.
-
+
An error occurred when attempting to read from the process. For example, the process may not be running.
-
+
Unknown error occurred.
-
+
The card database updater exited with an error:
%1
-
- This server supports additional features that your client doesn't have.
-This is most likely not a problem, but this message might mean there is a new version of Cockatrice available or this server is running a custom or pre-release version.
-
-To update your client, go to Help -> Check for Updates.
-
-
-
-
-
-
-
-
+
+
+
+
+
Load sets/cards
-
+
Selected file cannot be found.
-
+
You can only import XML databases at this time.
-
+
The new sets/cards have been added successfully.
Cockatrice will now reload the card database.
-
+
Sets/cards failed to import.
-
-
-
-
- Reset Password
-
-
-
-
- Your password has been reset successfully, you can now log in using the new credentials.
-
-
-
-
- Failed to reset user account password, please contact the server operator to reset your password.
-
-
-
-
- Activation request received, please check your email for an activation token.
-
-
ManaBaseConfigDialog
-
+
Mana Base Configuration
-
+
Display type:
-
+
pie
-
+
bar
-
+
combinedBar
-
+
Filter Colors (optional):
-
+
OK
-
+
Cancel
@@ -5555,27 +5658,27 @@ Cockatrice will now reload the card database.
ManaDevotionConfigDialog
-
+
Display type:
-
+
pie
-
+
bar
-
+
combinedBar
-
+
Filter Colors (optional):
@@ -5645,297 +5748,297 @@ Cockatrice will now reload the card database.
MessageLogWidget
-
+
from play
-
+
from their graveyard
-
+
from exile
-
+
from their hand
-
+
the top card of %1's library
-
+
the top card of their library
-
+
from the top of %1's library
-
+
from the top of their library
-
+
the bottom card of %1's library
-
+
the bottom card of their library
-
+
from the bottom of %1's library
-
+
from the bottom of their library
-
+
from %1's library
-
+
from their library
-
+
from sideboard
-
+
from the stack
-
+
from custom zone '%1'
-
+
%1 is now keeping the top card %2 revealed.
-
+
%1 is not revealing the top card %2 any longer.
-
+
%1 can now look at top card %2 at any time.
-
+
%1 no longer can look at top card %2 at any time.
-
+
%1 attaches %2 to %3's %4.
-
+
%1 has conceded the game.
-
+
%1 has unconceded the game.
-
+
%1 has restored connection to the game.
-
+
%1 has lost connection to the game.
-
+
%1 points from their %2 to themselves.
-
+
%1 points from their %2 to %3.
-
+
%1 points from %2's %3 to themselves.
-
+
%1 points from %2's %3 to %4.
-
+
%1 points from their %2 to their %3.
-
+
%1 points from their %2 to %3's %4.
-
+
%1 points from %2's %3 to their own %4.
-
+
%1 points from %2's %3 to %4's %5.
-
+
%1 creates a face down token.
-
+
%1 creates token: %2%3.
-
+
%1 has loaded a deck (%2).
-
+
%1 has loaded a deck with %2 sideboard cards (%3).
-
+
%1 destroys %2.
-
+
a card
-
+
%1 gives %2 control over %3.
-
+
%1 puts %2 into play%3 face down.
-
+
%1 puts %2 into play%3.
-
+
%1 puts %2%3 into their graveyard face down.
-
+
%1 puts %2%3 into their graveyard.
-
+
%1 exiles %2%3 face down.
-
+
%1 exiles %2%3.
-
+
%1 moves %2%3 to their hand.
-
+
%1 puts %2%3 into their library.
-
+
%1 puts %2%3 onto the bottom of their library.
-
+
%1 puts %2%3 on top of their library.
-
+
%1 puts %2%3 into their library %4 cards from the top.
-
+
%1 moves %2%3 to sideboard.
-
+
%1 plays %2%3 face down.
-
+
%1 plays %2%3.
-
+
%1 moves %2%3 to custom zone '%4' face down.
-
+
%1 moves %2%3 to custom zone '%4'.
-
+
%1 tries to draw from an empty library
-
+
%1 draws %2 card(s).
@@ -5943,12 +6046,12 @@ Cockatrice will now reload the card database.
-
+
%1 is looking at %2.
-
+
%1 is looking at the %4 %3 card(s) %2.
top card for singular, top %3 cards for plural
@@ -5957,72 +6060,72 @@ Cockatrice will now reload the card database.
-
+
bottom
-
+
top
-
+
%1 turns %2 face-down.
-
+
%1 turns %2 face-up.
-
+
The game has been closed.
-
+
The game has started.
-
+
You are flooding the game. Please wait a couple of seconds.
-
+
%1 has joined the game.
-
+
%1 is now watching the game.
-
+
You have been kicked out of the game.
-
+
%1 has left the game (%2).
-
+
%1 is not watching the game any more (%2).
-
+
%1 is not ready to start the game any more.
-
+
%1 shuffles their deck and draws a new hand of %2 card(s).
@@ -6030,28 +6133,28 @@ Cockatrice will now reload the card database.
-
+
%1 shuffles their deck and draws a new hand.
-
+
You are watching a replay of game #%1.
-
+
%1 is ready to start the game.
-
+
cards
an unknown amount of cards
-
+
%1 card(s)
a card for singular, %1 cards for plural
@@ -6060,213 +6163,218 @@ Cockatrice will now reload the card database.
-
+
%1 lends %2 to %3.
-
+
%1 reveals %2 to %3.
-
+
%1 reveals %2.
-
+
%1 randomly reveals %2%3 to %4.
-
+
%1 randomly reveals %2%3.
-
+
%1 peeks at face down card #%2.
-
+
%1 peeks at face down card #%2: %3.
-
+
%1 reveals %2%3 to %4.
-
+
%1 reveals %2%3.
-
+
%1 reversed turn order, now it's %2.
-
+
reversed
-
+
normal
-
+
Heads
-
+
Tails
-
+
%1 flipped a coin. It landed as %2.
-
+
%1 rolls a %2 with a %3-sided die.
-
+
%1 flips %2 coins. There are %3 heads and %4 tails.
-
+
%1 rolls a %2-sided dice %3 times: %4.
-
+
%1's turn.
-
+
%1 sets annotation of %2 to %3.
-
- %1 places %2 "%3" counter(s) on %4 (now %5).
+
+ %1 places %2 %3%4 counter(s) on %5 (now %6).
-
- %1 removes %2 "%3" counter(s) from %4 (now %5).
+
+ %1 removes %2 %3%4 counter(s) from %5 (now %6).
-
+
+ %1 failed to undo their last draw.
+
+
+
+
%1 sets counter %2 to %3 (%4%5).
-
+
%1 sets %2 to not untap normally.
-
+
%1 sets %2 to untap normally.
-
+
%1 removes the PT of %2.
-
+
%1 changes the PT of %2 from nothing to %4.
-
+
%1 changes the PT of %2 from %3 to %4.
-
+
%1 has locked their sideboard.
-
+
%1 has unlocked their sideboard.
-
+
%1 taps their permanents.
-
+
%1 untaps their permanents.
-
+
%1 taps %2.
-
+
%1 untaps %2.
-
+
%1 shuffles %2.
-
+
%1 shuffles the bottom %3 cards of %2.
-
+
%1 shuffles the top %3 cards of %2.
-
+
%1 shuffles cards %3 - %4 of %2.
-
+
%1 unattaches %2.
-
+
%1 undoes their last draw.
-
+
%1 undoes their last draw (%2).
@@ -6274,110 +6382,115 @@ Cockatrice will now reload the card database.
MessagesSettingsPage
-
+
Word1 Word2 Word3
-
+
Add New Message
-
+
Edit Message
-
+
Remove Message
-
+
Add message
-
-
+
+
Message:
-
+
Edit message
-
+
Chat settings
-
+
Custom alert words
-
+
Enable chat mentions
-
+
Enable mention completer
-
+
In-game message macros
-
+
How to use in-game message macros
-
+
Ignore chat room messages sent by unregistered users
-
+
Ignore private messages sent by unregistered users
-
-
+
+ Ignore private messages sent by non-buddy users
+
+
+
+
+
Invert text color
-
+
Enable desktop notifications for private messages
-
+
Enable desktop notification for mentions
-
+
Enable room message history on join
-
-
+
+
(Color is hexadecimal)
-
+
Separate words with a space, alphanumeric characters only
@@ -6385,42 +6498,42 @@ Cockatrice will now reload the card database.
MoveMenu
-
+
Move to
-
+
&Top of library in random order
-
+
X cards from the top of library...
-
+
&Bottom of library in random order
-
+
T&able
-
+
&Hand
-
+
&Graveyard
-
+
&Exile
@@ -6433,47 +6546,47 @@ Cockatrice will now reload the card database.
-
+
Mana Value
-
+
Color(s)
-
+
Loyalty
-
+
Main Card Type
-
+
Mana Cost
-
+
P/T
-
+
Side
-
+
Layout
-
+
Color Identity
@@ -6496,6 +6609,152 @@ Cockatrice will now reload the card database.
+
+ PaletteEditorDialog
+
+
+
+ Reset
+
+
+
+
+
+ Apply
+
+
+
+
+
+ Save && Apply
+
+
+
+
+ ▼ Edit Palette
+
+
+
+
+
+ ▶ Edit Palette
+
+
+
+
+ Palette Editor — %1
+
+
+
+
+ <b>Palette Editor</b> · %1
+
+
+
+
+ This theme ships no default palette files
+
+
+
+
+ Replace current colours with the theme author's defaults
+
+
+
+
+ Switch between the light and dark palette files
+
+
+
+
+ Editing:
+
+
+
+
+ Show or hide the per-role colour grid for manual tweaks
+
+
+
+
+ ↺ Revert to theme default
+
+
+
+
+ Discard unsaved edits and restore the last saved palette
+
+
+
+
+ Preview this palette without saving to disk
+
+
+
+
+ Write palette-%1.toml and reload the theme
+
+
+
+
+ Cannot save: this theme has no directory on disk
+
+
+
+
+ Save failed
+
+
+
+
+ Could not write %1 to:
+%2
+
+
+
+
+ No default found
+
+
+
+
+ No default palette file found for the "%1" scheme.
+
+
+
+
+ PaletteGridWidget
+
+
+ Active
+
+
+
+
+ Disabled
+
+
+
+
+ Inactive
+
+
+
+
+ Normal interactive state
+
+
+
+
+ Widget is disabled / not interactive
+
+
+
+
+ Window is in background / unfocused
+
+
+
Phase
@@ -6562,57 +6821,57 @@ Cockatrice will now reload the card database.
PhasesToolbar
-
+
Untap step
-
+
Upkeep step
-
+
Draw step
-
+
First main phase
-
+
Beginning of combat step
-
+
Declare attackers step
-
+
Declare blockers step
-
+
Combat damage step
-
+
End of combat step
-
+
Second main phase
-
+
End of turn step
@@ -6620,7 +6879,7 @@ Cockatrice will now reload the card database.
PictureLoader
-
+
en
code for scryfall's language property, not available for all languages
@@ -6629,151 +6888,142 @@ Cockatrice will now reload the card database.
PlayerActions
-
- View top cards of library
-
-
-
-
-
-
-
-
-
-
-
-
- Number of cards: (max. %1)
-
-
-
-
- View bottom cards of library
-
-
-
-
- Shuffle top cards of library
-
-
-
-
- Shuffle bottom cards of library
-
-
-
-
- Draw hand
-
-
-
-
- 0 and lower are in comparison to current hand size
-
-
-
-
- Draw cards
-
-
-
-
-
-
-
+
+
+
+
grave
-
-
-
-
+
+
+
+
exile
+
+
+ PlayerDialogs
-
+
+ View top cards of library
+
+
+
+
+
+
+
+
+
+
+
+
+ Number of cards: (max. %1)
+
+
+
+
+ View bottom cards of library
+
+
+
+
+ Shuffle top cards of library
+
+
+
+
+ Shuffle bottom cards of library
+
+
+
+
+ Draw hand
+
+
+
+
+ 0 and lower are in comparison to current hand size
+
+
+
+
+ Draw cards
+
+
+
+
Move top cards to %1
-
+
Move bottom cards to %1
-
+
Draw bottom cards
-
-
- C&reate another %1 token
-
-
-
-
+
Create tokens
-
-
+
Number:
-
+
Place card X cards from top of library
-
+
Which position should this card be placed:
-
+
(max. %1)
-
+
Change power/toughness
-
+
Change stats to:
-
+
Set annotation
-
+
Please enter the new annotation:
-
-
- Set counters
-
-
PlayerMenu
-
+
Player "%1"
-
+
&Counters
@@ -6803,7 +7053,7 @@ This setting means you'll only see the default printing for each card, inst
-
+
Printing Selector
@@ -6811,22 +7061,22 @@ This setting means you'll only see the default printing for each card, inst
PrintingSelectorCardOverlayWidget
-
+
Preference
-
+
Pin Printing
-
+
Unpin Printing
-
+
Show Related cards
@@ -6897,57 +7147,57 @@ This setting means you'll only see the default printing for each card, inst
PtMenu
-
+
Power / toughness
-
+
&Increase power
-
+
&Decrease power
-
+
I&ncrease toughness
-
+
D&ecrease toughness
-
+
In&crease power and toughness
-
+
Dec&rease power and toughness
-
+
Increase power and decrease toughness
-
+
Decrease power and increase toughness
-
+
Set &power and toughness...
-
+
Reset p&ower and toughness
@@ -6955,37 +7205,37 @@ This setting means you'll only see the default printing for each card, inst
QMenuBar
-
+
Services
-
+
Hide %1
-
+
Hide Others
-
+
Show All
-
+
Preferences...
-
+
Quit %1
-
+
About %1
@@ -6993,17 +7243,17 @@ This setting means you'll only see the default printing for each card, inst
QObject
-
+
Cockatrice card database (*.xml)
-
+
All files (*.*)
-
+
Cockatrice replays (*.cor)
@@ -7063,110 +7313,177 @@ Are you sure you would like to disable this feature?
QPlatformTheme
-
+
OK
-
+
Save
-
+
Save All
-
+
Open
-
+
&Yes
-
+
Yes to &All
-
+
&No
-
+
N&o to All
-
+
Abort
-
+
Retry
-
+
Ignore
-
+
Close
-
+
Cancel
-
+
Discard
-
+
Help
-
+
Apply
-
+
Reset
-
+
Restore Defaults
+
+ QuickSetupPanel
+
+
+ %1%
+
+
+
+
+ <b>Quick Setup</b>
+
+
+
+
+ Generate all palette roles automatically from a single accent colour
+
+
+
+
+ Accent:
+
+
+
+
+ Primary hue. Used directly for highlights and links.
+At high intensity it also tints buttons and backgrounds.
+
+
+
+
+ Intensity:
+
+
+
+
+ Subtle
+
+
+
+
+ Full colour
+
+
+
+
+ 0–30 Subtle tint — only highlights and links change hue
+30–70 Accented — buttons, tooltips, and borders join in
+70–100 Full colour — backgrounds, everything
+
+
+
+
+ 70%
+
+
+
+
+ Generate ↓
+
+
+
+
+ Derive all palette roles from the accent colour above.
+Fine-tune individual colours in the grid afterwards.
+
+
+
RemoteDeckList_TreeModel
-
+
Name
-
+
ID
-
+
Upload time
@@ -7174,32 +7491,32 @@ Are you sure you would like to disable this feature?
RemoteReplayList_TreeModel
-
+
ID
-
+
Name
-
+
Players
-
+
Keep
-
+
Time started
-
+
Duration (sec)
@@ -7207,37 +7524,37 @@ Are you sure you would like to disable this feature?
RfgMenu
-
+
&Exile
-
+
&View exile
-
+
&Move exile to...
-
+
&Top of library
-
+
&Bottom of library
-
+
&Hand
-
+
&Graveyard
@@ -7283,7 +7600,7 @@ Are you sure you would like to disable this feature?
SayMenu
-
+
S&ay
@@ -7324,27 +7641,27 @@ Are you sure you would like to disable this feature?
SetsModel
-
+
Enabled
-
+
Set type
-
+
Set code
-
+
Long name
-
+
Release date
@@ -7352,53 +7669,53 @@ Are you sure you would like to disable this feature?
ShortcutSettingsPage
-
-
+
+
Restore all default shortcuts
-
+
Do you really want to restore all default shortcuts?
-
+
Clear all default shortcuts
-
+
Do you really want to clear all shortcuts?
-
+
Section:
-
+
Action:
-
+
Shortcut:
-
+
How to set custom shortcuts
-
+
Clear all shortcuts
-
+
Search by shortcut name
@@ -7452,12 +7769,12 @@ Please check your shortcut settings!
SideboardMenu
-
+
&Sideboard
-
+
&View sideboard
@@ -7465,27 +7782,27 @@ Please check your shortcut settings!
SoundSettingsPage
-
+
Enable &sounds
-
+
Current sounds theme:
-
+
Test system sound engine
-
+
Sound settings
-
+
Master volume
@@ -7557,16 +7874,146 @@ Please check your shortcut settings!
-
+
No reply received from the tag update server.
-
+
Invalid reply received from the tag update server.
+
+ StorageSettingsPage
+
+
+
+
+ Success
+
+
+
+
+ Cached card pictures have been reset.
+
+
+
+
+ Downloaded card pictures have been reset.
+
+
+
+
+ Error
+
+
+
+
+ One or more downloaded card pictures could not be cleared.
+
+
+
+
+ In-memory (currently loaded) card pictures have been reset.
+
+
+
+
+ Card Picture Loader Caching Method:
+
+
+
+
+ The network cache is the preferred way of storing images. Downloaded images are stored here until the size of the cache exceeds the configured size. Cockatrice automatically monitors this cache and deletes the least recently seen card images to ensure the cache does not exceed the configured size.
+
+
+
+
+ Writing card images directly to a folder on your hard drive is another way of storing images. This does not change how Cockatrice accesses or downloads images. Cockatrice will NOT automatically monitor and clear this folder, so if you enable this option, it is up to you to ensure sufficient available space. It should also be noted that if a provider outage causes you to download the wrong picture (i.e. wrong printing) you will be stuck with it until you manually delete the file, as opposed to using the network cache, which automatically rotates and thus correct errors after a while.
+
+
+
+
+ This is the in-memory picture cache used by the application at runtime. It determines how much memory (RAM) Cockatrice can use before it has to fetch card images from the hard disk again. Increasing this will allow more card images to be displayed at once but shouldn't be necessary. Clearing this will make Cockatrice reload all images from the network cache or the disk.
+
+
+
+
+ Delete Cached Images
+
+
+
+
+ Delete Saved Images
+
+
+
+
+ Clear In-Memory Images
+
+
+
+
+ Card Picture Loader Cache Method
+
+
+
+
+ Network Cache
+
+
+
+
+ Filesystem
+
+
+
+
+ In-Memory Picture Cache
+
+
+
+
+ Network Cache Size:
+
+
+
+
+ On-disk cache for downloaded pictures
+
+
+
+
+ Redirect Cache TTL:
+
+
+
+
+ How long cached redirects for urls are valid for.
+
+
+
+
+ Picture Cache Size:
+
+
+
+
+ In-memory cache for pictures not currently on screen
+
+
+
+
+ Naming scheme:
+
+
+
+
+ Day(s)
+
+
+
TabAccount
@@ -7702,117 +8149,117 @@ Please check your shortcut settings!
TabArchidekt
-
-
+
+
Desc.
-
-
+
+
AND
-
-
+
+
Require ALL selected colors
-
-
+
+
Deck name...
-
-
+
+
Owner...
-
-
+
+
Packages
-
-
+
+
Advanced Filters
-
+
Bracket:
-
-
+
+
Any
-
-
+
+
Contains card...
-
-
+
+
Commander...
-
-
+
+
Tag...
-
-
+
+
Deck Size
-
+
Cards:
-
-
+
+
Asc.
-
+
Sort by:
-
+
Filter by:
-
+
Display Settings
-
-
+
+
Search
-
-
+
+
Formats
@@ -7822,6 +8269,54 @@ Please check your shortcut settings!
+
+ TabCardArtRules
+
+
+ Card:
+
+
+
+
+ ProviderId:
+
+
+
+
+ Mode:
+
+
+
+
+ Reason:
+
+
+
+
+ Type a card name...
+
+
+
+
+ Add rule
+
+
+
+
+ Remove rule
+
+
+
+
+ Refresh
+
+
+
+
+ Card Art Rules
+
+
+
TabDeckEditor
@@ -7870,7 +8365,7 @@ Please check your shortcut settings!
-
+
Deck: %1
@@ -7878,55 +8373,49 @@ Please check your shortcut settings!
TabDeckEditorVisual
-
+
Visual Deck: %1
-
+
&Visual Deck Editor
-
-
+
+
Card Info
-
-
+
+
Deck
-
-
- Filters
-
-
-
-
+
&View
-
+
Printing
-
+
Visible
-
+
Floating
-
+
Reset layout
@@ -7934,22 +8423,22 @@ Please check your shortcut settings!
TabDeckEditorVisualTabWidget
-
+
Visual Deck View
-
+
Visual Database Display
-
+
Deck Analytics
-
+
Sample Hand
@@ -7957,133 +8446,133 @@ Please check your shortcut settings!
TabDeckStorage
-
+
Local file system
-
+
Server deck storage
-
-
+
+
Open in deck editor
-
+
Rename deck or folder
-
+
Upload deck
-
+
Download deck
-
-
-
+
+
+
New folder
-
+
Delete
-
+
Open decks folder
-
+
Rename local folder
-
+
Rename local file
-
+
New name:
-
-
-
-
+
+
+
+
Error
-
+
Rename failed
-
-
+
+
Invalid deck file
-
+
Enter deck name
-
+
This decklist does not have a name.
Please enter a name:
-
+
Unnamed deck
-
+
Failed to upload deck to server
-
+
Delete local file
-
+
Are you sure you want to delete the selected files?
-
+
Delete remote decks
-
+
Are you sure you want to delete the selected decks?
-
-
+
+
Name of new folder:
@@ -8155,191 +8644,191 @@ Please enter a name:
TabGame
-
-
-
+
+
+
Replay
-
-
+
+
Game
-
-
+
+
Player List
-
-
+
+
Card Info
-
-
+
+
Messages
-
-
+
+
Replay Timeline
-
+
&Phases
-
+
&Game
-
+
Next &phase
-
+
Next phase with &action
-
+
Next &turn
-
+
Reverse turn order
-
+
&Remove all local arrows
-
+
Rotate View Cl&ockwise
-
+
Rotate View Co&unterclockwise
-
+
Game &information
-
+
Un&concede
-
-
-
+
+
+
&Concede
-
+
&Leave game
-
+
C&lose replay
-
+
&Focus Chat
-
+
&Say:
-
+
Selected cards
-
+
&View
-
+
Visible
-
+
Floating
-
+
Reset layout
-
+
Concede
-
+
Are you sure you want to concede this game?
-
+
Unconcede
-
+
You have already conceded. Do you want to return to this game?
-
+
Leave game
-
+
Are you sure you want to leave this game?
-
+
A player has joined game #%1
-
+
%1 has joined the game
-
+
You have been kicked out of the game.
@@ -8398,114 +8887,114 @@ Please enter a name:
-
+
Username:
-
+
IP Address:
-
+
Game Name:
-
+
GameID:
-
+
Message:
-
+
Main Room
-
+
Game Room
-
+
Private Chat
-
+
Past X Days:
-
+
Today
-
+
Last Hour
-
+
Maximum Results:
-
+
At least one filter is required.
The more information you put in, the more specific your results will be.
-
+
Get User Logs
-
+
Clear Filters
-
+
Filters
-
+
Log Locations
-
+
Date Range
-
+
Maximum Results
-
-
+
+
Message History
-
+
Failed to collect message history information.
-
+
There are no messages for the selected filters.
@@ -8523,27 +9012,27 @@ The more information you put in, the more specific your results will be.
-
+
%1 - Private chat
-
+
This user is ignoring you, they cannot see your messages in main chat and you cannot join their games.
-
+
Private message from
-
+
%1 has left the server.
-
+
%1 has joined the server.
@@ -8551,180 +9040,180 @@ The more information you put in, the more specific your results will be.
TabReplays
-
+
Local file system
-
+
Server replay storage
-
-
+
+
Watch replay
-
+
Rename
-
-
+
+
New folder
-
-
+
+
Delete
-
+
Open replays folder
-
+
Download replay
-
+
Toggle expiration lock
-
+
Get replay share code
-
-
+
+
Look up replay by share code
-
+
Rename local folder
-
+
Rename local file
-
+
New name:
-
+
Error
-
+
Rename failed
-
+
Name of new folder:
-
+
Delete local file
-
+
Are you sure you want to delete the selected files?
-
+
Are you sure you want to delete the selected replays?
-
+
Failed to get code
-
-
+
+
Either this server does not support replay sharing, or does not permit replay sharing for you.
-
-
-
+
+
+
Failed
-
+
Could not get replay code
-
+
Replay Share Code
-
+
Others can use this code to add the replay to their list of remote replays:
%1
-
+
Copy to clipboard
-
+
Replay share code
-
+
Replay code found
-
+
Replay was added, or you already had access to it.
-
+
Replay code not found
-
+
Failed to submit code
-
+
Unexpected error
-
+
Delete remote replay
@@ -8737,47 +9226,62 @@ The more information you put in, the more specific your results will be.
TabRoom
-
+
+ Friends
+
+
+
+
+ Online
+
+
+
+
+ Ignored
+
+
+
+
&Say:
-
+
Chat
-
+
&Room
-
+
&Leave room
-
+
&Clear chat
-
+
Chat Settings...
-
+
mentioned you.
-
+
Click to view
-
+
You are flooding the chat. Please wait a couple of seconds.
@@ -8790,30 +9294,30 @@ The more information you put in, the more specific your results will be.
-
-
-
-
+
+
+
+
Error
-
+
Failed to join the server room: it doesn't exist on the server.
-
+
The server thinks you are in the server room but your client is unable to display it. Try restarting your client.
-
+
You do not have the required permission to join this server room.
-
+
Failed to join the server room due to an unknown error: %1.
@@ -8821,97 +9325,97 @@ The more information you put in, the more specific your results will be.
TabSupervisor
-
+
Deck Editor
-
+
Visual Deck Editor
-
+
EDHRec
-
+
Archidekt
-
+
Home
-
+
&Visual Deck Storage
-
+
Visual Database Display
-
+
Server
-
+
Account
-
+
Deck Storage
-
+
Game Replays
-
+
Administration
-
+
Logs
-
+
Are you sure?
-
+
There are still open games. Are you sure you want to quit?
-
+
Click to view
-
+
Your buddy %1 has signed on!
-
+
Unknown Event
-
+
The server has sent you a message that your client does not understand.
This message might mean there is a new version of Cockatrice available or this server is running a custom or pre-release version.
@@ -8919,38 +9423,38 @@ To update your client, go to Help -> Check for Updates.
-
+
Idle Timeout
-
+
You are about to be logged out due to inactivity.
-
+
Promotion
-
+
You have been promoted. Please log out and back in for changes to take effect.
-
+
Warned
-
+
You have received a warning due to %1.
Please refrain from engaging in this activity or further actions may be taken against you. If you have any questions, please private message a moderator.
-
+
You have received the following message from the server.
(custom messages like these could be untranslated)
@@ -8959,12 +9463,12 @@ Please refrain from engaging in this activity or further actions may be taken ag
TabVisualDatabaseDisplay
-
+
Database Display
-
+
Visual Database Display
@@ -9001,42 +9505,42 @@ Please refrain from engaging in this activity or further actions may be taken ag
TranslateCounterName
-
+
Life
-
+
White
-
+
Blue
-
+
Black
-
+
Red
-
+
Green
-
+
Colorless
-
+
Other
@@ -9044,11 +9548,69 @@ Please refrain from engaging in this activity or further actions may be taken ag
UpdateDownloader
-
+
Could not open the file for reading.
+
+ UserCardArtSettingsDialog
+
+
+ Card Art Settings
+
+
+
+
+ Type a card name...
+
+
+
+
+ Card name:
+
+
+
+
+ Card ProviderId:
+
+
+
+
+ Left margin (%):
+
+
+
+
+ Right margin (%):
+
+
+
+
+ Vertical offset:
+
+
+
+
+ Zoom:
+
+
+
+
+ Parameters
+
+
+
+
+ Preview
+
+
+
+
+ Remove Banner Card
+
+
+
UserContextMenu
@@ -9166,7 +9728,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
Ban History
@@ -9181,77 +9743,87 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
Failed to collect ban information.
-
-
-
+
+
+
Warning History
-
+
Warning Time;Moderator;User Name;Reason
-
+
User has never been warned.
-
+
Failed to collect warning information.
-
+
Failed to get admin notes.
-
-
+
+
Success
-
+
Successfully promoted user.
-
+
Successfully demoted user.
-
-
-
+
+ Kick Player
+
+
+
+
+ Are you sure you want to kick this player from the game?
+
+
+
+
+
+
Failed
-
+
Failed to promote user.
-
+
Failed to demote user.
-
+
Copy hash to clipboard
-
+
Remove this user's messages
@@ -9259,109 +9831,116 @@ Please refrain from engaging in this activity or further actions may be taken ag
UserInfoBox
-
+
Location:
-
+
Account Age:
-
+
Edit
-
+
Change password
-
+
Change avatar
-
+
Administrator
-
+
Moderator
-
+
Registered user
-
-
+
+
Unregistered user
-
+
Judge
-
+
Unknown
-
+
The entered password does not match your account.
-
-
-
+
+
+
+
Information
-
+
User information updated.
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
Error
-
+
User Information
-
+
Real Name:
-
+
User Level:
+
+
+ Edit Banner Card
+
+
-
+
%n Year(s),
amount of years (only shown if more than 0)
@@ -9370,7 +9949,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
%10%n Day(s) %20
amount of years (if more than 0), amount of days, date in local short format
@@ -9379,212 +9958,433 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
Enter Password
-
+
Password verification is required in order to change your email address
-
-
-
+
+
+
An error occurred while trying to update your user information.
-
- This server does not permit you to update your user informations.
+
+ The selected card is blacklisted on this server or another error occurred.
-
- Password changed.
+
+ Banner card removed.
-
- This server does not permit you to change your password.
-
-
-
-
- The new password is too short.
-
-
-
-
- The old password is incorrect.
-
-
-
-
- Avatar updated.
-
-
-
-
- This server does not permit you to update your avatar.
+
+ Banner card updated.
- An error occured while trying to updater your avatar.
+ This server does not permit you to update your user informations.
+
+
+
+
+ Password changed.
+
+
+
+
+ This server does not permit you to change your password.
+
+
+
+
+ The new password is too short.
+
+
+
+
+ The old password is incorrect.
+
+
+
+
+ Avatar updated.
+
+
+
+
+ This server does not permit you to update your avatar.
+
+
+
+
+ An error occured while trying to update your avatar.
+
+
+
+
+ This server does not permit you to update your user informations.
+ An error occured while trying to updater your avatar.
+
+
+
+
+ UserInfoPopup
+
+
+
+ Games
+
+
+
+
+ Chat
+
+
+
+
+ Open private chat
+
+
+
+
+ Profile
+
+
+
+
+ View user profile
+
+
+
+
+ Show this user's games
+
+
+
+
+ − Buddy
+
+
+
+
+ Remove from buddy list
+
+
+
+
+ + Buddy
+
+
+
+
+ Add to buddy list
+
+
+
+
+ − Ignore
+
+
+
+
+ Remove from ignore list
+
+
+
+
+ + Ignore
+
+
+
+
+ Add to ignore list
+
+
+
+
+ Ban
+
+
+
+
+ Ban from server
+
+
+
+
+ Warn
+
+
+
+
+ Warn user
+
+
+
+
+ Ban log
+
+
+
+
+ View ban history
+
+
+
+
+ Warn log
+
+
+
+
+ View warning history
+
+
+
+
+ Notes
+
+
+
+
+ View admin notes
+
+
+
+
+ − Mod
+
+
+
+
+ Demote from moderator
+
+
+
+
+ + Mod
+
+
+
+
+ Promote to moderator
+
+
+
+
+ − Judge
+
+
+
+
+ Demote from judge
+
+
+
+
+ + Judge
+
+
+
+
+ Promote to judge
+
+
+
+
+ Join game
+
+
+
+
+ Spectate
+
+
+
+
+
+ Loading games…
+
+
+
+
+ Could not load games.
+
+
+
+
+ No active games.
UserInterfaceSettingsPage
-
+
General interface settings
-
+
&Double-click cards to play them (instead of single-click)
-
+
&Clicking plays all selected cards (instead of just the clicked card)
-
+
&Play all nonlands onto the stack (not the battlefield) by default
-
+
Do not delete &arrows inside of subphases
-
+
Close card view window when last card is removed
-
+
Auto focus search bar when card view window is opened
-
+
Annotate card text on tokens
-
- Show selection counter during drag selection
+
+ Show selection count during drag selection
-
- Show total selection counter
+
+ Show total selection count
-
+
+ Show subtype breakdown in selection tally
+
+
+
+
Use tear-off menus, allowing right click menus to persist on screen
-
+
+ Keep game chat focused when clicking in game (Note: disables card view search bar)
+
+
+
+
Notifications settings
-
+
Enable notifications in taskbar
-
+
Notify in the taskbar for game events while you are spectating
-
+
Notify in the taskbar when users in your buddy list connect
-
+
Animation settings
-
+
&Tap/untap animation
-
+
Deck editor/storage settings
-
+
Open deck in new tab by default
-
+
Use visual deck storage in game lobby
-
+
Use selection animation for Visual Deck Storage
-
+
When adding a tag in the visual deck storage to a .txt deck:
-
+
do nothing
-
+
ask to convert to .cod
-
+
always convert to .cod
-
+
Default deck editor type
-
+
Classic Deck Editor
-
+
Visual Deck Editor
-
+
Replay settings
-
+
Buffer time for backwards skip via shortcut:
@@ -9592,22 +10392,22 @@ Please refrain from engaging in this activity or further actions may be taken ag
UserListWidget
-
+
Users connected to server: %1
-
+
Users in this room: %1
-
+
Buddies online: %1 / %2
-
+
Ignored users online: %1 / %2
@@ -9615,35 +10415,45 @@ Please refrain from engaging in this activity or further actions may be taken ag
UtilityMenu
-
+
Increment all card counters
-
+
&Untap all permanents
-
+
R&oll die...
-
+
+ Flip coin
+
+
+
+
&Create token...
-
+
C&reate another token
-
+
Cr&eate predefined token
+
+
+ C&reate another %1 token
+
+
VisualDatabaseDisplayColorFilterWidget
@@ -9695,72 +10505,72 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayFilterToolbarWidget
-
+
Sort by
-
+
Filter by
-
+
Save and load filters
-
+
Filter by exact card name
-
+
Filter by card main-type
-
+
Filter by card sub-type
-
+
Filter by set
-
+
Filter by format legality
-
+
Save/Load
-
+
Name
-
+
Main Type
-
+
Sub Type
-
+
Sets
-
+
Formats
@@ -9768,22 +10578,22 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayFormatLegalityFilterWidget
-
+
Show formats with at least:
-
+
cards
-
+
Do not display formats with less than this amount of cards in the database
-
+
Filter mode (AND/OR/NOT conjunctions of filters)
@@ -9801,32 +10611,32 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayMainTypeFilterWidget
-
+
Show main types with at least:
-
+
cards
-
+
Do not display card main-types with less than this amount of cards in the database
-
+
Filter mode (AND/OR/NOT conjunctions of filters)
-
+
Mode: Exact Match
-
+
Mode: Includes
@@ -9834,27 +10644,27 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayNameFilterWidget
-
+
Filter by name... (Exact match)
-
+
Load from Deck
-
+
Apply all card names in currently loaded deck as exact match name filters
-
+
Load from Clipboard
-
+
Apply all card names in clipboard as exact match name filters
@@ -9862,7 +10672,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayRecentSetFilterSettingsWidget
-
+
Filter to most recent sets
@@ -9870,19 +10680,19 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplaySetFilterWidget
-
+
Search sets...
-
-
+
+
Mode: Exact Match
-
-
+
+
Mode: Includes
@@ -9890,37 +10700,37 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplaySubTypeFilterWidget
-
+
Search subtypes...
-
+
Show sub types with at least:
-
+
cards
-
+
Do not display card sub-types with less than this amount of cards in the database
-
+
Filter mode (AND/OR/NOT conjunctions of filters)
-
+
Mode: Exact Match
-
+
Mode: Includes
@@ -9928,23 +10738,23 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayWidget
-
+
Search by card name (or search expressions)
-
+
Visual
-
+
Loading database ...
-
+
Clear all filters
@@ -9983,17 +10793,17 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
Toggle Layout: Overlap
-
+
Change how cards are displayed within zones (i.e. overlapped or fully visible.)
-
+
Toggle Layout: Flat
@@ -10022,17 +10832,17 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckEditorWidget
-
+
Type a card name here for suggestions from the database...
-
+
Quick search and add card
-
+
Search for closest match in the database (with auto-suggestions) and add preferred printing to the deck on pressing enter
@@ -10150,43 +10960,43 @@ Please refrain from engaging in this activity or further actions may be taken ag
WarningDialog
-
+
Which warning would you like to send?
-
+
Redact all messages from this user in all rooms
-
+
&OK
-
+
&Cancel
-
+
Warn user for misconduct
-
-
+
+
Error
-
+
User name to send a warning to can not be blank, please specify a user to warn.
-
+
Warning to use can not be blank, please select a valid warning to send.
@@ -10194,133 +11004,133 @@ Please refrain from engaging in this activity or further actions may be taken ag
WndSets
-
+
Move selected set to the top
-
+
Move selected set up
-
+
Move selected set down
-
+
Move selected set to the bottom
-
+
Search by set name, code, or type
-
+
Default order
-
+
Restore original art priority order
-
+
Enable all sets
-
+
Disable all sets
-
+
Enable selected set(s)
-
+
Disable selected set(s)
-
+
Deck Editor
-
+
Use CTRL+A to select all sets in the view.
-
+
Only cards in enabled sets will appear in the card list of the deck editor.
-
+
Image priority is decided in the following order:
-
+
first the CUSTOM Folder (%1), then the Enabled Sets in this dialog (Top to Bottom)
%1 is a link to the wiki
-
+
Include cards rebalanced for Alchemy [requires restart]
-
+
Card Art
-
+
How to use custom card art
-
+
Hints
-
+
Note
-
+
Sorting by column allows you to find a set while not changing set priority.
-
+
To enable ordering again, click the column header until this message disappears.
-
+
Use the current sorting as the set priority instead
-
+
Sorts the set priority using the same column
-
+
Manage sets
@@ -10328,72 +11138,72 @@ Please refrain from engaging in this activity or further actions may be taken ag
ZoneViewWidget
-
+
Search by card name (or search expressions)
-
+
Ungrouped
-
+
Group by Type
-
+
Group by Mana Value
-
+
Group by Color
-
+
Unsorted
-
+
Sort by Name
-
+
Sort by Type
-
+
Sort by Mana Cost
-
+
Sort by Colors
-
+
Sort by P/T
-
+
Sort by Set
-
+
shuffle when closing
-
+
pile view
@@ -10401,7 +11211,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
i18n
-
+
English
@@ -10409,12 +11219,12 @@ Please refrain from engaging in this activity or further actions may be taken ag
main
-
+
Connect on startup
-
+
Debug to file
@@ -10428,7 +11238,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
Deck Editor
@@ -10509,7 +11319,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
Replays
@@ -10624,129 +11434,129 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
-
+
+
Load Deck from Clipboard...
-
+
Edit Deck in Clipboard, Annotated
-
+
Edit Deck in Clipboard
-
+
New Deck
-
+
Open Custom Pictures Folder
-
+
Print Deck...
-
+
Delete Card
-
-
+
+
Reset Layout
-
+
Save Deck
-
+
Save Deck as...
-
+
Save Deck to Clipboard, Annotated
-
+
Save Deck to Clipboard, Annotated (No Set Info)
-
+
Save Deck to Clipboard
-
+
Save Deck to Clipboard (No Set Info)
-
+
Load Local Deck...
-
+
Load Remote Deck...
-
+
Set Ready to Start
-
+
Toggle Sideboard Lock
-
+
Add Green Counter
-
+
Remove Green Counter
-
+
Set Green Counters...
-
+
Add Red Counter
-
+
Remove Red Counter
-
+
Set Red Counters...
-
+
Add Life Counter
@@ -10756,724 +11566,744 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+
+ Load deck from online service...
+
+
+
+
+ Load from website...
+
+
+
+
Unload Deck
-
+
Force Start
-
+
Add Card Counter (F)
-
+
Remove Card Counter (F)
-
+
Set Card Counters (F)...
-
+
Add Card Counter (E)
-
+
Remove Card Counter (E)
-
+
Set Card Counters (E)...
-
+
Add Card Counter(D)
-
+
Remove Card Counter (D)
-
+
Set Card Counters (D)...
-
+
Add Card Counter (C)
-
+
Remove Card Counter (C)
-
+
Set Card Counters (C)...
-
+
Add Card Counter (B)
-
+
Remove Card Counter (B)
-
+
Set Card Counters (B)...
-
+
Add Card Counter (A)
-
+
Remove Card Counter (A)
-
+
Set Card Counters (A)...
-
+
Remove Life Counter
-
+
Set Life Counters...
-
+
Add White Counter
-
+
Remove White Counter
-
+
Set White Counters...
-
+
Add Blue Counter
-
+
Remove Blue Counter
-
+
Set Blue Counters...
-
+
Add Black Counter
-
+
Remove Black Counter
-
+
Set Black Counters...
-
+
Add Colorless Counter
-
+
Remove Colorless Counter
-
+
Set Colorless Counters...
-
+
Add Other Counter
-
+
Remove Other Counter
-
+
Set Other Counters...
-
+
Increment all card counters
-
+
Add Power (+1/+0)
-
+
Remove Power (-1/-0)
-
+
Move Toughness to Power (+1/-1)
-
+
Add Toughness (+0/+1)
-
+
Remove Toughness (-0/-1)
-
+
Move Power to Toughness (-1/+1)
-
+
Add Power and Toughness (+1/+1)
-
+
Remove Power and Toughness (-1/-1)
-
+
Set Power and Toughness...
-
+
Reset Power and Toughness
-
+
Untap
-
+
Upkeep
-
+
Draw
-
+
First Main Phase
-
+
Start Combat
-
+
Attack
-
+
Block
-
+
Damage
-
+
End Combat
-
+
Second Main Phase
-
+
End
-
+
Next Phase
-
+
Next Phase Action
-
+
Next Turn
-
+
Hide Card in Reveal Window
-
+
Tap / Untap Card
-
+
Untap All
-
+
Toggle Skip Untapping
Toggle Untap
-
+
Turn Card Over
-
+
Peek Card
-
+
Play Card
-
+
Play Card, Face Down
-
+
Attach Card...
-
+
Unattach Card
-
+
Clone Card
-
+
Create Token...
-
+
Create All Related Tokens
-
+
Create Another Token
-
+
Set Annotation...
-
+
+ Reduce Life by Power
+
+
+
+
Select All Cards in Zone
-
+
Select All Cards in Row
-
+
Select All Cards in Column
-
+
Reveal Selected Cards to All Players
-
-
+
+
Bottom of Library
-
-
-
-
+
+
+
+
Exile
-
-
-
-
+
+
+
+
Graveyard
-
-
+
+
Hand
-
-
+
+
Top of Library
-
-
+
+
Battlefield, Face Down
-
+
Battlefield
-
+
Library
-
+
Sideboard
-
+
Top Cards of Library
-
+
Bottom Cards of Library
-
+
Close Recent View
-
-
+
+
Stack
-
-
+
+
Graveyard (Multiple)
-
-
+
+
Graveyard (Multiple), Face Down
-
-
+
+
Exile (Multiple)
-
-
+
+
Exile (Multiple), Face Down
-
+
Stack Until Found
-
+
Draw Bottom Card
-
+
Draw Multiple Cards from Bottom...
-
+
Draw Arrow...
-
+
Remove Local Arrows
-
+
Leave Game
-
+
Concede
-
+
Roll Dice...
-
+
+ Flip Coin
+
+
+
+
Shuffle Library
-
+
Shuffle Top Cards of Library
-
+
Shuffle Bottom Cards of Library
-
+
Mulligan
-
+
Mulligan (Same hand size)
-
+
Mulligan (Hand size - 1)
-
+
Draw a Card
-
+
Draw Multiple Cards...
-
+
Undo Draw
-
+
Always Reveal Top Card
-
+
Always Look At Top Card
-
+
Sort Hand by Name
-
+
Sort Hand by Type
-
+
Sort Hand by Mana Value
-
+
Reveal Hand to All Players
-
+
Reveal Random Card to All Players
-
+
Rotate View Clockwise
-
+
Rotate View Counterclockwise
-
+
Unfocus Text Box
-
+
Focus Chat
-
+
Clear Chat
-
+
Refresh
-
+
Skip Forward
-
+
Skip Backward
-
+
Skip Forward by a lot
-
+
Skip Backward by a lot
-
+
Play/Pause
-
+
Toggle Fast Forward
-
+
Home
-
+
Visual Deck Storage
-
+
Deck Storage
-
+
Server
-
+
Account
-
+
Administration
-
+
Logs
diff --git a/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp b/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp
index 75cedcafc..53dde125f 100644
--- a/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp
+++ b/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
ConnectionController::ConnectionController(QWidget *dialogParent, QObject *parent)
: QObject(parent), dialogParent(dialogParent)
@@ -295,6 +296,15 @@ void ConnectionController::onLoginError(int r,
return;
}
+ case Response::RespPasswordChangeRequired: {
+ QMessageBox::information(
+ dialogParent, tr("Password Change Required"),
+ tr("An administrator has reset your password. Please contact your server administrator to obtain "
+ "your temporary password, then log in and change it via Account -> Change Password."));
+ remoteClient->disconnectFromServer();
+ return;
+ }
+
case Response::RespServerFull: {
QMessageBox::critical(dialogParent, tr("Server Full"),
tr("The server has reached its maximum user capacity, please check back later."));
diff --git a/cockatrice/src/client/network/update/card_spoiler/spoiler_background_updater.cpp b/cockatrice/src/client/network/update/card_spoiler/spoiler_background_updater.cpp
index 7194c46e5..dae633717 100644
--- a/cockatrice/src/client/network/update/card_spoiler/spoiler_background_updater.cpp
+++ b/cockatrice/src/client/network/update/card_spoiler/spoiler_background_updater.cpp
@@ -14,6 +14,8 @@
#include
#include
#include
+#include
+#include
#include
#define SPOILERS_STATUS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/SpoilerSeasonEnabled"
@@ -21,7 +23,7 @@
SpoilerBackgroundUpdater::SpoilerBackgroundUpdater(QObject *apParent) : QObject(apParent), cardUpdateProcess(nullptr)
{
- isSpoilerDownloadEnabled = SettingsCache::instance().getDownloadSpoilersStatus();
+ isSpoilerDownloadEnabled = SettingsCache::instance().downloads().getDownloadSpoilersStatus();
if (isSpoilerDownloadEnabled) {
// Start the process of checking if we're in spoiler season
// File exists means we're in spoiler season
@@ -75,7 +77,7 @@ void SpoilerBackgroundUpdater::actDownloadFinishedSpoilersFile()
bool SpoilerBackgroundUpdater::deleteSpoilerFile()
{
- QString fileName = SettingsCache::instance().getSpoilerCardDatabasePath();
+ QString fileName = SettingsCache::instance().paths().getSpoilerCardDatabasePath();
QFileInfo fi(fileName);
QDir fileDir(fi.path());
QFile file(fileName);
@@ -126,7 +128,7 @@ void SpoilerBackgroundUpdater::actCheckIfSpoilerSeasonEnabled()
bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
{
- QString fileName = SettingsCache::instance().getSpoilerCardDatabasePath();
+ QString fileName = SettingsCache::instance().paths().getSpoilerCardDatabasePath();
QFileInfo fi(fileName);
QDir fileDir(fi.path());
diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp
index b6bc8a47d..eaa5d96ac 100644
--- a/cockatrice/src/client/settings/cache_settings.cpp
+++ b/cockatrice/src/client/settings/cache_settings.cpp
@@ -1,20 +1,41 @@
#include "cache_settings.h"
-#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
-#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "../network/update/client/release_channel.h"
#include "card_counter_settings.h"
+#include "shortcuts_settings.h"
#include "version_string.h"
-#include
-#include
#include
#include
#include
#include
#include
#include
+#include
+#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
Q_GLOBAL_STATIC(SettingsCache, settingsCache)
@@ -52,104 +73,6 @@ QString SettingsCache::getNetworkCachePath() const
return getCachePath() + "/downloaded/";
}
-void SettingsCache::translateLegacySettings()
-{
- if (isPortableBuild) {
- return;
- }
-
- // Layouts
- QFile layoutFile(getSettingsPath() + "layouts/deckLayout.ini");
- if (layoutFile.exists()) {
- if (layoutFile.copy(getSettingsPath() + "layouts.ini")) {
- layoutFile.remove();
- }
- }
-
- QStringList usedKeys;
- QSettings legacySetting;
-
- // Sets
- legacySetting.beginGroup("sets");
- QStringList setsGroups = legacySetting.childGroups();
- for (int i = 0; i < setsGroups.size(); i++) {
- legacySetting.beginGroup(setsGroups.at(i));
- cardDatabase()->setEnabled(setsGroups.at(i), legacySetting.value("enabled").toBool());
- cardDatabase()->setIsKnown(setsGroups.at(i), legacySetting.value("isknown").toBool());
- cardDatabase()->setSortKey(setsGroups.at(i), legacySetting.value("sortkey").toUInt());
- legacySetting.endGroup();
- }
- QStringList setsKeys = legacySetting.allKeys();
- for (int i = 0; i < setsKeys.size(); ++i) {
- usedKeys.append("sets/" + setsKeys.at(i));
- }
- legacySetting.endGroup();
-
- // Servers
- legacySetting.beginGroup("server");
- servers().setPreviousHostLogin(legacySetting.value("previoushostlogin").toInt());
- servers().setPreviousHostList(legacySetting.value("previoushosts").toStringList());
- servers().setAutoConnect(legacySetting.value("auto_connect").toInt());
- servers().setFPHostName(legacySetting.value("fphostname").toString());
- servers().setFPPort(legacySetting.value("fpport").toString());
- servers().setFPPlayerName(legacySetting.value("fpplayername").toString());
- usedKeys.append(legacySetting.allKeys());
- QStringList allKeysServer = legacySetting.allKeys();
- for (int i = 0; i < allKeysServer.size(); ++i) {
- usedKeys.append("server/" + allKeysServer.at(i));
- }
- legacySetting.endGroup();
-
- // Messages
- legacySetting.beginGroup("messages");
- QStringList allMessages = legacySetting.allKeys();
- for (int i = 0; i < allMessages.size(); ++i) {
- if (allMessages.at(i) != "count") {
- QString temp = allMessages.at(i);
- int index = temp.remove("msg").toInt();
- messages().setMessageAt(index, legacySetting.value(allMessages.at(i)).toString());
- }
- }
- messages().setCount(legacySetting.value("count").toInt());
- QStringList allKeysmessages = legacySetting.allKeys();
- for (int i = 0; i < allKeysmessages.size(); ++i) {
- usedKeys.append("messages/" + allKeysmessages.at(i));
- }
- legacySetting.endGroup();
-
- // Game filters
- legacySetting.beginGroup("filter_games");
- gameFilters().setGameNameFilter(legacySetting.value("game_name_filter").toString());
- gameFilters().setHideIgnoredUserGames(legacySetting.value("hide_ignored_user_games").toBool());
- gameFilters().setMinPlayers(legacySetting.value("min_players").toInt());
-
- if (legacySetting.value("max_players").toInt() > 1) {
- gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt());
- } else {
- gameFilters().setMaxPlayers(99); // This prevents a bug where no games will show if max was not set before
- }
-
- QStringList allFilters = legacySetting.allKeys();
- for (int i = 0; i < allFilters.size(); ++i) {
- if (allFilters.at(i).startsWith("game_type")) {
- gameFilters().setGameHashedTypeEnabled(allFilters.at(i), legacySetting.value(allFilters.at(i)).toBool());
- }
- }
- QStringList allKeysfilter_games = legacySetting.allKeys();
- for (int i = 0; i < allKeysfilter_games.size(); ++i) {
- usedKeys.append("filter_games/" + allKeysfilter_games.at(i));
- }
- legacySetting.endGroup();
-
- QStringList allLegacyKeys = legacySetting.allKeys();
- for (int i = 0; i < allLegacyKeys.size(); ++i) {
- if (usedKeys.contains(allLegacyKeys.at(i))) {
- continue;
- }
- settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i)));
- }
-}
-
QString SettingsCache::getSafeConfigPath(QString configEntry, QString defaultPath) const
{
QString tmp = settings->value(configEntry).toString();
@@ -183,11 +106,18 @@ SettingsCache::SettingsCache()
qCInfo(SettingsCacheLog) << "Portable mode enabled";
}
- // define a dummy context that will be used where needed
- QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
-
QString settingsPath = getSettingsPath();
+
settings = new QSettings(settingsPath + "global.ini", QSettings::IniFormat, this);
+
+ // Migrate from legacy NativeFormat settings to per-class INI files (runs at most once)
+ if (!isPortableBuild) {
+ SettingsMigration::migrateLegacySettings(settingsPath);
+ }
+
+ // Migrate settings from global.ini to per-class INI files (runs at most once)
+ SettingsMigration::migrateSettingsFromGlobalIni(settingsPath);
+
shortcutsSettings = new ShortcutsSettings(settingsPath, this);
cardDatabaseSettings = new CardDatabaseSettings(settingsPath, this);
serversSettings = new ServersSettings(settingsPath, this);
@@ -198,997 +128,51 @@ SettingsCache::SettingsCache()
recentsSettings = new RecentsSettings(settingsPath, this);
cardOverrideSettings = new CardOverrideSettings(settingsPath, this);
debugSettings = new DebugSettings(settingsPath, this);
-
cardCounterSettings = new CardCounterSettings(settingsPath, this);
- if (!QFile(settingsPath + "global.ini").exists()) {
- translateLegacySettings();
- }
+ tabsSettings = new TabsSettings(settingsPath, this);
+ soundSettings = new SoundSettings(settingsPath, this);
+ gameSettings = new GameSettings(settingsPath, this);
+ chatSettings = new ChatSettings(settingsPath, this);
+ cacheStorageSettings = new CacheStorageSettings(settingsPath, this);
+ updatesSettings = new UpdatesSettings(settingsPath, this);
+ personalSettings = new PersonalSettings(settingsPath, this);
+ cardsDisplaySettings = new CardsDisplaySettings(settingsPath, this);
+ interfaceSettings = new InterfaceSettings(settingsPath, this);
+ deckEditorSettings = new DeckEditorSettings(settingsPath, this);
+ pathsSettings = new PathsSettings(settingsPath, this);
+ visualDeckStorageSettings = new VisualDeckStorageSettings(settingsPath, this);
+ appearanceSettings = new AppearanceSettings(settingsPath, this);
+ networkSettings = new NetworkSettings(settingsPath, this);
+ commanderBracketSettings = new CommanderBracketSettings(settingsPath, this);
+
+ // Forward ICardDatabasePathProvider signal from PathsSettings
+ connect(pathsSettings, &PathsSettings::cardDatabasePathChanged, this,
+ &ICardDatabasePathProvider::cardDatabasePathChanged);
// updates - don't reorder them or their index in the settings won't match
// append channels one by one, or msvc will add them in the wrong order.
releaseChannels << new StableReleaseChannel();
releaseChannels << new BetaReleaseChannel();
- mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
+ themeName = appearanceSettings->getThemeName();
- if (settings->contains("personal/startupUpdateCheck")) {
- checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
- } else if (QString(VERSION_STRING).contains("custom", Qt::CaseInsensitive)) {
- checkUpdatesOnStartup = false; // do not run auto updater on custom version
- } else {
- checkUpdatesOnStartup = true; // default to run auto updater
- }
- startupCardUpdateCheckPromptForUpdate =
- settings->value("personal/startupCardUpdateCheckPromptForUpdate", true).toBool();
- startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
- cardUpdateCheckInterval = settings->value("personal/cardUpdateCheckInterval", 7).toInt();
- lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
- alwaysEnableNewSets = settings->value("personal/alwaysEnableNewSets", false).toBool();
- notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
- notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
-
- if (settings->contains("personal/updatereleasechannel")) {
- updateReleaseChannel = settings->value("personal/updatereleasechannel").toInt();
- } else if (QString(VERSION_STRING).contains("beta", Qt::CaseInsensitive)) {
- // default to beta if this is a beta release
- updateReleaseChannel = 1;
- } else {
- updateReleaseChannel = 0; // stable
- }
-
- lang = settings->value("personal/lang").toString();
- keepalive = settings->value("personal/keepalive", 3).toInt();
- timeout = settings->value("personal/timeout", 5).toInt();
-
- // tip of the day settings
- showTipsOnStartup = settings->value("tipOfDay/showTips", true).toBool();
- for (const auto &tipNumber : settings->value("tipOfDay/seenTips").toList()) {
- seenTips.append(tipNumber.toInt());
+ auto definitions = commanderBracketSettings->loadDefinitions();
+ if (definitions.isEmpty()) {
+ definitions = CommanderBracketSettings::defaultDefinitions();
}
+ commanderBracketSettings->reloadDefinitions(definitions);
loadPaths();
-
- themeName = settings->value("theme/name").toString();
-
- homeTabBackgroundSource = settings->value("home/background", "themed").toString();
- homeTabBackgroundShuffleFrequency = settings->value("home/background/shuffleTimer", 0).toInt();
- homeTabDisplayCardName = settings->value("home/background/displayCardName", true).toBool();
-
- tabVisualDeckStorageOpen = settings->value("tabs/visualDeckStorage", true).toBool();
- tabServerOpen = settings->value("tabs/server", true).toBool();
- tabAccountOpen = settings->value("tabs/account", true).toBool();
- tabDeckStorageOpen = settings->value("tabs/deckStorage", true).toBool();
- tabReplaysOpen = settings->value("tabs/replays", true).toBool();
- tabAdminOpen = settings->value("tabs/admin", true).toBool();
- tabLogOpen = settings->value("tabs/log", true).toBool();
-
- // we only want to reset the cache once, then its up to the user
- bool updateCache = settings->value("revert/pixmapCacheSize", false).toBool();
- if (!updateCache) {
- pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
- settings->setValue("personal/pixmapCacheSize", pixmapCacheSize);
- settings->setValue("personal/picturedownloadhq", false);
- settings->setValue("revert/pixmapCacheSize", true);
- } else {
- pixmapCacheSize = settings->value("personal/pixmapCacheSize", PIXMAPCACHE_SIZE_DEFAULT).toInt();
- }
- // sanity check
- if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX) {
- pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
- }
-
- networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
- redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt();
- cardPictureLoaderCacheMethod =
- settings
- ->value("personal/cardPictureLoaderCacheMethod",
- static_cast(CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE))
- .toInt();
- localCardImageStorageNamingScheme =
- settings
- ->value("personal/localCardImageStorageNamingScheme",
- static_cast(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_Set_Collector))
- .toInt();
-
- picDownload = settings->value("personal/picturedownload", true).toBool();
- showStatusBar = settings->value("personal/showStatusBar", false).toBool();
-
- notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
- spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
- buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
- doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
- clickPlaysAllSelected = settings->value("interface/clickPlaysAllSelected", true).toBool();
- playToStack = settings->value("interface/playtostack", true).toBool();
- doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
- startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
- annotateTokens = settings->value("interface/annotatetokens", false).toBool();
- knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
- useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
- cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
- cardViewExpandedRowsMax = settings->value("interface/cardViewExpandedRowsMax", 20).toInt();
- closeEmptyCardView = settings->value("interface/closeEmptyCardView", true).toBool();
- focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
- keepGameChatFocus = settings->value("interface/keepGameChatFocus", false).toBool();
-
- showDragSelectionCount = settings->value("interface/showlassoselectioncount", true).toBool();
- showTotalSelectionCount = settings->value("interface/showpersistentselectioncount", true).toBool();
- showSubtypeSelectionTally = settings->value("interface/showsubtypeselectiontally", true).toBool();
-
- showShortcuts = settings->value("menu/showshortcuts", true).toBool();
- showGameSelectorFilterToolbar = settings->value("menu/showgameselectorfiltertoolbar", true).toBool();
- displayCardNames = settings->value("cards/displaycardnames", true).toBool();
- roundCardCorners = settings->value("cards/roundcardcorners", true).toBool();
- overrideAllCardArtWithPersonalPreference =
- settings->value("cards/overrideallcardartwithpersonalpreference", false).toBool();
- bumpSetsWithCardsInDeckToTop = settings->value("cards/bumpsetswithcardsindecktotop", true).toBool();
- printingSelectorSortOrder = settings->value("cards/printingselectorsortorder", 1).toInt();
- printingSelectorCardSize = settings->value("cards/printingselectorcardsize", 100).toInt();
- includeRebalancedCards = settings->value("cards/includerebalancedcards", true).toBool();
- printingSelectorNavigationButtonsVisible =
- settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
- deckEditorBannerCardComboBoxVisible =
- settings->value("interface/deckeditorbannercardcomboboxvisible", true).toBool();
- deckEditorTagsWidgetVisible = settings->value("interface/deckeditortagswidgetvisible", true).toBool();
- visualDeckStorageCardSize = settings->value("interface/visualdeckstoragecardsize", 100).toInt();
- visualDeckStorageSortingOrder = settings->value("interface/visualdeckstoragesortingorder", 0).toInt();
- visualDeckStorageShowFolders = settings->value("interface/visualdeckstorageshowfolders", true).toBool();
- visualDeckStorageShowTagFilter = settings->value("interface/visualdeckstorageshowtagfilter", true).toBool();
- visualDeckStorageDefaultTagsList =
- settings->value("interface/visualdeckstoragedefaulttagslist", defaultTags).toStringList();
- visualDeckStorageSearchFolderNames = settings->value("interface/visualdeckstoragesearchfoldernames", true).toBool();
- visualDeckStorageShowColorIdentity = settings->value("interface/visualdeckstorageshowcoloridentity", true).toBool();
- visualDeckStorageShowBannerCardComboBox =
- settings->value("interface/visualdeckstorageshowbannercardcombobox", true).toBool();
- visualDeckStorageShowTagsOnDeckPreviews =
- settings->value("interface/visualdeckstorageshowtagsondeckpreviews", true).toBool();
- visualDeckStorageDrawUnusedColorIdentities =
- settings->value("interface/visualdeckstoragedrawunusedcoloridentities", true).toBool();
- visualDeckStorageUnusedColorIdentitiesOpacity =
- settings->value("interface/visualdeckstorageunusedcoloridentitiesopacity", 15).toInt();
- visualDeckStorageTooltipType = settings->value("interface/visualdeckstoragetooltiptype", 0).toInt();
- visualDeckStoragePromptForConversion =
- settings->value("interface/visualdeckstoragepromptforconversion", true).toBool();
- visualDeckStorageAlwaysConvert = settings->value("interface/visualdeckstoragealwaysconvert", false).toBool();
- visualDeckStorageInGame = settings->value("interface/visualdeckstorageingame", true).toBool();
- visualDeckStorageSelectionAnimation =
- settings->value("interface/visualdeckstorageselectionanimation", true).toBool();
- defaultDeckEditorType = settings->value("interface/defaultDeckEditorType", 1).toInt();
- visualDatabaseDisplayFilterToMostRecentSetsEnabled =
- settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsenabled", false).toBool();
- visualDatabaseDisplayFilterToMostRecentSetsAmount =
- settings->value("interface/visualdatabasedisplayfiltertomostrecentsetsamount", 10).toInt();
- visualDeckEditorSampleHandSize = settings->value("interface/visualdeckeditorsamplehandsize", 7).toInt();
- visualDeckEditorCardSize = settings->value("interface/visualdeckeditorcardsize", 100).toInt();
- visualDatabaseDisplayCardSize = settings->value("interface/visualdatabasedisplaycardsize", 100).toInt();
- edhrecCardSize = settings->value("interface/edhreccardsize", 100).toInt();
- archidektPreviewSize = settings->value("interface/archidektpreviewsize", 100).toInt();
-
- horizontalHand = settings->value("hand/horizontal", true).toBool();
- invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
- minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
- tapAnimation = settings->value("cards/tapanimation", true).toBool();
- autoRotateSidewaysLayoutCards = settings->value("cards/autorotatesidewayslayoutcards", true).toBool();
-
- openDeckInNewTab = settings->value("editor/openDeckInNewTab", false).toBool();
- rewindBufferingMs = settings->value("replay/rewindBufferingMs", 200).toInt();
- styleUserList = settings->value("appearance/styleUserList", true).toBool();
- chatMention = settings->value("chat/mention", true).toBool();
- chatMentionCompleter = settings->value("chat/mentioncompleter", true).toBool();
- chatMentionForeground = settings->value("chat/mentionforeground", true).toBool();
- chatHighlightForeground = settings->value("chat/highlightforeground", true).toBool();
- chatMentionColor = settings->value("chat/mentioncolor", "A6120D").toString();
- chatHighlightColor = settings->value("chat/highlightcolor", "A6120D").toString();
-
- zoneViewGroupByIndex = settings->value("zoneview/groupby", 1).toInt();
- zoneViewSortByIndex = settings->value("zoneview/sortby", 1).toInt();
- zoneViewPileView = settings->value("zoneview/pileview", true).toBool();
-
- soundEnabled = settings->value("sound/enabled", false).toBool();
- soundThemeName = settings->value("sound/theme").toString();
-
- maxFontSize = settings->value("game/maxfontsize", DEFAULT_FONT_SIZE).toInt();
-
- ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool();
- ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool();
- ignoreNonBuddyUserMessages = settings->value("chat/ignore_nonbuddy_messages", false).toBool();
-
- scaleCards = settings->value("cards/scaleCards", true).toBool();
- verticalCardOverlapPercent = settings->value("cards/verticalCardOverlapPercent", 33).toInt();
- showMessagePopups = settings->value("chat/showmessagepopups", true).toBool();
- showMentionPopups = settings->value("chat/showmentionpopups", true).toBool();
- roomHistory = settings->value("chat/roomhistory", true).toBool();
-
- leftJustified = settings->value("interface/leftjustified", false).toBool();
-
- masterVolume = settings->value("sound/mastervolume", 100).toInt();
-
- cardInfoViewMode = settings->value("cards/cardinfoviewmode", 0).toInt();
- highlightWords = settings->value("personal/highlightWords", QString()).toString();
- gameDescription = settings->value("game/gamedescription", "").toString();
- maxPlayers = settings->value("game/maxplayers", 2).toInt();
- gameTypes = settings->value("game/gametypes", "").toString();
- onlyBuddies = settings->value("game/onlybuddies", false).toBool();
- onlyRegistered = settings->value("game/onlyregistered", true).toBool();
- spectatorsAllowed = settings->value("game/spectatorsallowed", true).toBool();
- spectatorsNeedPassword = settings->value("game/spectatorsneedpassword", false).toBool();
- spectatorsCanTalk = settings->value("game/spectatorscantalk", false).toBool();
- spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
- createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool();
- defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
- shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
- rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
-
- // Local game settings use "localgameoptions/" prefix to keep them separate
- // from server game settings which use "game/" prefix
- localGameRememberSettings = settings->value("localgameoptions/remembersettings", false).toBool();
- localGameMaxPlayers = settings->value("localgameoptions/maxplayers", 1).toInt();
- localGameStartingLifeTotal = settings->value("localgameoptions/startinglifetotal", 20).toInt();
-
- clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
- clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
-}
-
-void SettingsCache::setUseTearOffMenus(bool _useTearOffMenus)
-{
- useTearOffMenus = _useTearOffMenus;
- settings->setValue("interface/usetearoffmenus", useTearOffMenus);
- emit useTearOffMenusChanged(useTearOffMenus);
-}
-
-void SettingsCache::setCardViewInitialRowsMax(int _cardViewInitialRowsMax)
-{
- cardViewInitialRowsMax = _cardViewInitialRowsMax;
- settings->setValue("interface/cardViewInitialRowsMax", cardViewInitialRowsMax);
-}
-
-void SettingsCache::setCardViewExpandedRowsMax(int value)
-{
- cardViewExpandedRowsMax = value;
- settings->setValue("interface/cardViewExpandedRowsMax", cardViewExpandedRowsMax);
-}
-
-void SettingsCache::setCloseEmptyCardView(QT_STATE_CHANGED_T value)
-{
- closeEmptyCardView = value;
- settings->setValue("interface/closeEmptyCardView", closeEmptyCardView);
-}
-
-void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T value)
-{
- focusCardViewSearchBar = value;
- settings->setValue("interface/focusCardViewSearchBar", focusCardViewSearchBar);
-}
-
-void SettingsCache::setKeepGameChatFocus(QT_STATE_CHANGED_T value)
-{
- keepGameChatFocus = value;
- settings->setValue("interface/keepGameChatFocus", keepGameChatFocus);
- emit keepGameChatFocusChanged(keepGameChatFocus);
-}
-
-void SettingsCache::setKnownMissingFeatures(const QString &_knownMissingFeatures)
-{
- knownMissingFeatures = _knownMissingFeatures;
- settings->setValue("interface/knownmissingfeatures", knownMissingFeatures);
-}
-
-void SettingsCache::setCardInfoViewMode(const int _viewMode)
-{
- cardInfoViewMode = _viewMode;
- settings->setValue("cards/cardinfoviewmode", cardInfoViewMode);
-}
-
-void SettingsCache::setHighlightWords(const QString &_highlightWords)
-{
- highlightWords = _highlightWords;
- settings->setValue("personal/highlightWords", highlightWords);
-}
-
-void SettingsCache::setMasterVolume(int _masterVolume)
-{
- masterVolume = _masterVolume;
- settings->setValue("sound/mastervolume", masterVolume);
- emit masterVolumeChanged(masterVolume);
-}
-
-void SettingsCache::setLeftJustified(const QT_STATE_CHANGED_T _leftJustified)
-{
- leftJustified = (bool)_leftJustified;
- settings->setValue("interface/leftjustified", leftJustified);
- emit handJustificationChanged();
-}
-
-void SettingsCache::setCardScaling(const QT_STATE_CHANGED_T _scaleCards)
-{
- scaleCards = (bool)_scaleCards;
- settings->setValue("cards/scaleCards", scaleCards);
-}
-
-void SettingsCache::setStackCardOverlapPercent(const int _verticalCardOverlapPercent)
-{
- verticalCardOverlapPercent = _verticalCardOverlapPercent;
- settings->setValue("cards/verticalCardOverlapPercent", verticalCardOverlapPercent);
-}
-
-void SettingsCache::setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups)
-{
- showMessagePopups = (bool)_showMessagePopups;
- settings->setValue("chat/showmessagepopups", showMessagePopups);
-}
-
-void SettingsCache::setShowMentionPopups(const QT_STATE_CHANGED_T _showMentionPopus)
-{
- showMentionPopups = (bool)_showMentionPopus;
- settings->setValue("chat/showmentionpopups", showMentionPopups);
-}
-
-void SettingsCache::setRoomHistory(const QT_STATE_CHANGED_T _roomHistory)
-{
- roomHistory = (bool)_roomHistory;
- settings->setValue("chat/roomhistory", roomHistory);
-}
-
-void SettingsCache::setLang(const QString &_lang)
-{
- lang = _lang;
- settings->setValue("personal/lang", lang);
- emit langChanged();
-}
-
-void SettingsCache::setShowTipsOnStartup(bool _showTipsOnStartup)
-{
- showTipsOnStartup = _showTipsOnStartup;
- settings->setValue("tipOfDay/showTips", showTipsOnStartup);
-}
-
-void SettingsCache::setSeenTips(const QList &_seenTips)
-{
- seenTips = _seenTips;
- QList storedTipList;
- for (auto tipNumber : seenTips) {
- storedTipList.append(tipNumber);
- }
- settings->setValue("tipOfDay/seenTips", storedTipList);
-}
-
-void SettingsCache::setDeckPath(const QString &_deckPath)
-{
- deckPath = _deckPath;
- settings->setValue("paths/decks", deckPath);
-}
-
-void SettingsCache::setFiltersPath(const QString &_filtersPath)
-{
- filtersPath = _filtersPath;
- settings->setValue("paths/filters", filtersPath);
-}
-
-void SettingsCache::setReplaysPath(const QString &_replaysPath)
-{
- replaysPath = _replaysPath;
- settings->setValue("paths/replays", replaysPath);
-}
-
-void SettingsCache::setThemesPath(const QString &_themesPath)
-{
- themesPath = _themesPath;
- settings->setValue("paths/themes", themesPath);
- emit themeChanged();
-}
-
-void SettingsCache::setCustomCardDatabasePath(const QString &_customCardDatabasePath)
-{
- customCardDatabasePath = _customCardDatabasePath;
- settings->setValue("paths/customsets", customCardDatabasePath);
- emit cardDatabasePathChanged();
-}
-
-void SettingsCache::setPicsPath(const QString &_picsPath)
-{
- picsPath = _picsPath;
- settings->setValue("paths/pics", picsPath);
- // get a new value for customPicsPath, currently derived from picsPath
- if (picsPath.endsWith("/")) {
- customPicsPath = getSafeConfigPath("paths/custompics", picsPath + "CUSTOM/");
- } else {
- customPicsPath = getSafeConfigPath("paths/custompics", picsPath + "/CUSTOM/");
- }
- emit picsPathChanged();
-}
-
-void SettingsCache::setCardDatabasePath(const QString &_cardDatabasePath)
-{
- cardDatabasePath = _cardDatabasePath;
- settings->setValue("paths/carddatabase", cardDatabasePath);
- emit cardDatabasePathChanged();
-}
-
-void SettingsCache::setSpoilerDatabasePath(const QString &_spoilerDatabasePath)
-{
- spoilerDatabasePath = _spoilerDatabasePath;
- settings->setValue("paths/spoilerdatabase", spoilerDatabasePath);
- emit cardDatabasePathChanged();
-}
-
-void SettingsCache::setTokenDatabasePath(const QString &_tokenDatabasePath)
-{
- tokenDatabasePath = _tokenDatabasePath;
- settings->setValue("paths/tokendatabase", tokenDatabasePath);
- emit cardDatabasePathChanged();
}
void SettingsCache::setThemeName(const QString &_themeName)
{
themeName = _themeName;
- settings->setValue("theme/name", themeName);
+ appearanceSettings->setThemeName(themeName);
emit themeChanged();
}
-void SettingsCache::setHomeTabBackgroundSource(const QString &_backgroundSource)
-{
- homeTabBackgroundSource = _backgroundSource;
- settings->setValue("home/background", homeTabBackgroundSource);
- emit homeTabBackgroundSourceChanged();
-}
-
-void SettingsCache::setHomeTabBackgroundShuffleFrequency(int _frequency)
-{
- homeTabBackgroundShuffleFrequency = _frequency;
- settings->setValue("home/background/shuffleTimer", homeTabBackgroundShuffleFrequency);
- emit homeTabBackgroundShuffleFrequencyChanged();
-}
-
-void SettingsCache::setHomeTabDisplayCardName(QT_STATE_CHANGED_T _displayCardName)
-{
- homeTabDisplayCardName = static_cast(_displayCardName);
- settings->setValue("home/background/displayCardName", homeTabDisplayCardName);
- emit homeTabDisplayCardNameChanged();
-}
-
-void SettingsCache::setTabVisualDeckStorageOpen(bool value)
-{
- tabVisualDeckStorageOpen = value;
- settings->setValue("tabs/visualDeckStorage", tabVisualDeckStorageOpen);
-}
-
-void SettingsCache::setTabServerOpen(bool value)
-{
- tabServerOpen = value;
- settings->setValue("tabs/server", tabServerOpen);
-}
-
-void SettingsCache::setTabAccountOpen(bool value)
-{
- tabAccountOpen = value;
- settings->setValue("tabs/account", tabAccountOpen);
-}
-
-void SettingsCache::setTabDeckStorageOpen(bool value)
-{
- tabDeckStorageOpen = value;
- settings->setValue("tabs/deckStorage", tabDeckStorageOpen);
-}
-
-void SettingsCache::setTabReplaysOpen(bool value)
-{
- tabReplaysOpen = value;
- settings->setValue("tabs/replays", tabReplaysOpen);
-}
-
-void SettingsCache::setTabAdminOpen(bool value)
-{
- tabAdminOpen = value;
- settings->setValue("tabs/admin", tabAdminOpen);
-}
-
-void SettingsCache::setTabLogOpen(bool value)
-{
- tabLogOpen = value;
- settings->setValue("tabs/log", tabLogOpen);
-}
-
-void SettingsCache::setPicDownload(QT_STATE_CHANGED_T _picDownload)
-{
- picDownload = static_cast(_picDownload);
- settings->setValue("personal/picturedownload", picDownload);
- emit picDownloadChanged();
-}
-
-void SettingsCache::setShowStatusBar(bool value)
-{
- showStatusBar = value;
- settings->setValue("personal/showStatusBar", showStatusBar);
- emit showStatusBarChanged(value);
-}
-
-void SettingsCache::setNotificationsEnabled(QT_STATE_CHANGED_T _notificationsEnabled)
-{
- notificationsEnabled = static_cast(_notificationsEnabled);
- settings->setValue("interface/notificationsenabled", notificationsEnabled);
-}
-
-void SettingsCache::setSpectatorNotificationsEnabled(QT_STATE_CHANGED_T _spectatorNotificationsEnabled)
-{
- spectatorNotificationsEnabled = static_cast(_spectatorNotificationsEnabled);
- settings->setValue("interface/specnotificationsenabled", spectatorNotificationsEnabled);
-}
-
-void SettingsCache::setBuddyConnectNotificationsEnabled(QT_STATE_CHANGED_T _buddyConnectNotificationsEnabled)
-{
- buddyConnectNotificationsEnabled = static_cast(_buddyConnectNotificationsEnabled);
- settings->setValue("interface/buddyconnectnotificationsenabled", buddyConnectNotificationsEnabled);
-}
-
-void SettingsCache::setDoubleClickToPlay(QT_STATE_CHANGED_T _doubleClickToPlay)
-{
- doubleClickToPlay = static_cast(_doubleClickToPlay);
- settings->setValue("interface/doubleclicktoplay", doubleClickToPlay);
-}
-
-void SettingsCache::setClickPlaysAllSelected(QT_STATE_CHANGED_T _clickPlaysAllSelected)
-{
- clickPlaysAllSelected = static_cast(_clickPlaysAllSelected);
- settings->setValue("interface/clickPlaysAllSelected", clickPlaysAllSelected);
-}
-
-void SettingsCache::setPlayToStack(QT_STATE_CHANGED_T _playToStack)
-{
- playToStack = static_cast(_playToStack);
- settings->setValue("interface/playtostack", playToStack);
-}
-
-void SettingsCache::setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases)
-{
- doNotDeleteArrowsInSubPhases = static_cast(_doNotDeleteArrowsInSubPhases);
- settings->setValue("interface/doNotDeleteArrowsInSubPhases", doNotDeleteArrowsInSubPhases);
-}
-
-void SettingsCache::setStartingHandSize(int _startingHandSize)
-{
- startingHandSize = _startingHandSize;
- settings->setValue("interface/startinghandsize", startingHandSize);
-}
-
-void SettingsCache::setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens)
-{
- annotateTokens = static_cast(_annotateTokens);
- settings->setValue("interface/annotatetokens", annotateTokens);
-}
-
-void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
-{
- showShortcuts = static_cast(_showShortcuts);
- settings->setValue("menu/showshortcuts", showShortcuts);
-}
-
-void SettingsCache::setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar)
-{
- showGameSelectorFilterToolbar = static_cast(_showGameSelectorFilterToolbar);
- settings->setValue("menu/showgameselectorfiltertoolbar", showGameSelectorFilterToolbar);
- emit showGameSelectorFilterToolbarChanged(showGameSelectorFilterToolbar);
-}
-
-void SettingsCache::setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames)
-{
- displayCardNames = static_cast(_displayCardNames);
- settings->setValue("cards/displaycardnames", displayCardNames);
- emit displayCardNamesChanged();
-}
-
-void SettingsCache::setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T _overrideAllCardArt)
-{
- overrideAllCardArtWithPersonalPreference = static_cast(_overrideAllCardArt);
- settings->setValue("cards/overrideallcardartwithpersonalpreference", overrideAllCardArtWithPersonalPreference);
- emit overrideAllCardArtWithPersonalPreferenceChanged(overrideAllCardArtWithPersonalPreference);
-}
-
-void SettingsCache::setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop)
-{
- bumpSetsWithCardsInDeckToTop = static_cast(_bumpSetsWithCardsInDeckToTop);
- settings->setValue("cards/bumpsetswithcardsindecktotop", bumpSetsWithCardsInDeckToTop);
- emit bumpSetsWithCardsInDeckToTopChanged();
-}
-
-void SettingsCache::setPrintingSelectorSortOrder(int _printingSelectorSortOrder)
-{
- printingSelectorSortOrder = _printingSelectorSortOrder;
- settings->setValue("cards/printingselectorsortorder", printingSelectorSortOrder);
- emit printingSelectorSortOrderChanged();
-}
-
-void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
-{
- printingSelectorCardSize = _printingSelectorCardSize;
- settings->setValue("cards/printingselectorcardsize", printingSelectorCardSize);
- emit printingSelectorCardSizeChanged();
-}
-
-void SettingsCache::setIncludeRebalancedCards(bool _includeRebalancedCards)
-{
- if (includeRebalancedCards == _includeRebalancedCards) {
- return;
- }
-
- includeRebalancedCards = _includeRebalancedCards;
- settings->setValue("cards/includerebalancedcards", includeRebalancedCards);
- emit includeRebalancedCardsChanged(includeRebalancedCards);
-}
-
-void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible)
-{
- printingSelectorNavigationButtonsVisible = _navigationButtonsVisible;
- settings->setValue("cards/printingselectornavigationbuttonsvisible", printingSelectorNavigationButtonsVisible);
- emit printingSelectorNavigationButtonsVisibleChanged();
-}
-
-void SettingsCache::setDeckEditorBannerCardComboBoxVisible(QT_STATE_CHANGED_T _deckEditorBannerCardComboBoxVisible)
-{
- deckEditorBannerCardComboBoxVisible = _deckEditorBannerCardComboBoxVisible;
- settings->setValue("interface/deckeditorbannercardcomboboxvisible", deckEditorBannerCardComboBoxVisible);
- emit deckEditorBannerCardComboBoxVisibleChanged(deckEditorBannerCardComboBoxVisible);
-}
-
-void SettingsCache::setDeckEditorTagsWidgetVisible(QT_STATE_CHANGED_T _deckEditorTagsWidgetVisible)
-{
- deckEditorTagsWidgetVisible = _deckEditorTagsWidgetVisible;
- settings->setValue("interface/deckeditortagswidgetvisible", deckEditorTagsWidgetVisible);
- emit deckEditorTagsWidgetVisibleChanged(deckEditorTagsWidgetVisible);
-}
-
-void SettingsCache::setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder)
-{
- visualDeckStorageSortingOrder = _visualDeckStorageSortingOrder;
- settings->setValue("interface/visualdeckstoragesortingorder", visualDeckStorageSortingOrder);
-}
-
-void SettingsCache::setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value)
-{
- visualDeckStorageShowFolders = value;
- settings->setValue("interface/visualdeckstorageshowfolders", visualDeckStorageShowFolders);
-}
-
-void SettingsCache::setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags)
-{
- visualDeckStorageShowTagFilter = _showTags;
- settings->setValue("interface/visualdeckstorageshowtagfilter", visualDeckStorageShowTagFilter);
- emit visualDeckStorageShowTagFilterChanged(visualDeckStorageShowTagFilter);
-}
-
-void SettingsCache::setVisualDeckStorageDefaultTagsList(QStringList _defaultTagsList)
-{
- visualDeckStorageDefaultTagsList = _defaultTagsList;
- settings->setValue("interface/visualdeckstoragedefaulttagslist", visualDeckStorageDefaultTagsList);
- emit visualDeckStorageDefaultTagsListChanged();
-}
-
-void SettingsCache::setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T value)
-{
- visualDeckStorageSearchFolderNames = value;
- settings->setValue("interface/visualdeckstoragesearchfoldernames", visualDeckStorageSearchFolderNames);
-}
-
-void SettingsCache::setVisualDeckStorageShowColorIdentity(QT_STATE_CHANGED_T value)
-{
- visualDeckStorageShowColorIdentity = value;
- settings->setValue("interface/visualdeckstorageshowcoloridentity", visualDeckStorageShowColorIdentity);
- emit visualDeckStorageShowColorIdentityChanged(visualDeckStorageShowColorIdentity);
-}
-
-void SettingsCache::setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox)
-{
- visualDeckStorageShowBannerCardComboBox = _showBannerCardComboBox;
- settings->setValue("interface/visualdeckstorageshowbannercardcombobox", visualDeckStorageShowBannerCardComboBox);
- emit visualDeckStorageShowBannerCardComboBoxChanged(visualDeckStorageShowBannerCardComboBox);
-}
-
-void SettingsCache::setVisualDeckStorageShowTagsOnDeckPreviews(QT_STATE_CHANGED_T _showTags)
-{
- visualDeckStorageShowTagsOnDeckPreviews = _showTags;
- settings->setValue("interface/visualdeckstorageshowtagsondeckpreviews", visualDeckStorageShowTagsOnDeckPreviews);
- emit visualDeckStorageShowTagsOnDeckPreviewsChanged(visualDeckStorageShowTagsOnDeckPreviews);
-}
-
-void SettingsCache::setVisualDeckStorageCardSize(int _visualDeckStorageCardSize)
-{
- visualDeckStorageCardSize = _visualDeckStorageCardSize;
- settings->setValue("interface/visualdeckstoragecardsize", visualDeckStorageCardSize);
- emit visualDeckStorageCardSizeChanged();
-}
-
-void SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities(
- QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities)
-{
- visualDeckStorageDrawUnusedColorIdentities = _visualDeckStorageDrawUnusedColorIdentities;
- settings->setValue("interface/visualdeckstoragedrawunusedcoloridentities",
- visualDeckStorageDrawUnusedColorIdentities);
- emit visualDeckStorageDrawUnusedColorIdentitiesChanged(visualDeckStorageDrawUnusedColorIdentities);
-}
-
-void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity)
-{
- visualDeckStorageUnusedColorIdentitiesOpacity = _visualDeckStorageUnusedColorIdentitiesOpacity;
- settings->setValue("interface/visualdeckstorageunusedcoloridentitiesopacity",
- visualDeckStorageUnusedColorIdentitiesOpacity);
- emit visualDeckStorageUnusedColorIdentitiesOpacityChanged(visualDeckStorageUnusedColorIdentitiesOpacity);
-}
-
-void SettingsCache::setVisualDeckStorageTooltipType(int value)
-{
- visualDeckStorageTooltipType = value;
- settings->setValue("interface/visualdeckstoragetooltiptype", visualDeckStorageTooltipType);
-}
-
-void SettingsCache::setVisualDeckStoragePromptForConversion(bool _visualDeckStoragePromptForConversion)
-{
- visualDeckStoragePromptForConversion = _visualDeckStoragePromptForConversion;
- settings->setValue("interface/visualdeckstoragepromptforconversion", visualDeckStoragePromptForConversion);
-}
-
-void SettingsCache::setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert)
-{
- visualDeckStorageAlwaysConvert = _visualDeckStorageAlwaysConvert;
- settings->setValue("interface/visualdeckstoragealwaysconvert", visualDeckStorageAlwaysConvert);
-}
-
-void SettingsCache::setVisualDeckStorageInGame(QT_STATE_CHANGED_T value)
-{
- visualDeckStorageInGame = value;
- settings->setValue("interface/visualdeckstorageingame", visualDeckStorageInGame);
- emit visualDeckStorageInGameChanged(visualDeckStorageInGame);
-}
-
-void SettingsCache::setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value)
-{
- visualDeckStorageSelectionAnimation = value;
- settings->setValue("interface/visualdeckstorageselectionanimation", visualDeckStorageSelectionAnimation);
- emit visualDeckStorageSelectionAnimationChanged(visualDeckStorageSelectionAnimation);
-}
-
-void SettingsCache::setVisualDeckEditorCardSize(int _visualDeckEditorCardSize)
-{
- visualDeckEditorCardSize = _visualDeckEditorCardSize;
- settings->setValue("interface/visualdeckeditorcardsize", visualDeckEditorCardSize);
- emit visualDeckEditorCardSizeChanged();
-}
-
-void SettingsCache::setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize)
-{
- visualDatabaseDisplayCardSize = _visualDatabaseDisplayCardSize;
- settings->setValue("interface/visualdatabasedisplaycardsize", visualDatabaseDisplayCardSize);
- emit visualDatabaseDisplayCardSizeChanged();
-}
-
-void SettingsCache::setEDHRecCardSize(int _edhrecCardSize)
-{
- edhrecCardSize = _edhrecCardSize;
- settings->setValue("interface/edhreccardsize", edhrecCardSize);
- emit edhRecCardSizeChanged();
-}
-
-void SettingsCache::setArchidektPreviewCardSize(int _archidektPreviewCardSize)
-{
- archidektPreviewSize = _archidektPreviewCardSize;
- settings->setValue("interface/archidektpreviewsize", archidektPreviewSize);
- emit archidektPreviewSizeChanged();
-}
-
-void SettingsCache::setDefaultDeckEditorType(int value)
-{
- defaultDeckEditorType = value;
- settings->setValue("interface/defaultDeckEditorType", defaultDeckEditorType);
-}
-
-void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled)
-{
- visualDatabaseDisplayFilterToMostRecentSetsEnabled = _enabled;
- settings->setValue("interface/visualdatabasedisplayfiltertomostrecentsetsenabled",
- visualDatabaseDisplayFilterToMostRecentSetsEnabled);
- emit visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(visualDatabaseDisplayFilterToMostRecentSetsEnabled);
-}
-
-void SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount)
-{
- visualDatabaseDisplayFilterToMostRecentSetsAmount = _amount;
- settings->setValue("interface/visualdatabasedisplayfiltertomostrecentsetsamount",
- visualDatabaseDisplayFilterToMostRecentSetsAmount);
- emit visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(visualDatabaseDisplayFilterToMostRecentSetsAmount);
-}
-
-void SettingsCache::setVisualDeckEditorSampleHandSize(int _amount)
-{
- visualDeckEditorSampleHandSize = _amount;
- settings->setValue("interface/visualdeckeditorsamplehandsize", visualDeckEditorSampleHandSize);
- emit visualDeckEditorSampleHandSizeAmountChanged(visualDeckEditorSampleHandSize);
-}
-
-void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
-{
- horizontalHand = static_cast(_horizontalHand);
- settings->setValue("hand/horizontal", horizontalHand);
- emit horizontalHandChanged();
-}
-
-void SettingsCache::setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate)
-{
- invertVerticalCoordinate = static_cast(_invertVerticalCoordinate);
- settings->setValue("table/invert_vertical", invertVerticalCoordinate);
- emit invertVerticalCoordinateChanged();
-}
-
-void SettingsCache::setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout)
-{
- minPlayersForMultiColumnLayout = _minPlayersForMultiColumnLayout;
- settings->setValue("interface/min_players_multicolumn", minPlayersForMultiColumnLayout);
- emit minPlayersForMultiColumnLayoutChanged();
-}
-
-void SettingsCache::setTapAnimation(QT_STATE_CHANGED_T _tapAnimation)
-{
- tapAnimation = static_cast(_tapAnimation);
- settings->setValue("cards/tapanimation", tapAnimation);
-}
-
-void SettingsCache::setAutoRotateSidewaysLayoutCards(QT_STATE_CHANGED_T _autoRotateSidewaysLayoutCards)
-{
- autoRotateSidewaysLayoutCards = static_cast(_autoRotateSidewaysLayoutCards);
- settings->setValue("cards/autorotatesidewayslayoutcards", autoRotateSidewaysLayoutCards);
-}
-
-void SettingsCache::setOpenDeckInNewTab(QT_STATE_CHANGED_T _openDeckInNewTab)
-{
- openDeckInNewTab = static_cast(_openDeckInNewTab);
- settings->setValue("editor/openDeckInNewTab", openDeckInNewTab);
-}
-
-void SettingsCache::setRewindBufferingMs(int _rewindBufferingMs)
-{
- rewindBufferingMs = _rewindBufferingMs;
- settings->setValue("replay/rewindBufferingMs", rewindBufferingMs);
-}
-
-void SettingsCache::setStyleUserList(QT_STATE_CHANGED_T _styleUserList)
-{
- styleUserList = static_cast(_styleUserList);
- settings->setValue("appearance/styleUserList", styleUserList);
- emit styleUserListChanged();
-}
-
-void SettingsCache::setChatMention(QT_STATE_CHANGED_T _chatMention)
-{
- chatMention = static_cast(_chatMention);
- settings->setValue("chat/mention", chatMention);
-}
-
-void SettingsCache::setChatMentionCompleter(const QT_STATE_CHANGED_T _enableMentionCompleter)
-{
- chatMentionCompleter = (bool)_enableMentionCompleter;
- settings->setValue("chat/mentioncompleter", chatMentionCompleter);
- emit chatMentionCompleterChanged();
-}
-
-void SettingsCache::setChatMentionForeground(QT_STATE_CHANGED_T _chatMentionForeground)
-{
- chatMentionForeground = static_cast(_chatMentionForeground);
- settings->setValue("chat/mentionforeground", chatMentionForeground);
-}
-
-void SettingsCache::setChatHighlightForeground(QT_STATE_CHANGED_T _chatHighlightForeground)
-{
- chatHighlightForeground = static_cast(_chatHighlightForeground);
- settings->setValue("chat/highlightforeground", chatHighlightForeground);
-}
-
-void SettingsCache::setChatMentionColor(const QString &_chatMentionColor)
-{
- chatMentionColor = _chatMentionColor;
- settings->setValue("chat/mentioncolor", chatMentionColor);
-}
-
-void SettingsCache::setChatHighlightColor(const QString &_chatHighlightColor)
-{
- chatHighlightColor = _chatHighlightColor;
- settings->setValue("chat/highlightcolor", chatHighlightColor);
-}
-
-void SettingsCache::setZoneViewGroupByIndex(int _zoneViewGroupByIndex)
-{
- zoneViewGroupByIndex = _zoneViewGroupByIndex;
- settings->setValue("zoneview/groupby", zoneViewGroupByIndex);
-}
-
-void SettingsCache::setZoneViewSortByIndex(int _zoneViewSortByIndex)
-{
- zoneViewSortByIndex = _zoneViewSortByIndex;
- settings->setValue("zoneview/sortby", zoneViewSortByIndex);
-}
-
-void SettingsCache::setZoneViewPileView(QT_STATE_CHANGED_T _zoneViewPileView)
-{
- zoneViewPileView = static_cast(_zoneViewPileView);
- settings->setValue("zoneview/pileview", zoneViewPileView);
-}
-
-void SettingsCache::setSoundEnabled(QT_STATE_CHANGED_T _soundEnabled)
-{
- soundEnabled = static_cast(_soundEnabled);
- settings->setValue("sound/enabled", soundEnabled);
- emit soundEnabledChanged();
-}
-
-void SettingsCache::setSoundThemeName(const QString &_soundThemeName)
-{
- soundThemeName = _soundThemeName;
- settings->setValue("sound/theme", soundThemeName);
- emit soundThemeChanged();
-}
-
-void SettingsCache::setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers)
-{
- ignoreUnregisteredUsers = static_cast(_ignoreUnregisteredUsers);
- settings->setValue("chat/ignore_unregistered", ignoreUnregisteredUsers);
-}
-
-void SettingsCache::setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages)
-{
- ignoreUnregisteredUserMessages = static_cast(_ignoreUnregisteredUserMessages);
- settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
-}
-
-void SettingsCache::setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages)
-{
- ignoreNonBuddyUserMessages = static_cast(_ignoreNonBuddyUserMessages);
- settings->setValue("chat/ignore_nonbuddy_messages", ignoreNonBuddyUserMessages);
-}
-
-void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
-{
- pixmapCacheSize = _pixmapCacheSize;
- settings->setValue("personal/pixmapCacheSize", pixmapCacheSize);
- emit pixmapCacheSizeChanged(pixmapCacheSize);
-}
-
-void SettingsCache::setCardImageCacheMethod(const CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod)
-{
- cardPictureLoaderCacheMethod = static_cast(_cardImageCachingMethod);
- settings->setValue("personal/cardPictureLoaderCacheMethod", cardPictureLoaderCacheMethod);
- emit cardPictureLoaderCacheMethodChanged(cardPictureLoaderCacheMethod);
-}
-
-void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
-{
- networkCacheSize = _networkCacheSize;
- settings->setValue("personal/networkCacheSize", networkCacheSize);
- emit networkCacheSizeChanged(networkCacheSize);
-}
-
-void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl)
-{
- redirectCacheTtl = _redirectCacheTtl;
- settings->setValue("personal/redirectCacheSize", redirectCacheTtl);
- emit redirectCacheTtlChanged(redirectCacheTtl);
-}
-
-void SettingsCache::setLocalCardImageStorageNamingScheme(
- const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme)
-{
- localCardImageStorageNamingScheme = static_cast(_localCardImageStorageNamingScheme);
- settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme);
- emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme);
-}
-
-void SettingsCache::setClientID(const QString &_clientID)
-{
- clientID = _clientID;
- settings->setValue("personal/clientid", clientID);
-}
-
-void SettingsCache::setClientVersion(const QString &_clientVersion)
-{
- clientVersion = _clientVersion;
- settings->setValue("personal/clientversion", clientVersion);
-}
-
QStringList SettingsCache::getCountries() const
{
static const QStringList countries = {
@@ -1210,236 +194,264 @@ QStringList SettingsCache::getCountries() const
return countries;
}
-void SettingsCache::setGameDescription(const QString _gameDescription)
-{
- gameDescription = _gameDescription;
- settings->setValue("game/gamedescription", gameDescription);
-}
-
-void SettingsCache::setMaxPlayers(const int _maxPlayers)
-{
- maxPlayers = _maxPlayers;
- settings->setValue("game/maxplayers", maxPlayers);
-}
-
-void SettingsCache::setGameTypes(const QString _gameTypes)
-{
- gameTypes = _gameTypes;
- settings->setValue("game/gametypes", gameTypes);
-}
-
-void SettingsCache::setOnlyBuddies(const bool _onlyBuddies)
-{
- onlyBuddies = _onlyBuddies;
- settings->setValue("game/onlybuddies", onlyBuddies);
-}
-
-void SettingsCache::setOnlyRegistered(const bool _onlyRegistered)
-{
- onlyRegistered = _onlyRegistered;
- settings->setValue("game/onlyregistered", onlyRegistered);
-}
-
-void SettingsCache::setSpectatorsAllowed(const bool _spectatorsAllowed)
-{
- spectatorsAllowed = _spectatorsAllowed;
- settings->setValue("game/spectatorsallowed", spectatorsAllowed);
-}
-
-void SettingsCache::setSpectatorsNeedPassword(const bool _spectatorsNeedPassword)
-{
- spectatorsNeedPassword = _spectatorsNeedPassword;
- settings->setValue("game/spectatorsneedpassword", spectatorsNeedPassword);
-}
-
-void SettingsCache::setSpectatorsCanTalk(const bool _spectatorsCanTalk)
-{
- spectatorsCanTalk = _spectatorsCanTalk;
- settings->setValue("game/spectatorscantalk", spectatorsCanTalk);
-}
-
-void SettingsCache::setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything)
-{
- spectatorsCanSeeEverything = _spectatorsCanSeeEverything;
- settings->setValue("game/spectatorscanseeeverything", spectatorsCanSeeEverything);
-}
-
-void SettingsCache::setCreateGameAsSpectator(const bool _createGameAsSpectator)
-{
- createGameAsSpectator = _createGameAsSpectator;
- settings->setValue("game/creategameasspectator", createGameAsSpectator);
-}
-
-void SettingsCache::setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal)
-{
- defaultStartingLifeTotal = _defaultStartingLifeTotal;
- settings->setValue("game/defaultstartinglifetotal", defaultStartingLifeTotal);
-}
-
-void SettingsCache::setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad)
-{
- shareDecklistsOnLoad = _shareDecklistsOnLoad;
- settings->setValue("game/sharedecklistsonload", shareDecklistsOnLoad);
-}
-
-void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value)
-{
- checkUpdatesOnStartup = static_cast(value);
- settings->setValue("personal/startupUpdateCheck", checkUpdatesOnStartup);
-}
-
-void SettingsCache::setStartupCardUpdateCheckPromptForUpdate(bool value)
-{
- startupCardUpdateCheckPromptForUpdate = value;
- settings->setValue("personal/startupCardUpdateCheckPromptForUpdate", startupCardUpdateCheckPromptForUpdate);
-}
-
-void SettingsCache::setStartupCardUpdateCheckAlwaysUpdate(bool value)
-{
- startupCardUpdateCheckAlwaysUpdate = value;
- settings->setValue("personal/startupCardUpdateCheckAlwaysUpdate", startupCardUpdateCheckAlwaysUpdate);
-}
-
-void SettingsCache::setCardUpdateCheckInterval(int value)
-{
- cardUpdateCheckInterval = value;
- settings->setValue("personal/cardUpdateCheckInterval", cardUpdateCheckInterval);
-}
-
-void SettingsCache::setLastCardUpdateCheck(QDate value)
-{
- lastCardUpdateCheck = value;
- settings->setValue("personal/lastCardUpdateCheck", lastCardUpdateCheck);
-}
-
-void SettingsCache::setAlwaysEnableNewSets(bool value)
-{
- alwaysEnableNewSets = value;
- settings->setValue("personal/alwaysEnableNewSets", alwaysEnableNewSets);
-}
-
-void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
-{
- rememberGameSettings = _rememberGameSettings;
- settings->setValue("game/remembergamesettings", rememberGameSettings);
-}
-
-void SettingsCache::setLocalGameRememberSettings(bool value)
-{
- localGameRememberSettings = value;
- settings->setValue("localgameoptions/remembersettings", value);
-}
-
-void SettingsCache::setLocalGameMaxPlayers(int value)
-{
- localGameMaxPlayers = value;
- settings->setValue("localgameoptions/maxplayers", value);
-}
-
-void SettingsCache::setLocalGameStartingLifeTotal(int value)
-{
- localGameStartingLifeTotal = value;
- settings->setValue("localgameoptions/startinglifetotal", value);
-}
-
-void SettingsCache::setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate)
-{
- notifyAboutUpdates = static_cast(_notifyaboutupdate);
- settings->setValue("personal/updatenotification", notifyAboutUpdates);
-}
-
-void SettingsCache::setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion)
-{
- notifyAboutNewVersion = static_cast(_notifyaboutnewversion);
- settings->setValue("personal/newversionnotification", notifyAboutNewVersion);
-}
-
-void SettingsCache::setDownloadSpoilerStatus(bool _spoilerStatus)
-{
- mbDownloadSpoilers = _spoilerStatus;
- settings->setValue("personal/downloadspoilers", mbDownloadSpoilers);
- emit downloadSpoilerStatusChanged();
-}
-
-void SettingsCache::setUpdateReleaseChannelIndex(int value)
-{
- updateReleaseChannel = value;
- settings->setValue("personal/updatereleasechannel", updateReleaseChannel);
-}
-
-void SettingsCache::setMaxFontSize(int _max)
-{
- maxFontSize = _max;
- settings->setValue("game/maxfontsize", maxFontSize);
-}
-
-void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
-{
- if (_roundCardCorners == roundCardCorners) {
- return;
- }
-
- roundCardCorners = _roundCardCorners;
- settings->setValue("cards/roundcardcorners", _roundCardCorners);
- emit roundCardCornersChanged(roundCardCorners);
-}
-
-void SettingsCache::setShowDragSelectionCount(QT_STATE_CHANGED_T _showDragSelectionCount)
-{
- showDragSelectionCount = static_cast(_showDragSelectionCount);
- settings->setValue("interface/showlassoselectioncount", showDragSelectionCount);
-}
-
-void SettingsCache::setShowTotalSelectionCount(QT_STATE_CHANGED_T _showTotalSelectionCount)
-{
- showTotalSelectionCount = static_cast(_showTotalSelectionCount);
- settings->setValue("interface/showpersistentselectioncount", showTotalSelectionCount);
-}
-
-void SettingsCache::setShowSubtypeSelectionTally(QT_STATE_CHANGED_T _showSubtypeSelectionTally)
-{
- showSubtypeSelectionTally = static_cast(_showSubtypeSelectionTally);
- settings->setValue("interface/showsubtypeselectiontally", showSubtypeSelectionTally);
-}
-
void SettingsCache::loadPaths()
{
QString dataPath = getDataPath();
- deckPath = getSafeConfigPath("paths/decks", dataPath + "/decks/");
- filtersPath = getSafeConfigPath("paths/filters", dataPath + "/filters/");
- replaysPath = getSafeConfigPath("paths/replays", dataPath + "/replays/");
- themesPath = getSafeConfigPath("paths/themes", dataPath + "/themes/");
- picsPath = getSafeConfigPath("paths/pics", dataPath + "/pics/");
- redirectCachePath = getSafeConfigPath("paths/redirects", getCachePath() + "/redirects/");
- // this has never been exposed as an user-configurable setting
- if (picsPath.endsWith("/")) {
- customPicsPath = getSafeConfigPath("paths/custompics", picsPath + "CUSTOM/");
- } else {
- customPicsPath = getSafeConfigPath("paths/custompics", picsPath + "/CUSTOM/");
- }
- customCardDatabasePath = getSafeConfigPath("paths/customsets", dataPath + "/customsets/");
+ QSettings pathsIni(getSettingsPath() + "paths.ini", QSettings::IniFormat);
- cardDatabasePath = getSafeConfigFilePath("paths/carddatabase", dataPath + "/cards.xml");
- tokenDatabasePath = getSafeConfigFilePath("paths/tokendatabase", dataPath + "/tokens.xml");
- spoilerDatabasePath = getSafeConfigFilePath("paths/spoilerdatabase", dataPath + "/spoiler.xml");
+ auto computePath = [&](const QString &key, const QString &defaultPath) -> QString {
+ QString val = pathsIni.value("paths/" + key).toString();
+ if (val.isEmpty() || !QDir(val).exists()) {
+ if (!QDir().mkpath(defaultPath)) {
+ qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
+ }
+ val = defaultPath;
+ pathsIni.setValue("paths/" + key, val);
+ }
+ return val;
+ };
+
+ auto computeFilePath = [&](const QString &key, const QString &defaultPath) -> QString {
+ QString val = pathsIni.value("paths/" + key).toString();
+ if (!QFile::exists(val) || val.isEmpty()) {
+ val = defaultPath;
+ pathsIni.setValue("paths/" + key, val);
+ }
+ return val;
+ };
+
+ computePath("decks", dataPath + "/decks/");
+ computePath("filters", dataPath + "/filters/");
+ computePath("replays", dataPath + "/replays/");
+ computePath("themes", dataPath + "/themes/");
+ computePath("pics", dataPath + "/pics/");
+ computePath("redirects", getCachePath() + "/redirects/");
+
+ // customPicsPath derived from picsPath
+ QString picsPath = pathsIni.value("paths/pics").toString();
+ if (picsPath.endsWith("/")) {
+ computePath("customPics", picsPath + "CUSTOM/");
+ } else {
+ computePath("customPics", picsPath + "/CUSTOM/");
+ }
+
+ computePath("customSets", dataPath + "/customsets/");
+ computeFilePath("cardDatabase", dataPath + "/cards.xml");
+ computeFilePath("tokenDatabase", dataPath + "/tokens.xml");
+ computeFilePath("spoilerDatabase", dataPath + "/spoiler.xml");
}
void SettingsCache::resetPaths()
{
- QStringList databasePaths{customCardDatabasePath, cardDatabasePath, spoilerDatabasePath, tokenDatabasePath};
- QString picsPath_ = picsPath;
- settings->remove("paths"); // removes all keys in paths/*
+ QStringList databasePaths{pathsSettings->getCustomCardDatabasePath(), pathsSettings->getCardDatabasePath(),
+ pathsSettings->getSpoilerCardDatabasePath(), pathsSettings->getTokenDatabasePath()};
+ QString picsPath_ = pathsSettings->getPicsPath();
+
+ QSettings pathsIni(getSettingsPath() + "paths.ini", QSettings::IniFormat);
+ pathsIni.remove("paths");
+
loadPaths();
- if (databasePaths !=
- QStringList{customCardDatabasePath, cardDatabasePath, spoilerDatabasePath, tokenDatabasePath}) {
+
+ if (databasePaths != QStringList{pathsSettings->getCustomCardDatabasePath(), pathsSettings->getCardDatabasePath(),
+ pathsSettings->getSpoilerCardDatabasePath(),
+ pathsSettings->getTokenDatabasePath()}) {
emit cardDatabasePathChanged();
}
- if (picsPath_ != picsPath) {
- emit picsPathChanged();
+ if (picsPath_ != pathsSettings->getPicsPath()) {
+ emit pathsSettings->picsPathChanged();
}
}
+// ICardDatabasePathProvider - delegate to pathsSettings
+QString SettingsCache::getCustomCardDatabasePath() const
+{
+ return pathsSettings->getCustomCardDatabasePath();
+}
+
+QString SettingsCache::getCardDatabasePath() const
+{
+ return pathsSettings->getCardDatabasePath();
+}
+
+QString SettingsCache::getSpoilerCardDatabasePath() const
+{
+ return pathsSettings->getSpoilerCardDatabasePath();
+}
+
+QString SettingsCache::getTokenDatabasePath() const
+{
+ return pathsSettings->getTokenDatabasePath();
+}
+
+// INetworkSettingsProvider - delegate to sub-objects
+int SettingsCache::getKeepAlive() const
+{
+ return networkSettings->getKeepAlive();
+}
+
+int SettingsCache::getTimeOut() const
+{
+ return networkSettings->getTimeOut();
+}
+
+bool SettingsCache::getNotifyAboutUpdates() const
+{
+ return updatesSettings->getNotifyAboutUpdates();
+}
+
+void SettingsCache::setKnownMissingFeatures(const QString &_knownMissingFeatures)
+{
+ networkSettings->setKnownMissingFeatures(_knownMissingFeatures);
+}
+
+QString SettingsCache::getKnownMissingFeatures()
+{
+ return networkSettings->getKnownMissingFeatures();
+}
+
+QString SettingsCache::getClientID()
+{
+ return networkSettings->getClientID();
+}
+
+// Release channels
+ReleaseChannel *SettingsCache::getUpdateReleaseChannel() const
+{
+ return releaseChannels.at(qMax(0, updatesSettings->getUpdateReleaseChannelIndex()));
+}
+
+QList SettingsCache::getUpdateReleaseChannels() const
+{
+ return releaseChannels;
+}
+
+int SettingsCache::getUpdateReleaseChannelIndex() const
+{
+ return updatesSettings->getUpdateReleaseChannelIndex();
+}
+
+// Sub-settings accessors
+ShortcutsSettings &SettingsCache::shortcuts() const
+{
+ return *shortcutsSettings;
+}
+
+CardDatabaseSettings &SettingsCache::cardDatabase() const
+{
+ return *cardDatabaseSettings;
+}
+
+ServersSettings &SettingsCache::servers() const
+{
+ return *serversSettings;
+}
+
+MessageSettings &SettingsCache::messages() const
+{
+ return *messageSettings;
+}
+
+GameFiltersSettings &SettingsCache::gameFilters() const
+{
+ return *gameFiltersSettings;
+}
+
+LayoutsSettings &SettingsCache::layouts() const
+{
+ return *layoutsSettings;
+}
+
+DownloadSettings &SettingsCache::downloads() const
+{
+ return *downloadSettings;
+}
+
+RecentsSettings &SettingsCache::recents() const
+{
+ return *recentsSettings;
+}
+
+CardOverrideSettings &SettingsCache::cardOverrides() const
+{
+ return *cardOverrideSettings;
+}
+
+DebugSettings &SettingsCache::debug() const
+{
+ return *debugSettings;
+}
+
CardCounterSettings &SettingsCache::cardCounters() const
{
return *cardCounterSettings;
}
+
+TabsSettings &SettingsCache::tabs() const
+{
+ return *tabsSettings;
+}
+
+SoundSettings &SettingsCache::sound() const
+{
+ return *soundSettings;
+}
+
+GameSettings &SettingsCache::game() const
+{
+ return *gameSettings;
+}
+
+ChatSettings &SettingsCache::chat() const
+{
+ return *chatSettings;
+}
+
+CacheStorageSettings &SettingsCache::cacheStorage() const
+{
+ return *cacheStorageSettings;
+}
+
+UpdatesSettings &SettingsCache::updates() const
+{
+ return *updatesSettings;
+}
+
+PersonalSettings &SettingsCache::personal() const
+{
+ return *personalSettings;
+}
+
+CardsDisplaySettings &SettingsCache::cardsDisplay() const
+{
+ return *cardsDisplaySettings;
+}
+
+InterfaceSettings &SettingsCache::userInterface() const
+{
+ return *interfaceSettings;
+}
+
+PathsSettings &SettingsCache::paths() const
+{
+ return *pathsSettings;
+}
+
+DeckEditorSettings &SettingsCache::deckEditor() const
+{
+ return *deckEditorSettings;
+}
+
+VisualDeckStorageSettings &SettingsCache::visualDeckStorage() const
+{
+ return *visualDeckStorageSettings;
+}
+
+AppearanceSettings &SettingsCache::appearance() const
+{
+ return *appearanceSettings;
+}
+
+NetworkSettings &SettingsCache::network() const
+{
+ return *networkSettings;
+}
diff --git a/cockatrice/src/client/settings/cache_settings.h b/cockatrice/src/client/settings/cache_settings.h
index 29af89587..23cdb4dbf 100644
--- a/cockatrice/src/client/settings/cache_settings.h
+++ b/cockatrice/src/client/settings/cache_settings.h
@@ -7,196 +7,55 @@
#ifndef SETTINGSCACHE_H
#define SETTINGSCACHE_H
-#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
-#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
-#include "shortcuts_settings.h"
-
-#include
#include
-#include
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
#include
inline Q_LOGGING_CATEGORY(SettingsCacheLog, "settings_cache");
class ReleaseChannel;
-// In MB (Increments of 64)
-#define PIXMAPCACHE_SIZE_DEFAULT 2048
-#define PIXMAPCACHE_SIZE_MIN 64
-#define PIXMAPCACHE_SIZE_MAX 4096
-
-// In MB
-constexpr int NETWORK_CACHE_SIZE_DEFAULT = 1024 * 4; // 4 GB
-constexpr int NETWORK_CACHE_SIZE_MIN = 1; // 1 MB
-constexpr int NETWORK_CACHE_SIZE_MAX = 1024 * 1024; // 1 TB
-
-// In Days
-#define NETWORK_REDIRECT_CACHE_TTL_DEFAULT 30
-#define NETWORK_REDIRECT_CACHE_TTL_MIN 1
-#define NETWORK_REDIRECT_CACHE_TTL_MAX 90
-
#define DEFAULT_LANG_NAME "English"
#define CLIENT_INFO_NOT_SET "notset"
#define DEFAULT_FONT_SIZE 12
-inline QStringList defaultTags = {
- // Strategies
- "🏃️ Aggro",
- "🧙️ Control",
- "⚔️ Midrange",
- "🌀 Combo",
- "🪓 Mill",
- "🔒 Stax",
- "🗺️ Landfall",
- "🛡️ Pillowfort",
- "🌱 Ramp",
- "⚡ Storm",
- "💀 Aristocrats",
- "☠️ Reanimator",
- "👹 Sacrifice",
- "🔥 Burn",
- "🌟 Lifegain",
- "🔮 Spellslinger",
- "👥 Tokens",
- "🎭 Blink",
- "⏳ Time Manipulation",
- "🌍 Domain",
- "💫 Proliferate",
- "📜 Saga",
- "🎲 Chaos",
- "🪄 Auras",
- "🔫 Pingers",
-
- // Themes
- "👑 Monarch",
- "🚀 Vehicles",
- "💉 Infect",
- "🩸 Madness",
- "🌀 Morph",
-
- // Card Types
- "⚔️ Creature",
- "💎 Artifact",
- "🌔 Enchantment",
- "📖 Sorcery",
- "⚡ Instant",
- "🌌 Planeswalker",
- "🌏 Land",
- "🪄 Aura",
-
- // Kindred Types
- "🐉 Kindred",
- "🧙 Humans",
- "⚔️ Soldiers",
- "🛡️ Knights",
- "🎻 Bards",
- "🧝 Elves",
- "🌲 Dryads",
- "😇 Angels",
- "🎩 Wizards",
- "🧛 Vampires",
- "🦴 Skeletons",
- "💀 Zombies",
- "👹 Demons",
- "👾 Eldrazi",
- "🐉 Dragons",
- "🐠 Merfolk",
- "🦁 Cats",
- "🐺 Wolves",
- "🐺 Werewolves",
- "🦇 Bats",
- "🐀 Rats",
- "🦅 Birds",
- "🦗 Insects",
- "🍄 Fungus",
- "🐚 Sea Creatures",
- "🐗 Boars",
- "🦊 Foxes",
- "🦄 Unicorns",
- "🐘 Elephants",
- "🐻 Bears",
- "🦏 Rhinos",
- "🦂 Scorpions",
-};
-
-class QSettings;
+class CacheStorageSettings;
class CardCounterSettings;
+class CardDatabaseSettings;
+class CardOverrideSettings;
+class CardsDisplaySettings;
+class ChatSettings;
+class CommanderBracketSettings;
+class DebugSettings;
+class DeckEditorSettings;
+class DownloadSettings;
+class GameFiltersSettings;
+class GameSettings;
+class InterfaceSettings;
+class LayoutsSettings;
+class MessageSettings;
+class PathsSettings;
+class PersonalSettings;
+class RecentsSettings;
+class ServersSettings;
+class ShortcutsSettings;
+class SoundSettings;
+class TabsSettings;
+class UpdatesSettings;
+class VisualDeckStorageSettings;
+class AppearanceSettings;
+class NetworkSettings;
+class QSettings;
class SettingsCache : public ICardDatabasePathProvider, public INetworkSettingsProvider
{
Q_OBJECT
signals:
- void langChanged();
- void picsPathChanged();
void themeChanged();
- void homeTabBackgroundSourceChanged();
- void homeTabBackgroundShuffleFrequencyChanged();
- void homeTabDisplayCardNameChanged();
- void picDownloadChanged();
- void showStatusBarChanged(bool state);
- void showGameSelectorFilterToolbarChanged(bool state);
- void displayCardNamesChanged();
- void overrideAllCardArtWithPersonalPreferenceChanged(bool _overrideAllCardArtWithPersonalPreference);
- void bumpSetsWithCardsInDeckToTopChanged();
- void printingSelectorSortOrderChanged();
- void printingSelectorCardSizeChanged();
- void includeRebalancedCardsChanged(bool _includeRebalancedCards);
- void printingSelectorNavigationButtonsVisibleChanged();
- void deckEditorBannerCardComboBoxVisibleChanged(bool _visible);
- void deckEditorTagsWidgetVisibleChanged(bool _visible);
- void visualDeckStorageShowTagFilterChanged(bool _visible);
- void visualDeckStorageDefaultTagsListChanged();
- void visualDeckStorageShowColorIdentityChanged(bool _visible);
- void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
- void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
- void visualDeckStorageCardSizeChanged();
- void visualDeckStorageDrawUnusedColorIdentitiesChanged(bool _visible);
- void visualDeckStorageUnusedColorIdentitiesOpacityChanged(bool value);
- void visualDeckStorageInGameChanged(bool enabled);
- void visualDeckStorageSelectionAnimationChanged(bool enabled);
- void visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged(bool enabled);
- void visualDatabaseDisplayFilterToMostRecentSetsAmountChanged(int amount);
- void visualDeckEditorSampleHandSizeAmountChanged(int amount);
- void visualDeckEditorCardSizeChanged();
- void visualDatabaseDisplayCardSizeChanged();
- void edhRecCardSizeChanged();
- void archidektPreviewSizeChanged();
- void horizontalHandChanged();
- void handJustificationChanged();
- void invertVerticalCoordinateChanged();
- void minPlayersForMultiColumnLayoutChanged();
- void soundEnabledChanged();
- void soundThemeChanged();
- void ignoreUnregisteredUsersChanged();
- void ignoreUnregisteredUserMessagesChanged();
- void ignoreNonBuddyUserMessagesChanged();
- void pixmapCacheSizeChanged(int newSizeInMBs);
- void networkCacheSizeChanged(int newSizeInMBs);
- void redirectCacheTtlChanged(int newTtl);
- void cardPictureLoaderCacheMethodChanged(int cardPictureLoaderCacheMethod);
- void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme);
- void masterVolumeChanged(int value);
- void styleUserListChanged();
- void chatMentionCompleterChanged();
- void downloadSpoilerTimeIndexChanged();
- void downloadSpoilerStatusChanged();
- void useTearOffMenusChanged(bool state);
- void roundCardCornersChanged(bool roundCardCorners);
- void keepGameChatFocusChanged(bool value);
private:
QSettings *settings;
@@ -211,151 +70,30 @@ private:
CardOverrideSettings *cardOverrideSettings;
DebugSettings *debugSettings;
CardCounterSettings *cardCounterSettings;
+ TabsSettings *tabsSettings;
+ SoundSettings *soundSettings;
+ GameSettings *gameSettings;
+ ChatSettings *chatSettings;
+ CacheStorageSettings *cacheStorageSettings;
+ UpdatesSettings *updatesSettings;
+ PersonalSettings *personalSettings;
+ CardsDisplaySettings *cardsDisplaySettings;
+ InterfaceSettings *interfaceSettings;
+ DeckEditorSettings *deckEditorSettings;
+ PathsSettings *pathsSettings;
+ VisualDeckStorageSettings *visualDeckStorageSettings;
+ AppearanceSettings *appearanceSettings;
+ NetworkSettings *networkSettings;
+ CommanderBracketSettings *commanderBracketSettings;
- QString lang;
- QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
- customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
- bool tabVisualDeckStorageOpen, tabServerOpen, tabAccountOpen, tabDeckStorageOpen, tabReplaysOpen, tabAdminOpen,
- tabLogOpen;
- bool checkUpdatesOnStartup;
- bool startupCardUpdateCheckPromptForUpdate;
- bool startupCardUpdateCheckAlwaysUpdate;
- bool checkCardUpdatesOnStartup;
- int cardUpdateCheckInterval;
- QDate lastCardUpdateCheck;
- bool alwaysEnableNewSets;
- bool notifyAboutUpdates;
- bool notifyAboutNewVersion;
- bool showTipsOnStartup;
- QList seenTips;
- int homeTabBackgroundShuffleFrequency;
- bool homeTabDisplayCardName;
- bool mbDownloadSpoilers;
- int updateReleaseChannel;
- int maxFontSize;
- bool picDownload;
- bool notificationsEnabled;
- bool spectatorNotificationsEnabled;
- bool buddyConnectNotificationsEnabled;
- bool doubleClickToPlay;
- bool clickPlaysAllSelected;
- bool playToStack;
- bool doNotDeleteArrowsInSubPhases;
- int startingHandSize;
- bool annotateTokens;
- bool showShortcuts;
- bool showGameSelectorFilterToolbar;
- bool displayCardNames;
- bool overrideAllCardArtWithPersonalPreference;
- bool bumpSetsWithCardsInDeckToTop;
- int printingSelectorSortOrder;
- int printingSelectorCardSize;
- bool includeRebalancedCards;
- bool printingSelectorNavigationButtonsVisible;
- bool deckEditorBannerCardComboBoxVisible;
- bool deckEditorTagsWidgetVisible;
- int visualDeckStorageSortingOrder;
- bool visualDeckStorageShowFolders;
- bool visualDeckStorageShowColorIdentity;
- bool visualDeckStorageShowBannerCardComboBox;
- bool visualDeckStorageShowTagsOnDeckPreviews;
- bool visualDeckStorageShowTagFilter;
- QStringList visualDeckStorageDefaultTagsList;
- bool visualDeckStorageSearchFolderNames;
- int visualDeckStorageCardSize;
- int visualDeckEditorCardSize;
- int visualDatabaseDisplayCardSize;
- int edhrecCardSize;
- int archidektPreviewSize;
- bool visualDeckStorageDrawUnusedColorIdentities;
- int visualDeckStorageUnusedColorIdentitiesOpacity;
- int visualDeckStorageTooltipType;
- bool visualDeckStoragePromptForConversion;
- bool visualDeckStorageAlwaysConvert;
- bool visualDeckStorageInGame;
- bool visualDeckStorageSelectionAnimation;
- int defaultDeckEditorType;
- bool visualDatabaseDisplayFilterToMostRecentSetsEnabled;
- int visualDatabaseDisplayFilterToMostRecentSetsAmount;
- int visualDeckEditorSampleHandSize;
- bool horizontalHand;
- bool invertVerticalCoordinate;
- int minPlayersForMultiColumnLayout;
- bool tapAnimation;
- bool autoRotateSidewaysLayoutCards;
- bool openDeckInNewTab;
- int rewindBufferingMs;
- bool styleUserList;
- bool chatMention;
- bool chatMentionCompleter;
- QString chatMentionColor;
- QString chatHighlightColor;
- bool chatMentionForeground;
- bool chatHighlightForeground;
- int zoneViewSortByIndex, zoneViewGroupByIndex;
- bool zoneViewPileView;
- bool soundEnabled;
- QString soundThemeName;
- bool ignoreUnregisteredUsers;
- bool ignoreUnregisteredUserMessages;
- bool ignoreNonBuddyUserMessages;
- QString picUrl;
- QString picUrlFallback;
- QString clientID;
- QString clientVersion;
- QString knownMissingFeatures;
- bool useTearOffMenus;
- int cardViewInitialRowsMax;
- int cardViewExpandedRowsMax;
- bool closeEmptyCardView;
- bool focusCardViewSearchBar;
- bool keepGameChatFocus;
- int pixmapCacheSize;
- int networkCacheSize;
- int redirectCacheTtl;
- int cardPictureLoaderCacheMethod;
- int localCardImageStorageNamingScheme;
- bool scaleCards;
- int verticalCardOverlapPercent;
- bool showMessagePopups;
- bool showMentionPopups;
- bool roomHistory;
- bool leftJustified;
- int masterVolume;
- int cardInfoViewMode;
- QString highlightWords;
- QString gameDescription;
- int maxPlayers;
- QString gameTypes;
- bool onlyBuddies;
- bool onlyRegistered;
- bool spectatorsAllowed;
- bool spectatorsNeedPassword;
- bool spectatorsCanTalk;
- bool spectatorsCanSeeEverything;
- bool createGameAsSpectator;
- int defaultStartingLifeTotal;
- bool shareDecklistsOnLoad;
- int keepalive;
- int timeout;
- void translateLegacySettings();
- [[nodiscard]] QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
- [[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
- void loadPaths();
- bool rememberGameSettings;
-
- // Local game settings (separate from server game settings in game/*)
- bool localGameRememberSettings;
- int localGameMaxPlayers;
- int localGameStartingLifeTotal;
+ QString themeName;
QList releaseChannels;
bool isPortableBuild;
- bool roundCardCorners;
- bool showStatusBar;
- bool showDragSelectionCount;
- bool showTotalSelectionCount;
- bool showSubtypeSelectionTally;
+
+ [[nodiscard]] QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
+ [[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
+ void loadPaths();
public:
SettingsCache();
@@ -363,824 +101,71 @@ public:
QString getSettingsPath();
[[nodiscard]] QString getCachePath() const;
[[nodiscard]] QString getNetworkCachePath() const;
- [[nodiscard]] QString getLang() const
- {
- return lang;
- }
- [[nodiscard]] QString getDeckPath() const
- {
- return deckPath;
- }
- [[nodiscard]] QString getFiltersPath() const
- {
- return filtersPath;
- }
- [[nodiscard]] QString getReplaysPath() const
- {
- return replaysPath;
- }
- [[nodiscard]] QString getThemesPath() const
- {
- return themesPath;
- }
- [[nodiscard]] QString getPicsPath() const
- {
- return picsPath;
- }
- [[nodiscard]] QString getRedirectCachePath() const
- {
- return redirectCachePath;
- }
- [[nodiscard]] QString getCustomPicsPath() const
- {
- return customPicsPath;
- }
- [[nodiscard]] QString getCustomCardDatabasePath() const override
- {
- return customCardDatabasePath;
- }
- [[nodiscard]] QString getCardDatabasePath() const override
- {
- return cardDatabasePath;
- }
- [[nodiscard]] QString getSpoilerCardDatabasePath() const override
- {
- return spoilerDatabasePath;
- }
- [[nodiscard]] QString getTokenDatabasePath() const override
- {
- return tokenDatabasePath;
- }
+
+ // ICardDatabasePathProvider - delegate to pathsSettings
+ [[nodiscard]] QString getCustomCardDatabasePath() const override;
+ [[nodiscard]] QString getCardDatabasePath() const override;
+ [[nodiscard]] QString getSpoilerCardDatabasePath() const override;
+ [[nodiscard]] QString getTokenDatabasePath() const override;
+
+ // INetworkSettingsProvider - delegate to sub-objects
+ [[nodiscard]] int getKeepAlive() const override;
+ [[nodiscard]] int getTimeOut() const override;
+ [[nodiscard]] bool getNotifyAboutUpdates() const override;
+ void setKnownMissingFeatures(const QString &_knownMissingFeatures) override;
+ [[nodiscard]] QString getKnownMissingFeatures() override;
+ QString getClientID() override;
+
[[nodiscard]] QString getThemeName() const
{
return themeName;
}
- [[nodiscard]] QString getHomeTabBackgroundSource() const
- {
- return homeTabBackgroundSource;
- }
- [[nodiscard]] int getHomeTabBackgroundShuffleFrequency() const
- {
- return homeTabBackgroundShuffleFrequency;
- }
- [[nodiscard]] bool getHomeTabDisplayCardName() const
- {
- return homeTabDisplayCardName;
- }
- [[nodiscard]] bool getTabVisualDeckStorageOpen() const
- {
- return tabVisualDeckStorageOpen;
- }
- [[nodiscard]] bool getTabServerOpen() const
- {
- return tabServerOpen;
- }
- [[nodiscard]] bool getTabAccountOpen() const
- {
- return tabAccountOpen;
- }
- [[nodiscard]] bool getTabDeckStorageOpen() const
- {
- return tabDeckStorageOpen;
- }
- [[nodiscard]] bool getTabReplaysOpen() const
- {
- return tabReplaysOpen;
- }
- [[nodiscard]] bool getTabAdminOpen() const
- {
- return tabAdminOpen;
- }
- [[nodiscard]] bool getTabLogOpen() const
- {
- return tabLogOpen;
- }
- [[nodiscard]] QString getChatMentionColor() const
- {
- return chatMentionColor;
- }
- [[nodiscard]] QString getChatHighlightColor() const
- {
- return chatHighlightColor;
- }
- [[nodiscard]] bool getPicDownload() const
- {
- return picDownload;
- }
- [[nodiscard]] bool getShowStatusBar() const
- {
- return showStatusBar;
- }
- [[nodiscard]] bool getShowDragSelectionCount() const
- {
- return showDragSelectionCount;
- }
- [[nodiscard]] bool getShowTotalSelectionCount() const
- {
- return showTotalSelectionCount;
- }
- [[nodiscard]] bool getShowSubtypeSelectionTally() const
- {
- return showSubtypeSelectionTally;
- }
- [[nodiscard]] bool getNotificationsEnabled() const
- {
- return notificationsEnabled;
- }
- [[nodiscard]] bool getSpectatorNotificationsEnabled() const
- {
- return spectatorNotificationsEnabled;
- }
- [[nodiscard]] bool getBuddyConnectNotificationsEnabled() const
- {
- return buddyConnectNotificationsEnabled;
- }
- [[nodiscard]] bool getCheckUpdatesOnStartup() const
- {
- return checkUpdatesOnStartup;
- }
- bool getStartupCardUpdateCheckPromptForUpdate()
- {
- return startupCardUpdateCheckPromptForUpdate;
- }
- bool getStartupCardUpdateCheckAlwaysUpdate()
- {
- return startupCardUpdateCheckAlwaysUpdate;
- }
- [[nodiscard]] int getCardUpdateCheckInterval() const
- {
- return cardUpdateCheckInterval;
- }
- [[nodiscard]] QDate getLastCardUpdateCheck() const
- {
- return lastCardUpdateCheck;
- }
- [[nodiscard]] bool getCardUpdateCheckRequired() const
- {
- return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() &&
- getLastCardUpdateCheck() != QDateTime::currentDateTime().date();
- }
- [[nodiscard]] bool getAlwaysEnableNewSets() const
- {
- return alwaysEnableNewSets;
- }
- [[nodiscard]] bool getNotifyAboutUpdates() const override
- {
- return notifyAboutUpdates;
- }
- [[nodiscard]] bool getNotifyAboutNewVersion() const
- {
- return notifyAboutNewVersion;
- }
- [[nodiscard]] bool getShowTipsOnStartup() const
- {
- return showTipsOnStartup;
- }
- [[nodiscard]] QList getSeenTips() const
- {
- return seenTips;
- }
- [[nodiscard]] int getUpdateReleaseChannelIndex() const
- {
- return updateReleaseChannel;
- }
- [[nodiscard]] ReleaseChannel *getUpdateReleaseChannel() const
- {
- return releaseChannels.at(qMax(0, updateReleaseChannel));
- }
- [[nodiscard]] QList getUpdateReleaseChannels() const
- {
- return releaseChannels;
- }
- [[nodiscard]] bool getDoubleClickToPlay() const
- {
- return doubleClickToPlay;
- }
- [[nodiscard]] bool getClickPlaysAllSelected() const
- {
- return clickPlaysAllSelected;
- }
- [[nodiscard]] bool getPlayToStack() const
- {
- return playToStack;
- }
- [[nodiscard]] bool getDoNotDeleteArrowsInSubPhases() const
- {
- return doNotDeleteArrowsInSubPhases;
- }
- [[nodiscard]] int getStartingHandSize() const
- {
- return startingHandSize;
- }
- [[nodiscard]] bool getAnnotateTokens() const
- {
- return annotateTokens;
- }
- [[nodiscard]] bool getShowShortcuts() const
- {
- return showShortcuts;
- }
- [[nodiscard]] bool getShowGameSelectorFilterToolbar() const
- {
- return showGameSelectorFilterToolbar;
- }
- [[nodiscard]] bool getDisplayCardNames() const
- {
- return displayCardNames;
- }
- [[nodiscard]] bool getOverrideAllCardArtWithPersonalPreference() const
- {
- return overrideAllCardArtWithPersonalPreference;
- }
- [[nodiscard]] bool getBumpSetsWithCardsInDeckToTop() const
- {
- return bumpSetsWithCardsInDeckToTop;
- }
- [[nodiscard]] int getPrintingSelectorSortOrder() const
- {
- return printingSelectorSortOrder;
- }
- [[nodiscard]] int getPrintingSelectorCardSize() const
- {
- return printingSelectorCardSize;
- }
- [[nodiscard]] bool getIncludeRebalancedCards() const
- {
- return includeRebalancedCards;
- }
- [[nodiscard]] bool getPrintingSelectorNavigationButtonsVisible() const
- {
- return printingSelectorNavigationButtonsVisible;
- }
- [[nodiscard]] bool getDeckEditorBannerCardComboBoxVisible() const
- {
- return deckEditorBannerCardComboBoxVisible;
- }
- [[nodiscard]] bool getDeckEditorTagsWidgetVisible() const
- {
- return deckEditorTagsWidgetVisible;
- }
- [[nodiscard]] int getVisualDeckStorageSortingOrder() const
- {
- return visualDeckStorageSortingOrder;
- }
- [[nodiscard]] bool getVisualDeckStorageShowFolders() const
- {
- return visualDeckStorageShowFolders;
- }
- [[nodiscard]] bool getVisualDeckStorageShowTagFilter() const
- {
- return visualDeckStorageShowTagFilter;
- }
- [[nodiscard]] QStringList getVisualDeckStorageDefaultTagsList() const
- {
- return visualDeckStorageDefaultTagsList;
- }
- [[nodiscard]] bool getVisualDeckStorageSearchFolderNames() const
- {
- return visualDeckStorageSearchFolderNames;
- }
- [[nodiscard]] bool getVisualDeckStorageShowColorIdentity() const
- {
- return visualDeckStorageShowColorIdentity;
- }
- [[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
- {
- return visualDeckStorageShowBannerCardComboBox;
- }
- [[nodiscard]] bool getVisualDeckStorageShowTagsOnDeckPreviews() const
- {
- return visualDeckStorageShowTagsOnDeckPreviews;
- }
- [[nodiscard]] int getVisualDeckStorageCardSize() const
- {
- return visualDeckStorageCardSize;
- }
- [[nodiscard]] bool getVisualDeckStorageDrawUnusedColorIdentities() const
- {
- return visualDeckStorageDrawUnusedColorIdentities;
- }
- [[nodiscard]] int getVisualDeckStorageUnusedColorIdentitiesOpacity() const
- {
- return visualDeckStorageUnusedColorIdentitiesOpacity;
- }
- [[nodiscard]] int getVisualDeckStorageTooltipType() const
- {
- return visualDeckStorageTooltipType;
- }
- [[nodiscard]] bool getVisualDeckStoragePromptForConversion() const
- {
- return visualDeckStoragePromptForConversion;
- }
- [[nodiscard]] bool getVisualDeckStorageAlwaysConvert() const
- {
- return visualDeckStorageAlwaysConvert;
- }
- [[nodiscard]] bool getVisualDeckStorageInGame() const
- {
- return visualDeckStorageInGame;
- }
- [[nodiscard]] bool getVisualDeckStorageSelectionAnimation() const
- {
- return visualDeckStorageSelectionAnimation;
- }
- [[nodiscard]] int getVisualDeckEditorCardSize() const
- {
- return visualDeckEditorCardSize;
- }
- [[nodiscard]] int getVisualDatabaseDisplayCardSize() const
- {
- return visualDatabaseDisplayCardSize;
- }
- [[nodiscard]] int getEDHRecCardSize() const
- {
- return edhrecCardSize;
- }
- [[nodiscard]] int getArchidektPreviewSize() const
- {
- return archidektPreviewSize;
- }
- [[nodiscard]] int getDefaultDeckEditorType() const
- {
- return defaultDeckEditorType;
- }
- [[nodiscard]] bool getVisualDatabaseDisplayFilterToMostRecentSetsEnabled() const
- {
- return visualDatabaseDisplayFilterToMostRecentSetsEnabled;
- }
- [[nodiscard]] int getVisualDatabaseDisplayFilterToMostRecentSetsAmount() const
- {
- return visualDatabaseDisplayFilterToMostRecentSetsAmount;
- }
- [[nodiscard]] int getVisualDeckEditorSampleHandSize() const
- {
- return visualDeckEditorSampleHandSize;
- }
- [[nodiscard]] bool getHorizontalHand() const
- {
- return horizontalHand;
- }
- [[nodiscard]] bool getInvertVerticalCoordinate() const
- {
- return invertVerticalCoordinate;
- }
- [[nodiscard]] int getMinPlayersForMultiColumnLayout() const
- {
- return minPlayersForMultiColumnLayout;
- }
- [[nodiscard]] bool getTapAnimation() const
- {
- return tapAnimation;
- }
- [[nodiscard]] bool getAutoRotateSidewaysLayoutCards() const
- {
- return autoRotateSidewaysLayoutCards;
- }
- [[nodiscard]] bool getOpenDeckInNewTab() const
- {
- return openDeckInNewTab;
- }
- [[nodiscard]] int getRewindBufferingMs() const
- {
- return rewindBufferingMs;
- }
- [[nodiscard]] bool getStyleUserList() const
- {
- return styleUserList;
- }
- [[nodiscard]] bool getChatMention() const
- {
- return chatMention;
- }
- [[nodiscard]] bool getChatMentionCompleter() const
- {
- return chatMentionCompleter;
- }
- [[nodiscard]] bool getChatMentionForeground() const
- {
- return chatMentionForeground;
- }
- [[nodiscard]] bool getChatHighlightForeground() const
- {
- return chatHighlightForeground;
- }
- /**
- * Currently selected index for the `Group by X` QComboBox
- */
- [[nodiscard]] int getZoneViewGroupByIndex() const
- {
- return zoneViewGroupByIndex;
- }
- /**
- * Currently selected index for the `Sort by X` QComboBox
- */
- [[nodiscard]] int getZoneViewSortByIndex() const
- {
- return zoneViewSortByIndex;
- }
- /**
- Returns if the view should be sorted into pile view.
- @return zoneViewPileView if the view should be sorted into pile view.
- */
- [[nodiscard]] bool getZoneViewPileView() const
- {
- return zoneViewPileView;
- }
- [[nodiscard]] bool getSoundEnabled() const
- {
- return soundEnabled;
- }
- [[nodiscard]] QString getSoundThemeName() const
- {
- return soundThemeName;
- }
- [[nodiscard]] bool getIgnoreUnregisteredUsers() const
- {
- return ignoreUnregisteredUsers;
- }
- [[nodiscard]] bool getIgnoreUnregisteredUserMessages() const
- {
- return ignoreUnregisteredUserMessages;
- }
- [[nodiscard]] bool getIgnoreNonBuddyUserMessages() const
- {
- return ignoreNonBuddyUserMessages;
- }
- [[nodiscard]] int getPixmapCacheSize() const
- {
- return pixmapCacheSize;
- }
- [[nodiscard]] CardPictureLoaderCacheMethod::CacheMethod getCardPictureLoaderCacheMethod() const
- {
- return static_cast(cardPictureLoaderCacheMethod);
- }
- [[nodiscard]] int getNetworkCacheSizeInMB() const
- {
- return networkCacheSize;
- }
- [[nodiscard]] int getRedirectCacheTtl() const
- {
- return redirectCacheTtl;
- }
- [[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const
- {
- return static_cast(localCardImageStorageNamingScheme);
- }
- [[nodiscard]] bool getScaleCards() const
- {
- return scaleCards;
- }
- [[nodiscard]] int getStackCardOverlapPercent() const
- {
- return verticalCardOverlapPercent;
- }
- [[nodiscard]] bool getShowMessagePopup() const
- {
- return showMessagePopups;
- }
- [[nodiscard]] bool getShowMentionPopup() const
- {
- return showMentionPopups;
- }
- [[nodiscard]] bool getRoomHistory() const
- {
- return roomHistory;
- }
- [[nodiscard]] bool getLeftJustified() const
- {
- return leftJustified;
- }
- [[nodiscard]] int getMasterVolume() const
- {
- return masterVolume;
- }
- [[nodiscard]] int getCardInfoViewMode() const
- {
- return cardInfoViewMode;
- }
+ [[nodiscard]] ReleaseChannel *getUpdateReleaseChannel() const;
+ [[nodiscard]] QList getUpdateReleaseChannels() const;
+ [[nodiscard]] int getUpdateReleaseChannelIndex() const;
+
[[nodiscard]] QStringList getCountries() const;
- [[nodiscard]] QString getHighlightWords() const
- {
- return highlightWords;
- }
- [[nodiscard]] QString getGameDescription() const
- {
- return gameDescription;
- }
- [[nodiscard]] int getMaxPlayers() const
- {
- return maxPlayers;
- }
- [[nodiscard]] QString getGameTypes() const
- {
- return gameTypes;
- }
- [[nodiscard]] bool getOnlyBuddies() const
- {
- return onlyBuddies;
- }
- [[nodiscard]] bool getOnlyRegistered() const
- {
- return onlyRegistered;
- }
- [[nodiscard]] bool getSpectatorsAllowed() const
- {
- return spectatorsAllowed;
- }
- [[nodiscard]] bool getSpectatorsNeedPassword() const
- {
- return spectatorsNeedPassword;
- }
- [[nodiscard]] bool getSpectatorsCanTalk() const
- {
- return spectatorsCanTalk;
- }
- [[nodiscard]] bool getSpectatorsCanSeeEverything() const
- {
- return spectatorsCanSeeEverything;
- }
- [[nodiscard]] int getDefaultStartingLifeTotal() const
- {
- return defaultStartingLifeTotal;
- }
- [[nodiscard]] bool getShareDecklistsOnLoad() const
- {
- return shareDecklistsOnLoad;
- }
- [[nodiscard]] bool getCreateGameAsSpectator() const
- {
- return createGameAsSpectator;
- }
- [[nodiscard]] bool getRememberGameSettings() const
- {
- return rememberGameSettings;
- }
- [[nodiscard]] bool getLocalGameRememberSettings() const
- {
- return localGameRememberSettings;
- }
- [[nodiscard]] int getLocalGameMaxPlayers() const
- {
- return localGameMaxPlayers;
- }
- [[nodiscard]] int getLocalGameStartingLifeTotal() const
- {
- return localGameStartingLifeTotal;
- }
- [[nodiscard]] int getKeepAlive() const override
- {
- return keepalive;
- }
- [[nodiscard]] int getTimeOut() const override
- {
- return timeout;
- }
- [[nodiscard]] int getMaxFontSize() const
- {
- return maxFontSize;
- }
- void setClientID(const QString &clientID);
- void setClientVersion(const QString &clientVersion);
- void setKnownMissingFeatures(const QString &_knownMissingFeatures) override;
- void setUseTearOffMenus(bool _useTearOffMenus);
- void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
- void setCardViewExpandedRowsMax(int value);
- void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
- void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
- void setKeepGameChatFocus(QT_STATE_CHANGED_T value);
- QString getClientID() override
- {
- return clientID;
- }
- QString getClientVersion()
- {
- return clientVersion;
- }
- QString getKnownMissingFeatures() override
- {
- return knownMissingFeatures;
- }
- bool getUseTearOffMenus()
- {
- return useTearOffMenus;
- }
- [[nodiscard]] int getCardViewInitialRowsMax() const
- {
- return cardViewInitialRowsMax;
- }
- [[nodiscard]] int getCardViewExpandedRowsMax() const
- {
- return cardViewExpandedRowsMax;
- }
- [[nodiscard]] bool getCloseEmptyCardView() const
- {
- return closeEmptyCardView;
- }
- [[nodiscard]] bool getFocusCardViewSearchBar() const
- {
- return focusCardViewSearchBar;
- }
- [[nodiscard]] bool getKeepGameChatFocus() const
- {
- return keepGameChatFocus;
- }
- [[nodiscard]] ShortcutsSettings &shortcuts() const
- {
- return *shortcutsSettings;
- }
- [[nodiscard]] CardDatabaseSettings *cardDatabase() const
- {
- return cardDatabaseSettings;
- }
- [[nodiscard]] ServersSettings &servers() const
- {
- return *serversSettings;
- }
- [[nodiscard]] MessageSettings &messages() const
- {
- return *messageSettings;
- }
- [[nodiscard]] GameFiltersSettings &gameFilters() const
- {
- return *gameFiltersSettings;
- }
- [[nodiscard]] LayoutsSettings &layouts() const
- {
- return *layoutsSettings;
- }
- [[nodiscard]] DownloadSettings &downloads() const
- {
- return *downloadSettings;
- }
- [[nodiscard]] RecentsSettings &recents() const
- {
- return *recentsSettings;
- }
- [[nodiscard]] CardOverrideSettings &cardOverrides() const
- {
- return *cardOverrideSettings;
- }
- [[nodiscard]] DebugSettings &debug() const
- {
- return *debugSettings;
- }
+
+ [[nodiscard]] ShortcutsSettings &shortcuts() const;
+ [[nodiscard]] CardDatabaseSettings &cardDatabase() const;
+ [[nodiscard]] ServersSettings &servers() const;
+ [[nodiscard]] MessageSettings &messages() const;
+ [[nodiscard]] GameFiltersSettings &gameFilters() const;
+ [[nodiscard]] LayoutsSettings &layouts() const;
+ [[nodiscard]] DownloadSettings &downloads() const;
+ [[nodiscard]] RecentsSettings &recents() const;
+ [[nodiscard]] CardOverrideSettings &cardOverrides() const;
+ [[nodiscard]] DebugSettings &debug() const;
[[nodiscard]] CardCounterSettings &cardCounters() const;
+ [[nodiscard]] TabsSettings &tabs() const;
+ [[nodiscard]] SoundSettings &sound() const;
+ [[nodiscard]] GameSettings &game() const;
+ [[nodiscard]] ChatSettings &chat() const;
+ [[nodiscard]] CacheStorageSettings &cacheStorage() const;
+ [[nodiscard]] UpdatesSettings &updates() const;
+ [[nodiscard]] PersonalSettings &personal() const;
+ [[nodiscard]] CardsDisplaySettings &cardsDisplay() const;
+ [[nodiscard]] InterfaceSettings &userInterface() const;
+ [[nodiscard]] DeckEditorSettings &deckEditor() const;
+ [[nodiscard]] PathsSettings &paths() const;
+ [[nodiscard]] VisualDeckStorageSettings &visualDeckStorage() const;
+ [[nodiscard]] AppearanceSettings &appearance() const;
+ [[nodiscard]] NetworkSettings &network() const;
+ [[nodiscard]] CommanderBracketSettings &commanderBrackets() const
+ {
+ return *commanderBracketSettings;
+ }
[[nodiscard]] bool getIsPortableBuild() const
{
return isPortableBuild;
}
- [[nodiscard]] bool getDownloadSpoilersStatus() const
- {
- return mbDownloadSpoilers;
- }
- [[nodiscard]] bool getRoundCardCorners() const
- {
- return roundCardCorners;
- }
static SettingsCache &instance();
void resetPaths();
public slots:
- void setDownloadSpoilerStatus(bool _spoilerStatus);
-
- void setLang(const QString &_lang);
- void setShowTipsOnStartup(bool _showTipsOnStartup);
- void setSeenTips(const QList &_seenTips);
- void setDeckPath(const QString &_deckPath);
- void setFiltersPath(const QString &_filtersPath);
- void setReplaysPath(const QString &_replaysPath);
- void setThemesPath(const QString &_themesPath);
- void setCustomCardDatabasePath(const QString &_customCardDatabasePath);
- void setPicsPath(const QString &_picsPath);
- void setCardDatabasePath(const QString &_cardDatabasePath);
- void setSpoilerDatabasePath(const QString &_spoilerDatabasePath);
- void setTokenDatabasePath(const QString &_tokenDatabasePath);
void setThemeName(const QString &_themeName);
- void setHomeTabBackgroundSource(const QString &_backgroundSource);
- void setHomeTabBackgroundShuffleFrequency(int _frequency);
- void setHomeTabDisplayCardName(QT_STATE_CHANGED_T _displayCardName);
- void setTabVisualDeckStorageOpen(bool value);
- void setTabServerOpen(bool value);
- void setTabAccountOpen(bool value);
- void setTabDeckStorageOpen(bool value);
- void setTabReplaysOpen(bool value);
- void setTabAdminOpen(bool value);
- void setTabLogOpen(bool value);
- void setChatMentionColor(const QString &_chatMentionColor);
- void setChatHighlightColor(const QString &_chatHighlightColor);
- void setPicDownload(QT_STATE_CHANGED_T _picDownload);
- void setShowStatusBar(bool value);
- void setNotificationsEnabled(QT_STATE_CHANGED_T _notificationsEnabled);
- void setSpectatorNotificationsEnabled(QT_STATE_CHANGED_T _spectatorNotificationsEnabled);
- void setBuddyConnectNotificationsEnabled(QT_STATE_CHANGED_T _buddyConnectNotificationsEnabled);
- void setDoubleClickToPlay(QT_STATE_CHANGED_T _doubleClickToPlay);
- void setClickPlaysAllSelected(QT_STATE_CHANGED_T _clickPlaysAllSelected);
- void setPlayToStack(QT_STATE_CHANGED_T _playToStack);
- void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
- void setStartingHandSize(int _startingHandSize);
- void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
- void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
- void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
- void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
- void setOverrideAllCardArtWithPersonalPreference(QT_STATE_CHANGED_T _overrideAllCardArt);
- void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
- void setPrintingSelectorSortOrder(int _printingSelectorSortOrder);
- void setPrintingSelectorCardSize(int _printingSelectorCardSize);
- void setIncludeRebalancedCards(bool _includeRebalancedCards);
- void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
- void setDeckEditorBannerCardComboBoxVisible(QT_STATE_CHANGED_T _deckEditorBannerCardComboBoxVisible);
- void setDeckEditorTagsWidgetVisible(QT_STATE_CHANGED_T _deckEditorTagsWidgetVisible);
- void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
- void setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value);
- void setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags);
- void setVisualDeckStorageDefaultTagsList(QStringList _defaultTagsList);
- void setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T value);
- void setVisualDeckStorageShowColorIdentity(QT_STATE_CHANGED_T value);
- void setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox);
- void setVisualDeckStorageShowTagsOnDeckPreviews(QT_STATE_CHANGED_T _showTags);
- void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
- void setVisualDeckStorageDrawUnusedColorIdentities(QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities);
- void setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity);
- void setVisualDeckStorageTooltipType(int value);
- void setVisualDeckStoragePromptForConversion(bool _visualDeckStoragePromptForConversion);
- void setVisualDeckStorageAlwaysConvert(bool _visualDeckStorageAlwaysConvert);
- void setVisualDeckStorageInGame(QT_STATE_CHANGED_T value);
- void setVisualDeckStorageSelectionAnimation(QT_STATE_CHANGED_T value);
- void setVisualDeckEditorCardSize(int _visualDeckEditorCardSize);
- void setVisualDatabaseDisplayCardSize(int _visualDatabaseDisplayCardSize);
- void setEDHRecCardSize(int _EDHRecCardSize);
- void setArchidektPreviewCardSize(int _archidektPreviewCardSize);
- void setDefaultDeckEditorType(int value);
- void setVisualDatabaseDisplayFilterToMostRecentSetsEnabled(QT_STATE_CHANGED_T _enabled);
- void setVisualDatabaseDisplayFilterToMostRecentSetsAmount(int _amount);
- void setVisualDeckEditorSampleHandSize(int _amount);
- void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
- void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
- void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
- void setTapAnimation(QT_STATE_CHANGED_T _tapAnimation);
- void setAutoRotateSidewaysLayoutCards(QT_STATE_CHANGED_T _autoRotateSidewaysLayoutCards);
- void setOpenDeckInNewTab(QT_STATE_CHANGED_T _openDeckInNewTab);
- void setRewindBufferingMs(int _rewindBufferingMs);
- void setStyleUserList(QT_STATE_CHANGED_T _styleUserList);
- void setChatMention(QT_STATE_CHANGED_T _chatMention);
- void setChatMentionCompleter(QT_STATE_CHANGED_T _chatMentionCompleter);
- void setChatMentionForeground(QT_STATE_CHANGED_T _chatMentionForeground);
- void setChatHighlightForeground(QT_STATE_CHANGED_T _chatHighlightForeground);
- void setZoneViewGroupByIndex(const int _zoneViewGroupByIndex);
- void setZoneViewSortByIndex(const int _zoneViewSortByIndex);
- void setZoneViewPileView(QT_STATE_CHANGED_T _zoneViewPileView);
- void setSoundEnabled(QT_STATE_CHANGED_T _soundEnabled);
- void setSoundThemeName(const QString &_soundThemeName);
- void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers);
- void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages);
- void setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages);
- void setPixmapCacheSize(const int _pixmapCacheSize);
- void setCardImageCacheMethod(CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod);
- void setNetworkCacheSizeInMB(const int _networkCacheSize);
- void setNetworkRedirectCacheTtl(const int _redirectCacheTtl);
- void setLocalCardImageStorageNamingScheme(
- const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme);
- void setCardScaling(const QT_STATE_CHANGED_T _scaleCards);
- void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
- void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups);
- void setShowMentionPopups(const QT_STATE_CHANGED_T _showMentionPopups);
- void setRoomHistory(const QT_STATE_CHANGED_T _roomHistory);
- void setLeftJustified(const QT_STATE_CHANGED_T _leftJustified);
- void setMasterVolume(const int _masterVolume);
- void setCardInfoViewMode(const int _viewMode);
- void setHighlightWords(const QString &_highlightWords);
- void setGameDescription(const QString _gameDescription);
- void setMaxPlayers(const int _maxPlayers);
- void setGameTypes(const QString _gameTypes);
- void setOnlyBuddies(const bool _onlyBuddies);
- void setOnlyRegistered(const bool _onlyRegistered);
- void setSpectatorsAllowed(const bool _spectatorsAllowed);
- void setSpectatorsNeedPassword(const bool _spectatorsNeedPassword);
- void setSpectatorsCanTalk(const bool _spectatorsCanTalk);
- void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
- void setCreateGameAsSpectator(const bool _createGameAsSpectator);
- void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
- void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
- void setRememberGameSettings(const bool _rememberGameSettings);
- void setLocalGameRememberSettings(bool value);
- void setLocalGameMaxPlayers(int value);
- void setLocalGameStartingLifeTotal(int value);
- void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
- void setStartupCardUpdateCheckPromptForUpdate(bool value);
- void setStartupCardUpdateCheckAlwaysUpdate(bool value);
- void setCardUpdateCheckInterval(int value);
- void setLastCardUpdateCheck(QDate value);
- void setAlwaysEnableNewSets(bool value);
- void setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate);
- void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
- void setUpdateReleaseChannelIndex(int value);
- void setMaxFontSize(int _max);
- void setRoundCardCorners(bool _roundCardCorners);
- void setShowDragSelectionCount(QT_STATE_CHANGED_T _showDragSelectionCount);
- void setShowTotalSelectionCount(QT_STATE_CHANGED_T _showTotalSelectionCount);
- void setShowSubtypeSelectionTally(QT_STATE_CHANGED_T _showSubtypeSelectionTally);
};
#endif
diff --git a/cockatrice/src/client/settings/card_counter_settings.cpp b/cockatrice/src/client/settings/card_counter_settings.cpp
index 662ae0c7d..d4030c174 100644
--- a/cockatrice/src/client/settings/card_counter_settings.cpp
+++ b/cockatrice/src/client/settings/card_counter_settings.cpp
@@ -5,7 +5,7 @@
#include
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
- : SettingsManager(settingsPath + "global.ini", "cards", "counters", parent)
+ : SettingsManager(settingsPath + "card_counters.ini", "cards", "counters", parent)
{
}
diff --git a/cockatrice/src/client/settings/shortcuts_settings.h b/cockatrice/src/client/settings/shortcuts_settings.h
index 95155b8d1..f4ebc204e 100644
--- a/cockatrice/src/client/settings/shortcuts_settings.h
+++ b/cockatrice/src/client/settings/shortcuts_settings.h
@@ -786,6 +786,10 @@ private:
ShortcutGroup::Tabs)},
{"Tabs/aTabLogs",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Logs"), parseSequenceString(""), ShortcutGroup::Tabs)},
+ {"Tabs/aTabReport",
+ ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Report Queue"), parseSequenceString(""), ShortcutGroup::Tabs)},
+ {"Tabs/aTabModeration",
+ ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Moderation"), parseSequenceString(""), ShortcutGroup::Tabs)},
};
};
diff --git a/cockatrice/src/client/sound_engine.cpp b/cockatrice/src/client/sound_engine.cpp
index e592b5ea0..18de2264d 100644
--- a/cockatrice/src/client/sound_engine.cpp
+++ b/cockatrice/src/client/sound_engine.cpp
@@ -2,12 +2,11 @@
#include "settings/cache_settings.h"
+#include
+#include
#include
#include
-
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
-#include
-#endif
+#include
#define DEFAULT_THEME_NAME "Default"
#define TEST_SOUND_FILENAME "player_join"
@@ -15,8 +14,10 @@
SoundEngine::SoundEngine(QObject *parent) : QObject(parent), audioOutput(nullptr), player(nullptr)
{
ensureThemeDirectoryExists();
- connect(&SettingsCache::instance(), &SettingsCache::soundThemeChanged, this, &SoundEngine::themeChangedSlot);
- connect(&SettingsCache::instance(), &SettingsCache::soundEnabledChanged, this, &SoundEngine::soundEnabledChanged);
+ connect(&SettingsCache::instance().sound(), &SoundSettings::soundThemeChanged, this,
+ &SoundEngine::themeChangedSlot);
+ connect(&SettingsCache::instance().sound(), &SoundSettings::soundEnabledChanged, this,
+ &SoundEngine::soundEnabledChanged);
soundEnabledChanged();
themeChangedSlot();
@@ -36,14 +37,12 @@ SoundEngine::~SoundEngine()
void SoundEngine::soundEnabledChanged()
{
- if (SettingsCache::instance().getSoundEnabled()) {
+ if (SettingsCache::instance().sound().getSoundEnabled()) {
qCInfo(SoundEngineLog) << "SoundEngine: enabling sound with" << audioData.size() << "sounds";
if (!player) {
player = new QMediaPlayer;
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
audioOutput = new QAudioOutput(player);
player->setAudioOutput(audioOutput);
-#endif
}
} else {
qCInfo(SoundEngineLog) << "SoundEngine: disabling sound";
@@ -70,14 +69,9 @@ void SoundEngine::playSound(const QString &fileName)
}
player->stop();
- int volumeSliderValue = SettingsCache::instance().getMasterVolume();
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+ int volumeSliderValue = SettingsCache::instance().sound().getMasterVolume();
player->audioOutput()->setVolume(qreal(volumeSliderValue) / 100);
player->setSource(QUrl::fromLocalFile(audioData[fileName]));
-#else
- player->setVolume(volumeSliderValue);
- player->setMedia(QUrl::fromLocalFile(audioData[fileName]));
-#endif
player->play();
}
@@ -88,10 +82,10 @@ void SoundEngine::testSound()
void SoundEngine::ensureThemeDirectoryExists()
{
- if (SettingsCache::instance().getSoundThemeName().isEmpty() ||
- !getAvailableThemes().contains(SettingsCache::instance().getSoundThemeName())) {
+ if (SettingsCache::instance().sound().getSoundThemeName().isEmpty() ||
+ !getAvailableThemes().contains(SettingsCache::instance().sound().getSoundThemeName())) {
qCInfo(SoundEngineLog) << "Sounds theme name not set, setting default value";
- SettingsCache::instance().setSoundThemeName(DEFAULT_THEME_NAME);
+ SettingsCache::instance().sound().setSoundThemeName(DEFAULT_THEME_NAME);
}
}
@@ -132,7 +126,7 @@ QStringMap &SoundEngine::getAvailableThemes()
void SoundEngine::themeChangedSlot()
{
- QString themeName = SettingsCache::instance().getSoundThemeName();
+ QString themeName = SettingsCache::instance().sound().getSoundThemeName();
qCInfo(SoundEngineLog) << "Sound theme changed:" << themeName;
QDir dir = getAvailableThemes().value(themeName);
diff --git a/cockatrice/src/client/url_scheme_event_filter.h b/cockatrice/src/client/url_scheme_event_filter.h
new file mode 100644
index 000000000..9e96502ca
--- /dev/null
+++ b/cockatrice/src/client/url_scheme_event_filter.h
@@ -0,0 +1,69 @@
+#ifndef COCKATRICE_URL_SCHEME_EVENT_FILTER_H
+#define COCKATRICE_URL_SCHEME_EVENT_FILTER_H
+
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * @brief Event filter that catches QFileOpenEvent URLs matching a scheme and
+ * re-emits them as urlReceived().
+ *
+ * On macOS, when the application is registered as a URL scheme handler, the
+ * OS delivers incoming URLs via QFileOpenEvent on the QApplication object.
+ * Install this filter on QApplication to intercept them:
+ *
+ * @code
+ * UrlSchemeEventFilter filter(QStringList{QStringLiteral("cockatrice")});
+ * QObject::connect(&filter, &UrlSchemeEventFilter::urlReceived,
+ * &mainWindow, &MainWindow::handleUrl);
+ * app.installEventFilter(&filter);
+ * @endcode
+ *
+ * Note: the strings are compared against QUrl::scheme(), so they must be
+ * written without the "://" suffix (e.g. "cockatrice", not "cockatrice://").
+ */
+class UrlSchemeEventFilter : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit UrlSchemeEventFilter(const QStringList &schemes, QObject *parent = nullptr)
+ : QObject(parent), prefixes(schemes)
+ {
+ }
+
+signals:
+ void urlReceived(const QString &url);
+
+public:
+ bool eventFilter(QObject *watched, QEvent *event) override
+ {
+ if (event->type() == QEvent::FileOpen) {
+ auto *fileEvent = static_cast(event);
+
+ const QUrl url = fileEvent->url();
+
+ for (const auto &prefix : prefixes) {
+ if (url.scheme() == prefix) {
+ emit urlReceived(url.toString());
+ return true;
+ }
+ }
+
+ if (url.isLocalFile()) {
+ emit urlReceived(url.toLocalFile());
+ return true;
+ }
+ }
+
+ return QObject::eventFilter(watched, event);
+ }
+
+private:
+ QStringList prefixes;
+};
+
+#endif // COCKATRICE_URL_SCHEME_EVENT_FILTER_H
diff --git a/cockatrice/src/database/interface/settings_card_database_path_provider.h b/cockatrice/src/database/interface/settings_card_database_path_provider.h
new file mode 100644
index 000000000..1c7d02460
--- /dev/null
+++ b/cockatrice/src/database/interface/settings_card_database_path_provider.h
@@ -0,0 +1,41 @@
+#ifndef SETTINGS_CARD_DATABASE_PATH_PROVIDER_H
+#define SETTINGS_CARD_DATABASE_PATH_PROVIDER_H
+
+#include "../../client/settings/cache_settings.h"
+
+#include
+#include
+
+class SettingsCardDatabasePathProvider : public ICardDatabasePathProvider
+{
+ Q_OBJECT
+
+public:
+ explicit SettingsCardDatabasePathProvider(QObject *parent = nullptr) : ICardDatabasePathProvider(parent)
+ {
+ connect(&SettingsCache::instance().paths(), &PathsSettings::cardDatabasePathChanged, this,
+ &ICardDatabasePathProvider::cardDatabasePathChanged);
+ }
+
+ [[nodiscard]] QString getCardDatabasePath() const override
+ {
+ return SettingsCache::instance().paths().getCardDatabasePath();
+ }
+
+ [[nodiscard]] QString getCustomCardDatabasePath() const override
+ {
+ return SettingsCache::instance().paths().getCustomCardDatabasePath();
+ }
+
+ [[nodiscard]] QString getTokenDatabasePath() const override
+ {
+ return SettingsCache::instance().paths().getTokenDatabasePath();
+ }
+
+ [[nodiscard]] virtual QString getSpoilerCardDatabasePath() const override
+ {
+ return SettingsCache::instance().paths().getSpoilerCardDatabasePath();
+ }
+};
+
+#endif // SETTINGS_CARD_DATABASE_PATH_PROVIDER_H
diff --git a/cockatrice/src/database/interface/settings_card_preference_provider.h b/cockatrice/src/database/interface/settings_card_preference_provider.h
index 6c31b9d6d..64502e3a7 100644
--- a/cockatrice/src/database/interface/settings_card_preference_provider.h
+++ b/cockatrice/src/database/interface/settings_card_preference_provider.h
@@ -3,6 +3,8 @@
#include "../../client/settings/cache_settings.h"
#include
+#include
+#include
class SettingsCardPreferenceProvider : public ICardPreferenceProvider
{
@@ -14,7 +16,7 @@ public:
[[nodiscard]] bool getIncludeRebalancedCards() const override
{
- return SettingsCache::instance().getIncludeRebalancedCards();
+ return SettingsCache::instance().cardsDisplay().getIncludeRebalancedCards();
}
};
diff --git a/cockatrice/src/filters/deck_filter_string.cpp b/cockatrice/src/filters/deck_filter_string.cpp
index dd873cfa5..4abb8210c 100644
--- a/cockatrice/src/filters/deck_filter_string.cpp
+++ b/cockatrice/src/filters/deck_filter_string.cpp
@@ -52,18 +52,14 @@ static void setupParserRules()
search["Start"] = passthru;
search["QueryPartList"] = [](const peg::SemanticValues &sv) -> DeckFilter {
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) {
- auto matchesFilter = [&deck, &info](const std::any &query) {
- return std::any_cast(query)(deck, info);
- };
+ return [=](const DeckSearchData &data) {
+ auto matchesFilter = [&data](const std::any &query) { return std::any_cast(query)(data); };
return std::all_of(sv.begin(), sv.end(), matchesFilter);
};
};
search["ComplexQueryPart"] = [](const peg::SemanticValues &sv) -> DeckFilter {
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) {
- auto matchesFilter = [&deck, &info](const std::any &query) {
- return std::any_cast(query)(deck, info);
- };
+ return [=](const DeckSearchData &data) {
+ auto matchesFilter = [&data](const std::any &query) { return std::any_cast(query)(data); };
return std::any_of(sv.begin(), sv.end(), matchesFilter);
};
};
@@ -71,9 +67,7 @@ static void setupParserRules()
search["QueryPart"] = passthru;
search["NotQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
const auto dependent = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) -> bool {
- return !dependent(deck, info);
- };
+ return [=](const DeckSearchData &data) -> bool { return !dependent(data); };
};
search["String"] = [](const peg::SemanticValues &sv) -> QString {
@@ -125,9 +119,9 @@ static void setupParserRules()
auto cardFilter = FilterString(std::any_cast(sv[0]));
auto numberMatcher = sv.size() > 1 ? std::any_cast(sv[1]) : [](int count) { return count > 0; };
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
+ return [=](const DeckSearchData &data) -> bool {
int count = 0;
- auto cardNodes = deck->deckLoader->getDeck().deckList.getCardNodes();
+ auto cardNodes = data.deck->deckList.getCardNodes();
for (auto node : cardNodes) {
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
@@ -146,53 +140,49 @@ static void setupParserRules()
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto name = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
- return deck->deckLoader->getDeck().deckList.getName().contains(name, Qt::CaseInsensitive);
+ return [=](const DeckSearchData &data) {
+ return data.deck->deckList.getName().contains(name, Qt::CaseInsensitive);
};
};
search["FileNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto name = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
- auto filename = QFileInfo(deck->filePath).fileName();
+ return [=](const DeckSearchData &data) {
+ auto filename = QFileInfo(data.filePath).fileName();
return filename.contains(name, Qt::CaseInsensitive);
};
};
search["PathQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto name = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *, const ExtraDeckSearchInfo &info) {
- return info.relativeFilePath.contains(name, Qt::CaseInsensitive);
- };
+ return [=](const DeckSearchData &data) { return data.relativeFilePath.contains(name, Qt::CaseInsensitive); };
};
search["FormatQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto format = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
- auto gameFormat = deck->deckLoader->getDeck().deckList.getGameFormat();
+ return [=](const DeckSearchData &data) {
+ auto gameFormat = data.deck->deckList.getGameFormat();
return QString::compare(format, gameFormat, Qt::CaseInsensitive) == 0;
};
};
search["CommentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto value = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
- auto comments = deck->deckLoader->getDeck().deckList.getComments();
+ return [=](const DeckSearchData &data) {
+ auto comments = data.deck->deckList.getComments();
return comments.contains(value, Qt::CaseInsensitive);
};
};
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
auto name = std::any_cast(sv[0]);
- return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
- return deck->getDisplayName().contains(name, Qt::CaseInsensitive);
- };
+ return [=](const DeckSearchData &data) { return data.displayName.contains(name, Qt::CaseInsensitive); };
};
}
DeckFilterString::DeckFilterString()
{
- filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; };
+ filter = [](const DeckSearchData &) { return false; };
_error = "Not initialized";
}
@@ -205,7 +195,7 @@ DeckFilterString::DeckFilterString(const QString &expr)
_error = QString();
if (ba.isEmpty()) {
- filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return true; };
+ filter = [](const DeckSearchData &) { return true; };
return;
}
@@ -215,6 +205,6 @@ DeckFilterString::DeckFilterString(const QString &expr)
if (!search.parse(ba.data(), filter)) {
qCInfo(DeckFilterStringLog).nospace() << "DeckFilterString error for " << expr << "; " << qPrintable(_error);
- filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; };
+ filter = [](const DeckSearchData &) { return false; };
}
-}
\ No newline at end of file
+}
diff --git a/cockatrice/src/filters/deck_filter_string.h b/cockatrice/src/filters/deck_filter_string.h
index 916b629ee..90a6a17eb 100644
--- a/cockatrice/src/filters/deck_filter_string.h
+++ b/cockatrice/src/filters/deck_filter_string.h
@@ -7,7 +7,7 @@
#ifndef DECK_FILTER_STRING_H
#define DECK_FILTER_STRING_H
-#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h"
+#include "../interface/deck_loader/loaded_deck.h"
#include
#include
@@ -16,26 +16,29 @@
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
/**
- * Extra info relevant to filtering that isn't present in the DeckPreviewWidget
+ * The data a deck search expression is evaluated against.
+ *
+ * This is a data view rather than a widget pointer, so the same filter
+ * expression can be evaluated against a model or a live widget.
*/
-struct ExtraDeckSearchInfo
+struct DeckSearchData
{
- /**
- * The relative filepath starting from the deck folder
- */
- QString relativeFilePath;
+ const LoadedDeck *deck = nullptr; ///< The loaded deck. Must not be null.
+ QString filePath; ///< Absolute path of the deck file.
+ QString displayName; ///< Deck name, or the file name if the deck has no name.
+ QString relativeFilePath; ///< File path relative to the deck folder.
};
-typedef std::function DeckFilter;
+typedef std::function DeckFilter;
class DeckFilterString
{
public:
DeckFilterString();
explicit DeckFilterString(const QString &expr);
- bool check(const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) const
+ bool check(const DeckSearchData &data) const
{
- return filter(deck, info);
+ return filter(data);
}
[[nodiscard]] bool valid() const
diff --git a/cockatrice/src/game/abstract_game.cpp b/cockatrice/src/game/abstract_game.cpp
index c20003ece..6aa2ab28f 100644
--- a/cockatrice/src/game/abstract_game.cpp
+++ b/cockatrice/src/game/abstract_game.cpp
@@ -31,7 +31,7 @@ AbstractClient *AbstractGame::getClientForPlayer(int playerId) const
}
}
-void AbstractGame::loadReplay(GameReplay *replay)
+void AbstractGame::loadReplay(const GameReplay *replay)
{
gameMetaInfo->setFromProto(replay->game_info());
gameMetaInfo->setSpectatorsOmniscient(true);
diff --git a/cockatrice/src/game/abstract_game.h b/cockatrice/src/game/abstract_game.h
index 5115ed5ca..fcf764492 100644
--- a/cockatrice/src/game/abstract_game.h
+++ b/cockatrice/src/game/abstract_game.h
@@ -53,7 +53,7 @@ public:
AbstractClient *getClientForPlayer(int playerId) const;
- void loadReplay(GameReplay *replay);
+ void loadReplay(const GameReplay *replay);
CardItem *getCard(int playerId, const QString &zoneName, int cardId) const;
diff --git a/cockatrice/src/game/game_event_handler.cpp b/cockatrice/src/game/game_event_handler.cpp
index 4a96eebdb..bc68d4d7c 100644
--- a/cockatrice/src/game/game_event_handler.cpp
+++ b/cockatrice/src/game/game_event_handler.cpp
@@ -229,7 +229,11 @@ void GameEventHandler::handleArrowDeletion(int creatorId, int arrowId)
void GameEventHandler::handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId)
{
- if (response.response_code() == Response::RespNameNotFound) {
+ // The server confirms the arrow no longer exists whether it deleted it itself
+ // (RespOk, followed by an Event_DeleteArrow broadcast) or never had it
+ // (RespNameNotFound). In both cases the local copy has to go. deleteArrow is
+ // a no-op if the arrow was already removed by the event broadcast.
+ if (response.response_code() == Response::RespOk || response.response_code() == Response::RespNameNotFound) {
emit arrowDeleted(creatorId, arrowId);
}
}
@@ -281,12 +285,19 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
emit playerJoined(prop);
}
player->processPlayerInfo(playerInfo);
+ // Extract playmat from player properties for opponent display
+ if (prop.has_playmat_params()) {
+ player->setPlaymatFromProperties(prop);
+ }
if (player->getPlayerInfo()->getLocal()) {
emit localPlayerDeckSelected(player, playerId, playerInfo);
} else {
if (!game->getGameMetaInfo()->proto().share_decklists_on_load()) {
continue;
}
+ if (!playerInfo.has_deck_list()) {
+ continue;
+ }
opponentDecksToDisplay.append(
qMakePair(playerId, qMakePair(playerName, QString::fromStdString(playerInfo.deck_list()))));
@@ -344,6 +355,11 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
const ServerInfo_PlayerProperties &prop = event.player_properties();
emit playerPropertiesChanged(prop, eventPlayerId);
+ // Update playmat from player properties
+ if (prop.has_playmat_params()) {
+ player->setPlaymatFromProperties(prop);
+ }
+
const auto contextType = static_cast(getPbExtension(context));
switch (contextType) {
case GameEventContext::READY_START: {
diff --git a/cockatrice/src/game/game_event_handler.h b/cockatrice/src/game/game_event_handler.h
index f47116949..99277abb7 100644
--- a/cockatrice/src/game/game_event_handler.h
+++ b/cockatrice/src/game/game_event_handler.h
@@ -1,8 +1,16 @@
/**
* @file game_event_handler.h
* @ingroup GameLogic
+ * @brief Game-level command sender and event dispatcher.
+ *
+ * GameEventHandler sends commands initiated by the local client to the server
+ * and processes incoming game-wide events. It bridges the networking layer
+ * (protobuf events received via AbstractClient) with the game model and UI
+ * (GameState, PlayerManager, logging, widgets).
+ *
+ * Player-scoped events are forwarded to PlayerEventHandler instances, while
+ * spectator and global game events are handled directly here.
*/
-//! \todo Document this file.
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
#define COCKATRICE_GAME_EVENT_HANDLER_H
@@ -15,92 +23,310 @@
#include
class AbstractClient;
-class Response;
+class AbstractGame;
+class CommandContainer;
+class GameCommand;
class GameEventContainer;
class GameEventContext;
-class GameCommand;
-class GameState;
-class MessageLogWidget;
-class CommandContainer;
-class Event_GameJoined;
+class PendingCommand;
+class PlayerLogic;
+class Response;
+
class Event_GameStateChanged;
class Event_PlayerPropertiesChanged;
class Event_Join;
class Event_Leave;
class Event_GameHostChanged;
class Event_GameClosed;
-class Event_GameStart;
class Event_SetActivePlayer;
class Event_SetActivePhase;
-class Event_Ping;
class Event_GameSay;
class Event_Kicked;
class Event_ReverseTurn;
-class AbstractGame;
-class PendingCommand;
-class PlayerLogic;
+class Event_Ping;
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
+/**
+ * @class GameEventHandler
+ * @brief Central dispatcher for game-wide commands and events.
+ *
+ * This class owns no game state itself. Instead, it:
+ * - Sends commands to the server on behalf of local players
+ * - Receives and dispatches server-side game events
+ * - Updates the game model indirectly via Player, GameState, and PlayerManager
+ * - Emits high-level signals for UI updates and logging
+ */
class GameEventHandler : public QObject
{
Q_OBJECT
private:
+ /** Pointer to the owning game instance. */
AbstractGame *game;
public:
+ /** @name Construction
+ * Lifecycle and ownership.
+ * @{
+ */
+
+ /**
+ * @brief Construct a GameEventHandler.
+ *
+ * The handler is owned by the AbstractGame instance and uses it to
+ * access the game state, players, and network clients.
+ *
+ * @param _game Owning game instance (also used as QObject parent).
+ */
explicit GameEventHandler(AbstractGame *_game);
+ /** @} */
+
+ /** @name Outgoing game commands
+ * Commands initiated locally and sent to the server.
+ *
+ * These methods construct and send protobuf commands corresponding
+ * to user actions in the UI.
+ * @{
+ */
+
+ /** @brief Request advancing the game to the next turn. */
void handleNextTurn();
+
+ /** @brief Request reversing the current turn order. */
void handleReverseTurn();
+ /** @brief Concede the game for the currently active local player. */
void handleActiveLocalPlayerConceded();
+
+ /** @brief Undo a previous concede for the active local player. */
void handleActiveLocalPlayerUnconceded();
+
+ /**
+ * @brief Set the active phase of the game.
+ *
+ * Typically triggered by the active player selecting a new phase.
+ *
+ * @param phase Phase identifier.
+ */
void handleActivePhaseChanged(int phase);
+
+ /** @brief Leave the current game session. */
void handleGameLeft();
+
+ /**
+ * @brief Send a chat message to all players and spectators.
+ *
+ * @param chatMessage Message text.
+ */
void handleChatMessageSent(const QString &chatMessage);
+
+ /**
+ * @brief Delete an existing arrow.
+ *
+ * @param arrowId Unique identifier of the arrow to delete.
+ */
void handleArrowDeletion(int creatorId, int arrowId);
void handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId);
+ /** @} */
+
+ /** @name Incoming event processing
+ * Entry points for server-sent events.
+ * @{
+ */
+
+ /**
+ * @brief Process a container of game events received from the server.
+ *
+ * This is the main dispatch function for incoming game events.
+ * Events are routed to spectator handlers, game-level handlers,
+ * or forwarded to PlayerEventHandler instances as appropriate.
+ *
+ * @param cont Game event container from the server.
+ * @param client Client that received the container.
+ * @param options Processing flags (e.g. silent, replay).
+ */
+ void
+ processGameEventContainer(const GameEventContainer &cont, AbstractClient *client, EventProcessingOptions options);
+
+ /** @} */
+
+ /** @name Command preparation helpers
+ * Internal helpers for building command containers.
+ * @{
+ */
+
+ /**
+ * @brief Wrap a single protobuf command in a PendingCommand.
+ *
+ * @param cmd Protobuf command message.
+ * @return Newly allocated PendingCommand (caller takes ownership).
+ */
+ PendingCommand *prepareGameCommand(const ::google::protobuf::Message &cmd);
+
+ /**
+ * @brief Wrap multiple protobuf commands in a single PendingCommand.
+ *
+ * Ownership of the messages in cmdList is transferred to the handler.
+ *
+ * @param cmdList List of protobuf command messages.
+ * @return Newly allocated PendingCommand.
+ */
+ PendingCommand *prepareGameCommand(const QList &cmdList);
+
+ /** @} */
+
+ /** @name Spectator event handlers
+ * Events originating from spectators.
+ * @{
+ */
+
+ /**
+ * @brief Handle a spectator chat message.
+ */
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
+
+ /**
+ * @brief Handle a spectator leaving the game.
+ */
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
+ /** @} */
+
+ /** @name Game state event handlers
+ * Events that affect global game state.
+ * @{
+ */
+
+ /**
+ * @brief Handle a full game state update from the server.
+ *
+ * Used during game startup, reconnection, and resynchronization.
+ */
void eventGameStateChanged(const Event_GameStateChanged &event, int eventPlayerId, const GameEventContext &context);
+
+ /**
+ * @brief Update card attachment relationships for all players.
+ *
+ * Called after a game state update to ensure attachments are resolved
+ * consistently across all zones.
+ */
void processCardAttachmentsForPlayers(const Event_GameStateChanged &event);
+
+ /** @brief Handle a change in game host. */
+ void eventGameHostChanged(const Event_GameHostChanged &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @brief Handle the game being closed by the server. */
+ void eventGameClosed(const Event_GameClosed &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @brief Handle a change of the active player. */
+ void eventSetActivePlayer(const Event_SetActivePlayer &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @brief Handle a change of the active phase. */
+ void eventSetActivePhase(const Event_SetActivePhase &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @brief Handle a turn reversal event. */
+ void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @brief Handle ping / latency updates. */
+ void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @} */
+
+ /** @name Player lifecycle and property handlers
+ * Events related to players joining, leaving, or changing state.
+ * @{
+ */
+
+ /**
+ * @brief Handle updates to a player's properties.
+ *
+ * Includes readiness, concede state, deck selection, sideboard lock,
+ * and connection state changes.
+ */
void eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &event,
int eventPlayerId,
const GameEventContext &context);
+
+ /** @brief Handle a player or spectator joining the game. */
void eventJoin(const Event_Join &event, int eventPlayerId, const GameEventContext &context);
+
+ /** @brief Handle a player leaving the game. */
void eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
- QString getLeaveReason(Event_Leave::LeaveReason reason);
+
+ /** @brief Handle the local player being kicked from the game. */
void eventKicked(const Event_Kicked &event, int eventPlayerId, const GameEventContext &context);
- void eventGameHostChanged(const Event_GameHostChanged &event, int eventPlayerId, const GameEventContext &context);
- void eventGameClosed(const Event_GameClosed &event, int eventPlayerId, const GameEventContext &context);
- void eventSetActivePlayer(const Event_SetActivePlayer &event, int eventPlayerId, const GameEventContext &context);
- void eventSetActivePhase(const Event_SetActivePhase &event, int eventPlayerId, const GameEventContext &context);
- void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
- void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext & /*context*/);
+ /**
+ * @brief Convert a leave reason enum to a human-readable string.
+ */
+ QString getLeaveReason(Event_Leave::LeaveReason reason);
- void commandFinished(const Response &response);
+ /** @} */
- void
- processGameEventContainer(const GameEventContainer &cont, AbstractClient *client, EventProcessingOptions options);
- PendingCommand *prepareGameCommand(const ::google::protobuf::Message &cmd);
- PendingCommand *prepareGameCommand(const QList &cmdList);
public slots:
+ /** @name Command dispatch slots
+ * Low-level command transmission.
+ * @{
+ */
+
+ /**
+ * @brief Send a prepared PendingCommand.
+ *
+ * @param pend Pending command to send.
+ * @param playerId Player whose client should send the command.
+ */
void sendGameCommand(PendingCommand *pend, int playerId = -1);
+
+ /**
+ * @brief Send a single protobuf command.
+ *
+ * @param command Protobuf command message.
+ * @param playerId Player whose client should send the command.
+ */
void sendGameCommand(const ::google::protobuf::Message &command, int playerId = -1);
+ /**
+ * @brief Called when a PendingCommand finishes execution.
+ *
+ * Used to detect server-side errors such as chat flood protection.
+ */
+ void commandFinished(const Response &response);
+
+ /** @} */
+
signals:
+ /** @name Core state signals
+ * @{
+ */
+
void emitUserEvent();
+ void containerProcessingStarted(GameEventContext context);
+ void containerProcessingDone();
+ void gameFlooded();
+ void setContextJudgeName(QString judgeName);
+
+ /** @} */
+
+ /** @name Player and spectator signals
+ * @{
+ */
+
void addPlayerToAutoCompleteList(QString playerName);
void localPlayerDeckSelected(PlayerLogic *localPlayer, int playerId, ServerInfo_Player playerInfo);
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
void remotePlayersDecksSelected(QVector>> opponentDecks);
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
void localPlayerReadyStateChanged(int playerId, bool ready);
+
+ /** @} */
+
+ /** @name Game flow signals
+ * @{
+ */
+
void gameStopped();
void gameClosed();
void playerPropertiesChanged(const ServerInfo_PlayerProperties &prop, int playerId);
@@ -109,11 +335,15 @@ signals:
void playerKicked();
void spectatorJoined(const ServerInfo_PlayerProperties &spectatorInfo);
void spectatorLeft(int leavingSpectatorId);
- void gameFlooded();
- void containerProcessingStarted(GameEventContext context);
- void setContextJudgeName(QString judgeName);
- void containerProcessingDone();
void arrowDeleted(int creatorId, int arrowId);
+
+ /** @} */
+
+ /** @name Logging signals
+ * Signals consumed by MessageLogWidget.
+ * @{
+ */
+
void logSpectatorSay(ServerInfo_User userInfo, QString message);
void logSpectatorLeave(QString name, QString reason);
void logGameStart();
@@ -132,6 +362,8 @@ signals:
void logActivePhaseChanged(int activePhase);
void logConcede(int playerId);
void logUnconcede(int playerId);
+
+ /** @} */
};
#endif // COCKATRICE_GAME_EVENT_HANDLER_H
diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp
index c9e8628f4..67c3295d6 100644
--- a/cockatrice/src/game/player/player_actions.cpp
+++ b/cockatrice/src/game/player/player_actions.cpp
@@ -27,8 +27,11 @@
#include
#include
#include
+#include
+#include
+#include
+#include
#include
-#include
#include
// milliseconds in between triggers of the move top cards until action
@@ -66,7 +69,7 @@ void PlayerActions::playCard(CardItem *card, bool faceDown)
const CardInfo &info = exactCard.getInfo();
int tableRow = info.getUiAttributes().tableRow;
- bool playToStack = SettingsCache::instance().getPlayToStack();
+ bool playToStack = SettingsCache::instance().userInterface().getPlayToStack();
QString currentZone = card->getZone()->getName();
if (!faceDown && currentZone == ZoneNames::STACK && tableRow == 3) {
cmd.set_target_zone(ZoneNames::GRAVE);
@@ -309,7 +312,7 @@ void PlayerActions::actDrawCard()
void PlayerActions::actRequestMulliganDialog()
{
- int startSize = SettingsCache::instance().getStartingHandSize();
+ int startSize = SettingsCache::instance().userInterface().getStartingHandSize();
int handSize = player->getHandZone()->getCards().size();
int deckSize = player->getDeckZone()->getCards().size() + handSize;
@@ -325,7 +328,7 @@ void PlayerActions::actMulligan(int number)
}
doMulligan(number);
- SettingsCache::instance().setStartingHandSize(number);
+ SettingsCache::instance().userInterface().setStartingHandSize(number);
}
void PlayerActions::actMulliganSameSize()
@@ -929,13 +932,13 @@ void PlayerActions::setLastTokenInfo(CardInfoPtr cardInfo)
return;
}
- lastTokenInfo = {.name = cardInfo->getName(),
- .color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(),
- .pt = cardInfo->getPowTough(),
- .annotation = SettingsCache::instance().getAnnotateTokens() ? cardInfo->getText() : "",
- .destroy = true,
- .providerId =
- SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
+ lastTokenInfo = {
+ .name = cardInfo->getName(),
+ .color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(),
+ .pt = cardInfo->getPowTough(),
+ .annotation = SettingsCache::instance().userInterface().getAnnotateTokens() ? cardInfo->getText() : "",
+ .destroy = true,
+ .providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
lastTokenTableRow = TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow);
@@ -1168,7 +1171,7 @@ void PlayerActions::createCard(const CardItem *sourceCard,
}
cmd.set_pt(cardInfo->getPowTough().toStdString());
- if (SettingsCache::instance().getAnnotateTokens()) {
+ if (SettingsCache::instance().userInterface().getAnnotateTokens()) {
cmd.set_annotation(cardInfo->getText().toStdString());
} else {
cmd.set_annotation("");
@@ -1351,11 +1354,7 @@ void PlayerActions::actSetPT(QList selectedCards, const QString &pt)
const auto oldpt = CardItem::parsePT(card->getPT());
int ptIter = 0;
for (const auto &_item : ptList) {
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (_item.typeId() == QMetaType::Type::Int) {
-#else
- if (_item.type() == QVariant::Int) {
-#endif
int oldItem = ptIter < oldpt.size() ? oldpt.at(ptIter).toInt() : 0;
newpt += '/' + QString::number(oldItem + _item.toInt());
} else {
@@ -1530,12 +1529,15 @@ void PlayerActions::offsetCardCounter(QList selectedCards, int count
QList commandList;
for (auto card : selectedCards) {
int oldValue = card->getCounters().value(counterId, 0);
- int newValue = oldValue + offset;
- // Early exit optimization: server enforces [0, MAX_COUNTERS_ON_CARD].
- // Compare clamped value to allow recovery from invalid states.
- int clampedValue = qBound(0, newValue, MAX_COUNTERS_ON_CARD);
- if (clampedValue != oldValue) {
+ // Overflow-safe clamp to the server-enforced range [0, MAX_COUNTER_VALUE];
+ // a result differing from oldValue also corrects an out-of-range cached value.
+ // Callers only ever pass offset == ±1 (actAddCardCounter / actRemoveCardCounter).
+ // This client-side clamp is a defense-in-depth UX check, consistent with
+ // actSetCardCounter and actIncrementAllCardCounters; the server remains the
+ // authoritative enforcer of the bounds.
+ int newValue = addClamped(oldValue, offset, 0, MAX_COUNTER_VALUE);
+ if (newValue != oldValue) {
auto *cmd = new Command_SetCardCounter;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
@@ -1568,7 +1570,7 @@ void PlayerActions::actSetCardCounter(QList selectedCards, int count
Expression exp(oldValue);
double parsed = exp.parse(counterValue);
// Clamp in double precision first to avoid UB, then cast
- int number = static_cast(qBound(0.0, parsed, static_cast(MAX_COUNTERS_ON_CARD)));
+ int number = static_cast(qBound(0.0, parsed, static_cast(MAX_COUNTER_VALUE)));
auto *cmd = new Command_SetCardCounter;
cmd->set_zone(card->getZone()->getName().toStdString());
@@ -1598,7 +1600,7 @@ void PlayerActions::actIncrementAllCardCounters(QList cardsToUpdate)
counterIterator.next();
int counterId = counterIterator.key();
int currentValue = counterIterator.value();
- if (currentValue >= MAX_COUNTERS_ON_CARD) {
+ if (currentValue >= MAX_COUNTER_VALUE) {
continue;
}
diff --git a/cockatrice/src/game/player/player_event_handler.h b/cockatrice/src/game/player/player_event_handler.h
index cfd82933f..48ad85e88 100644
--- a/cockatrice/src/game/player/player_event_handler.h
+++ b/cockatrice/src/game/player/player_event_handler.h
@@ -1,11 +1,24 @@
/**
* @file player_event_handler.h
* @ingroup GameLogicPlayers
+ * @brief Player-scoped game event handler.
+ *
+ * PlayerEventHandler applies game events that affect a single Player’s
+ * board state, zones, cards, counters, arrows, and related UI/log output.
+ *
+ * It is invoked by GameEventHandler after basic routing and validation.
+ * Each instance is bound 1:1 to a Player and must never mutate state
+ * belonging to other players except where explicitly required by events
+ * (e.g. moving cards between players, attaching cards, arrows).
+ *
+ * This class is intentionally stateful and tightly coupled to Player,
+ * PlayerActions, and the board/zones implementation. It performs both
+ * model mutation and UI-side bookkeeping (zone views, arrows, menus).
*/
-//! \todo Document this file.
#ifndef COCKATRICE_PLAYER_EVENT_HANDLER_H
#define COCKATRICE_PLAYER_EVENT_HANDLER_H
+
#include "event_processing_options.h"
#include
@@ -16,6 +29,7 @@
class CardItem;
class CardZoneLogic;
class PlayerLogic;
+
class Event_AttachCard;
class Event_ChangeZoneProperties;
class Event_CreateArrow;
@@ -37,11 +51,176 @@ class Event_SetCounter;
class Event_Shuffle;
class Event_GameLogNotice;
+/**
+ * @class PlayerEventHandler
+ * @brief Applies player-specific game events and emits corresponding log signals.
+ *
+ * Design notes:
+ * - All event handlers assume events are authoritative and already validated
+ * by the server.
+ * - Most handlers mutate both logical state (CardItem, CardZoneLogic, counters)
+ * and visual/UI state (views, arrows, menus).
+ * - Logging signals are emitted *after* or *during* state mutation, depending
+ * on whether later mutations would invalidate log data.
+ */
class PlayerEventHandler : public QObject
{
-
Q_OBJECT
+
+public:
+ /**
+ * @brief Construct a PlayerEventHandler bound to a Player.
+ * @param player Owning player instance.
+ */
+ explicit PlayerEventHandler(PlayerLogic *player);
+
+ /** @name Event dispatch
+ * @{
+ */
+
+ /**
+ * @brief Dispatch a generic GameEvent to the appropriate handler.
+ *
+ * This is the single entry point used by GameEventHandler. It extracts
+ * the correct protobuf extension and forwards the event to a typed
+ * handler method.
+ *
+ * @param type Game event type enum.
+ * @param event Generic protobuf container.
+ * @param context Additional context (undo, judge, etc.).
+ * @param options Processing options (UI suppression, reveal behavior).
+ */
+ void processGameEvent(GameEvent::GameEventType type,
+ const GameEvent &event,
+ const GameEventContext &context,
+ EventProcessingOptions options);
+
+ /** @} */
+
+ /** @name Chat and randomization events
+ * @{
+ */
+
+ /// Handle in-game chat messages from this player.
+ void eventGameSay(const Event_GameSay &event);
+
+ /// Handle zone shuffle events (typically libraries).
+ void eventShuffle(const Event_Shuffle &event);
+
+ /// Handle die roll events.
+ void eventRollDie(const Event_RollDie &event);
+
+ /** @} */
+
+ /** @name Arrow and targeting events
+ * @{
+ */
+
+ /// Create a visual arrow between cards or players.
+ void eventCreateArrow(const Event_CreateArrow &event);
+
+ /// Delete an existing arrow.
+ void eventDeleteArrow(const Event_DeleteArrow &event);
+
+ /** @} */
+
+ /** @name Token and card creation
+ * @{
+ */
+
+ /// Create a token card in a target zone.
+ void eventCreateToken(const Event_CreateToken &event);
+
+ /** @} */
+
+ /** @name Card attribute and counter updates
+ * @{
+ */
+
+ /**
+ * @brief Set a card attribute (tapped, PT, annotation, etc.).
+ *
+ * May apply to a single card or all cards in a zone if no card ID
+ * is provided by the event.
+ */
+ void
+ eventSetCardAttr(const Event_SetCardAttr &event, const GameEventContext &context, EventProcessingOptions options);
+
+ /// Update a counter attached to a card.
+ void eventSetCardCounter(const Event_SetCardCounter &event);
+
+ /// Create a player-level counter.
+ void eventCreateCounter(const Event_CreateCounter &event);
+
+ /// Set a player-level counter value.
+ void eventSetCounter(const Event_SetCounter &event);
+
+ /// Delete a player-level counter.
+ void eventDelCounter(const Event_DelCounter &event);
+
+ /** @} */
+
+ /** @name Zone-level operations
+ * @{
+ */
+
+ /// Log a zone dump (e.g. reveal graveyard/library contents).
+ void eventDumpZone(const Event_DumpZone &event);
+
+ /**
+ * @brief Move a card between zones and/or players.
+ *
+ * This is one of the most complex handlers:
+ * - Removes the card from the start zone
+ * - Updates card identity and ownership if needed
+ * - Handles attachments and arrows
+ * - Emits appropriate move or undo-draw logs
+ * - Inserts the card into the target zone
+ */
+ void eventMoveCard(const Event_MoveCard &event, const GameEventContext &context);
+
+ /// Flip a card face up or face down.
+ void eventFlipCard(const Event_FlipCard &event);
+
+ /// Destroy a card and clean up attachments.
+ void eventDestroyCard(const Event_DestroyCard &event);
+
+ /// Attach or detach a card to/from another card.
+ void eventAttachCard(const Event_AttachCard &event);
+
+ /** @} */
+
+ /** @name Draw and reveal operations
+ * @{
+ */
+
+ /// Draw one or more cards from the deck.
+ void eventDrawCards(const Event_DrawCards &event);
+
+ /**
+ * @brief Reveal cards from a zone.
+ *
+ * Handles peeking, in-place top-card reveals, full reveal windows,
+ * and write-access granting.
+ */
+ void eventRevealCards(const Event_RevealCards &event, EventProcessingOptions options);
+
+ /** @} */
+
+ /** @name Zone configuration
+ * @{
+ */
+
+ /// Update zone visibility and reveal behavior.
+ void eventChangeZoneProperties(const Event_ChangeZoneProperties &event);
+
+ /** @} */
+
+ void eventGameLogNotice(const Event_GameLogNotice &event);
signals:
+ /** @name Logging signals
+ * @{
+ */
void logSay(PlayerLogic *player, QString message);
void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end);
void logRollDie(PlayerLogic *player, int sides, const QList &rolls);
@@ -82,40 +261,13 @@ signals:
bool isLentToAnotherPlayer = false);
void logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
+ /** @} */
+
void cardZoneChanged(CardItem *card, bool sameZone);
void requestCardMenuUpdate(const CardItem *card);
-public:
- PlayerEventHandler(PlayerLogic *player);
-
- void processGameEvent(GameEvent::GameEventType type,
- const GameEvent &event,
- const GameEventContext &context,
- EventProcessingOptions options);
-
- void eventGameSay(const Event_GameSay &event);
- void eventShuffle(const Event_Shuffle &event);
- void eventRollDie(const Event_RollDie &event);
- void eventCreateArrow(const Event_CreateArrow &event);
- void eventDeleteArrow(const Event_DeleteArrow &event);
- void eventCreateToken(const Event_CreateToken &event);
- void
- eventSetCardAttr(const Event_SetCardAttr &event, const GameEventContext &context, EventProcessingOptions options);
- void eventSetCardCounter(const Event_SetCardCounter &event);
- void eventCreateCounter(const Event_CreateCounter &event);
- void eventSetCounter(const Event_SetCounter &event);
- void eventDelCounter(const Event_DelCounter &event);
- void eventDumpZone(const Event_DumpZone &event);
- void eventMoveCard(const Event_MoveCard &event, const GameEventContext &context);
- void eventFlipCard(const Event_FlipCard &event);
- void eventDestroyCard(const Event_DestroyCard &event);
- void eventAttachCard(const Event_AttachCard &event);
- void eventDrawCards(const Event_DrawCards &event);
- void eventRevealCards(const Event_RevealCards &event, EventProcessingOptions options);
- void eventChangeZoneProperties(const Event_ChangeZoneProperties &event);
- void eventGameLogNotice(const Event_GameLogNotice &event);
-
private:
+ /** Owning player instance. */
PlayerLogic *player;
void setCardAttrHelper(const GameEventContext &context,
diff --git a/cockatrice/src/game/player/player_logic.cpp b/cockatrice/src/game/player/player_logic.cpp
index 485e2fc5c..45ba09aac 100644
--- a/cockatrice/src/game/player/player_logic.cpp
+++ b/cockatrice/src/game/player/player_logic.cpp
@@ -250,6 +250,22 @@ void PlayerLogic::setDeck(const DeckList &_deck)
emit deckChanged();
}
+void PlayerLogic::setPlaymatFromProperties(const ServerInfo_PlayerProperties &props)
+{
+ if (props.has_playmat_params() && !props.playmat_params().card_name().empty()) {
+ const auto &pp = props.playmat_params();
+ remotePlaymatCard = {QString::fromStdString(pp.card_name()), QString::fromStdString(pp.card_provider_id())};
+ remotePlaymatParams = {qBound(0.0, pp.margin_pct_l(), 0.95), qBound(0.0, pp.margin_pct_r(), 0.95),
+ qBound(0.0, pp.vertical_offset(), 1.0), qBound(0.1, pp.zoom(), 4.0)};
+ hasRemotePlaymat = true;
+ } else {
+ remotePlaymatCard = CardRef{};
+ remotePlaymatParams = PlaymatParams{};
+ hasRemotePlaymat = false;
+ }
+ emit playmatChanged();
+}
+
CounterState *PlayerLogic::addCounter(const ServerInfo_Counter &counter)
{
return addCounter(counter.id(), QString::fromStdString(counter.name()),
diff --git a/cockatrice/src/game/player/player_logic.h b/cockatrice/src/game/player/player_logic.h
index a89cb6eed..6923b3afe 100644
--- a/cockatrice/src/game/player/player_logic.h
+++ b/cockatrice/src/game/player/player_logic.h
@@ -17,6 +17,7 @@
#include "../zones/table_zone_logic.h"
#include "player_event_handler.h"
#include "player_info.h"
+#include "player_manager.h"
#include
#include
@@ -72,6 +73,8 @@ signals:
const QList &cardList,
bool withWritePermission);
void deckChanged();
+ /** @brief Emitted when the remote playmat (card/params) is updated from player properties. */
+ void playmatChanged();
void newCardAdded(AbstractCardItem *card);
void requestCardMenuUpdate(const CardItem *card);
void counterAdded(CounterState *state);
@@ -226,6 +229,20 @@ public:
void setZoneId(int _zoneId);
+ void setPlaymatFromProperties(const ServerInfo_PlayerProperties &props);
+ const CardRef &getRemotePlaymatCard() const
+ {
+ return remotePlaymatCard;
+ }
+ const PlaymatParams &getRemotePlaymatParams() const
+ {
+ return remotePlaymatParams;
+ }
+ bool getHasRemotePlaymat() const
+ {
+ return hasRemotePlaymat;
+ }
+
private:
AbstractGame *game;
PlayerInfo *playerInfo;
@@ -243,6 +260,11 @@ private:
bool dialogSemaphore;
QList cardsToDelete;
+
+ // Playmat from player properties (for opponent display)
+ CardRef remotePlaymatCard;
+ PlaymatParams remotePlaymatParams;
+ bool hasRemotePlaymat = false;
};
class AnnotationDialog : public QInputDialog
diff --git a/cockatrice/src/game/replay.cpp b/cockatrice/src/game/replay.cpp
index 69f9d8b20..dcf3e9b9b 100644
--- a/cockatrice/src/game/replay.cpp
+++ b/cockatrice/src/game/replay.cpp
@@ -2,7 +2,7 @@
#include "../interface/widgets/tabs/tab_game.h"
-Replay::Replay(QObject *_parent, GameReplay *_replay, bool isLocalGame) : AbstractGame(_parent)
+Replay::Replay(QObject *_parent, const GameReplay *_replay, bool isLocalGame) : AbstractGame(_parent)
{
gameState = new GameState(this, 0, -1, isLocalGame, {}, false, false, -1, false);
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
diff --git a/cockatrice/src/game/replay.h b/cockatrice/src/game/replay.h
index ecb3a10d0..1c269b273 100644
--- a/cockatrice/src/game/replay.h
+++ b/cockatrice/src/game/replay.h
@@ -15,7 +15,7 @@ class Replay : public AbstractGame
Q_OBJECT
public:
- explicit Replay(QObject *_parent, GameReplay *_replay, bool isLocalGame);
+ explicit Replay(QObject *_parent, const GameReplay *_replay, bool isLocalGame);
};
#endif // COCKATRICE_REPLAY_H
diff --git a/cockatrice/src/game/selection_subtype_tally.h b/cockatrice/src/game/selection_subtype_tally.h
deleted file mode 100644
index 9038653f6..000000000
--- a/cockatrice/src/game/selection_subtype_tally.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SELECTION_SUBTYPE_TALLY_H
-#define SELECTION_SUBTYPE_TALLY_H
-
-#include
-#include
-
-class CardItem;
-
-/** @brief A single subtype (e.g., "Goblin", "Warrior") with its occurrence count. */
-struct SubtypeEntry
-{
- QString name; ///< The subtype name
- int count; ///< Number of selected cards with this subtype
-
- bool operator==(const SubtypeEntry &other) const
- {
- return name == other.name && count == other.count;
- }
-};
-
-/**
- * @brief Extracts and tallies subtypes from selected cards.
- */
-namespace SelectionSubtypeTally
-{
-/**
- * @brief Parses card type lines and counts each subtype occurrence.
- *
- * Skips face-down cards and cards without type info.
- * @param cards The list of selected card items to analyze.
- * @return Entries sorted by count ascending, then alphabetically.
- */
-QList countSubtypes(const QList &cards);
-} // namespace SelectionSubtypeTally
-
-#endif
diff --git a/cockatrice/src/game/zones/view_zone_logic.cpp b/cockatrice/src/game/zones/view_zone_logic.cpp
index 8782a1762..2ef04284a 100644
--- a/cockatrice/src/game/zones/view_zone_logic.cpp
+++ b/cockatrice/src/game/zones/view_zone_logic.cpp
@@ -3,6 +3,7 @@
#include "../../client/settings/cache_settings.h"
#include "../../game_graphics/board/card_item.h"
+#include
/**
* @param _player the player that the cards are revealed to.
* @param _origZone the zone the cards were revealed from.
@@ -57,7 +58,7 @@ bool ZoneViewZoneLogic::prepareAddCard(int x)
// autoclose check is done both here and in removeCard
- if (cards.isEmpty() && !doInsert && SettingsCache::instance().getCloseEmptyCardView()) {
+ if (cards.isEmpty() && !doInsert && SettingsCache::instance().userInterface().getCloseEmptyCardView()) {
emit closeView();
}
@@ -144,7 +145,7 @@ void ZoneViewZoneLogic::removeCard(int position, bool toNewZone)
// card gets dragged within the view.
// Another autoclose check is done in prepareAddCard so that the view autocloses if the last card was moved to an
// unrevealed portion of the same zone.
- if (cards.isEmpty() && SettingsCache::instance().getCloseEmptyCardView() && toNewZone) {
+ if (cards.isEmpty() && SettingsCache::instance().userInterface().getCloseEmptyCardView() && toNewZone) {
emit closeView();
return;
}
diff --git a/cockatrice/src/game_graphics/animated_item.h b/cockatrice/src/game_graphics/animated_item.h
new file mode 100644
index 000000000..700e0f62d
--- /dev/null
+++ b/cockatrice/src/game_graphics/animated_item.h
@@ -0,0 +1,26 @@
+#ifndef ANIMATED_ITEM_H
+#define ANIMATED_ITEM_H
+
+/**
+ * @file animated_item.h
+ * @ingroup GameGraphics
+ * @brief Interface for scene items driven by GameScene's shared animation timer.
+ *
+ * Items that want per-tick animation while a single QBasicTimer runs (instead of
+ * owning their own QTimer) implement this interface and register with the scene
+ * via GameScene::registerAnimationItem.
+ */
+
+class IAnimatedItem
+{
+public:
+ virtual ~IAnimatedItem() = default;
+
+ /**
+ * @brief Advances the item's animation by one timer tick.
+ * @return true while the animation is still running, false once it has finished.
+ */
+ virtual bool animationEvent() = 0;
+};
+
+#endif
diff --git a/cockatrice/src/game_graphics/board/abstract_card_drag_item.cpp b/cockatrice/src/game_graphics/board/abstract_card_drag_item.cpp
index 026efd60d..2f43591ac 100644
--- a/cockatrice/src/game_graphics/board/abstract_card_drag_item.cpp
+++ b/cockatrice/src/game_graphics/board/abstract_card_drag_item.cpp
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
const QColor GHOST_MASK = QColor(255, 255, 255, 50);
@@ -34,12 +35,13 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
setCacheMode(DeviceCoordinateCache);
- connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
- Q_UNUSED(_roundCardCorners);
+ connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::roundCardCornersChanged, this,
+ [this](bool _roundCardCorners) {
+ Q_UNUSED(_roundCardCorners);
- prepareGeometryChange();
- update();
- });
+ prepareGeometryChange();
+ update();
+ });
connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
}
@@ -47,7 +49,8 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
QPainterPath AbstractCardDragItem::shape() const
{
QPainterPath shape;
- qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
+ qreal cardCornerRadius =
+ SettingsCache::instance().cardsDisplay().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
return shape;
}
diff --git a/cockatrice/src/game_graphics/board/abstract_card_item.cpp b/cockatrice/src/game_graphics/board/abstract_card_item.cpp
index 86b3e27c8..1410d0c80 100644
--- a/cockatrice/src/game_graphics/board/abstract_card_item.cpp
+++ b/cockatrice/src/game_graphics/board/abstract_card_item.cpp
@@ -12,6 +12,9 @@
#include
#include
#include
+#include
+#include
+#include
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),
@@ -21,15 +24,17 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef
setFlag(ItemIsSelectable);
setCacheMode(DeviceCoordinateCache);
- connect(&SettingsCache::instance(), &SettingsCache::displayCardNamesChanged, this, [this] { update(); });
+ connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::displayCardNamesChanged, this,
+ [this] { update(); });
refreshCardInfo();
- connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
- Q_UNUSED(_roundCardCorners);
+ connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::roundCardCornersChanged, this,
+ [this](bool _roundCardCorners) {
+ Q_UNUSED(_roundCardCorners);
- prepareGeometryChange();
- update();
- });
+ prepareGeometryChange();
+ update();
+ });
}
AbstractCardItem::~AbstractCardItem()
@@ -45,7 +50,8 @@ QRectF AbstractCardItem::boundingRect() const
QPainterPath AbstractCardItem::shape() const
{
QPainterPath shape;
- qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
+ qreal cardCornerRadius =
+ SettingsCache::instance().cardsDisplay().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
return shape;
}
@@ -101,7 +107,7 @@ QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const
void AbstractCardItem::transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle)
{
- const int MAX_FONT_SIZE = SettingsCache::instance().getMaxFontSize();
+ const int MAX_FONT_SIZE = SettingsCache::instance().appearance().getMaxFontSize();
const int fontSize = std::max(9, MAX_FONT_SIZE);
QRectF totalBoundingRect = painter->combinedTransform().mapRect(boundingRect());
@@ -151,7 +157,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
painter->drawPath(shape());
}
- if (translatedPixmap.isNull() || SettingsCache::instance().getDisplayCardNames() || facedown) {
+ if (translatedPixmap.isNull() || SettingsCache::instance().cardsDisplay().getDisplayCardNames() || facedown) {
painter->save();
transformPainter(painter, translatedSize, angle);
painter->setPen(Qt::white);
@@ -234,7 +240,7 @@ void AbstractCardItem::setHovered(bool _hovered)
isHovered = _hovered;
setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue);
- setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
+ setScale(_hovered && SettingsCache::instance().cardsDisplay().getScaleCards() ? 1.1 : 1);
setTransformOriginPoint(_hovered ? CardDimensions::WIDTH_HALF_F : 0, _hovered ? CardDimensions::HEIGHT_HALF_F : 0);
update();
}
@@ -287,7 +293,7 @@ void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
}
tapped = _tapped;
- if (SettingsCache::instance().getTapAnimation() && canAnimate) {
+ if (SettingsCache::instance().cardsDisplay().getTapAnimation() && canAnimate) {
static_cast(scene())->registerAnimationItem(this);
} else {
tapAngle = tapped ? 90 : 0;
@@ -299,6 +305,11 @@ void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
}
}
+bool AbstractCardItem::animationEvent()
+{
+ return false;
+}
+
void AbstractCardItem::setFaceDown(bool _facedown)
{
facedown = _facedown;
diff --git a/cockatrice/src/game_graphics/board/abstract_card_item.h b/cockatrice/src/game_graphics/board/abstract_card_item.h
index bdb5f7cf1..8cbe95282 100644
--- a/cockatrice/src/game_graphics/board/abstract_card_item.h
+++ b/cockatrice/src/game_graphics/board/abstract_card_item.h
@@ -7,6 +7,7 @@
#ifndef ABSTRACTCARDITEM_H
#define ABSTRACTCARDITEM_H
+#include "../animated_item.h"
#include "../card_dimensions.h"
#include "arrow_target.h"
#include "graphics_item_type.h"
@@ -16,7 +17,7 @@
class PlayerLogic;
-class AbstractCardItem : public ArrowTarget
+class AbstractCardItem : public ArrowTarget, public IAnimatedItem
{
Q_OBJECT
protected:
@@ -126,6 +127,9 @@ public:
emit deleteCardInfoPopup(cardRef.name);
}
+ /** @brief Default: no per-tick animation. Subclasses override to animate. */
+ bool animationEvent() override;
+
protected:
void transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle);
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
diff --git a/cockatrice/src/game_graphics/board/abstract_counter.cpp b/cockatrice/src/game_graphics/board/abstract_counter.cpp
index 219dd456e..e63117e13 100644
--- a/cockatrice/src/game_graphics/board/abstract_counter.cpp
+++ b/cockatrice/src/game_graphics/board/abstract_counter.cpp
@@ -1,6 +1,7 @@
#include "abstract_counter.h"
#include "../../client/settings/cache_settings.h"
+#include "../../client/settings/shortcuts_settings.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../../game_graphics/board/translate_counter_name.h"
@@ -28,8 +29,9 @@ AbstractCounter::AbstractCounter(CounterState *state,
{
setAcceptHoverEvents(true);
- connect(state, &CounterState::valueChanged, this, [this](int, int newValue) {
+ connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
value = newValue;
+ onValueChanged(oldValue, newValue);
update();
});
@@ -227,3 +229,9 @@ void AbstractCounterDialog::changeValue(int diff)
curValue += diff;
setTextValue(QString::number(curValue));
}
+
+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 b319a722d..9ddcc6d58 100644
--- a/cockatrice/src/game_graphics/board/abstract_counter.h
+++ b/cockatrice/src/game_graphics/board/abstract_counter.h
@@ -35,6 +35,13 @@ protected:
bool hovered = false;
bool useNameForShortcut;
+ /**
+ * @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.
+ */
+ virtual void onValueChanged(int oldValue, int newValue);
+
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
diff --git a/cockatrice/src/game_graphics/board/arrow_item.cpp b/cockatrice/src/game_graphics/board/arrow_item.cpp
index af6a6bf36..664d44ecc 100644
--- a/cockatrice/src/game_graphics/board/arrow_item.cpp
+++ b/cockatrice/src/game_graphics/board/arrow_item.cpp
@@ -4,12 +4,14 @@
#include "../../client/settings/cache_settings.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
+#include "../game_scene.h"
#include "../player/player_target.h"
#include "../z_values.h"
#include "../zones/card_zone.h"
#include "card_item.h"
#include
+#include
#include
#include
#include
@@ -18,9 +20,27 @@
#include
#include
#include
+#include
+#include
#include
#include
+namespace
+{
+constexpr qreal kMinStrokeDurationMs = 200.0;
+constexpr qreal kMaxStrokeDurationMs = 450.0;
+constexpr qreal kMsPerPixel = 0.8;
+constexpr qreal kGlowFadeDurationMs = 120.0;
+constexpr qreal kSheenHalfWidth = 14.0;
+
+/// @brief Ease-out cubic, for a natural "slow in / slow out" reveal.
+qreal easeOutCubic(qreal t)
+{
+ const qreal inverse = 1.0 - t;
+ return 1.0 - inverse * inverse * inverse;
+}
+} // namespace
+
ArrowItem::ArrowItem(QSharedPointer _data, ArrowTarget *_startItem, ArrowTarget *_targetItem)
: data(std::move(_data)), startItem(_startItem), targetItem(_targetItem)
{
@@ -46,8 +66,23 @@ ArrowItem::ArrowItem(QSharedPointer _data, ArrowTarget *_startI
}
}
+ArrowItem::~ArrowItem()
+{
+ if (auto *scene = qobject_cast(this->scene())) {
+ scene->unregisterAnimationItem(this);
+ }
+}
+
void ArrowItem::onTargetDestroyed()
{
+ if (data->id == -1) {
+ // Drag and attach arrows are never inserted into the arrow registry and
+ // have no server-side counterpart, so no deletion event can clean them
+ // up. Delete them locally when either endpoint is destroyed.
+ delArrow();
+ return;
+ }
+
emit requestDeletion(data->creatorId, data->id);
}
@@ -90,16 +125,21 @@ void ArrowItem::updatePath(const QPointF &endPoint)
prepareGeometryChange();
if (lineLength < 30) {
path = QPainterPath();
+ bodyPath = QPainterPath();
+ headPath = QPainterPath();
+ shaftOutlinePath = QPainterPath();
+ centerLine = QPainterPath();
+ headBaseFraction = 1.0;
} else {
QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength);
- QPainterPath centerLine;
+ centerLine = QPainterPath();
centerLine.moveTo(0, 0);
centerLine.quadTo(c, QPointF(lineLength, 0));
- double percentage = 1 - headLength / lineLength;
- QPointF arrowBodyEndPoint = centerLine.pointAtPercent(percentage);
- QLineF testLine(arrowBodyEndPoint, centerLine.pointAtPercent(percentage + 0.001));
+ headBaseFraction = 1 - headLength / lineLength;
+ QPointF arrowBodyEndPoint = centerLine.pointAtPercent(headBaseFraction);
+ QLineF testLine(arrowBodyEndPoint, centerLine.pointAtPercent(headBaseFraction + 0.001));
qreal alpha = testLine.angle() - 90;
QPointF endPoint1 =
arrowBodyEndPoint + arrowWidth / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180));
@@ -110,20 +150,89 @@ void ArrowItem::updatePath(const QPointF &endPoint)
QPointF point2 =
endPoint2 + (headWidth - arrowWidth) / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180));
- path = QPainterPath(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
+ QPointF start1 = -arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180));
+ QPointF start2 = arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180));
+
+ path = QPainterPath(start1);
path.quadTo(c, endPoint1);
path.lineTo(point1);
path.lineTo(QPointF(lineLength, 0));
path.lineTo(point2);
path.lineTo(endPoint2);
- path.quadTo(c, arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
- path.lineTo(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
+ path.quadTo(c, start2);
+ path.lineTo(start1);
+
+ bodyPath = QPainterPath(start1);
+ bodyPath.quadTo(c, endPoint1);
+ bodyPath.lineTo(endPoint2);
+ bodyPath.quadTo(c, start2);
+ bodyPath.lineTo(start1);
+
+ headPath = QPainterPath(endPoint1);
+ headPath.lineTo(point1);
+ headPath.lineTo(QPointF(lineLength, 0));
+ headPath.lineTo(point2);
+ headPath.lineTo(endPoint2);
+
+ shaftOutlinePath = QPainterPath(start1);
+ shaftOutlinePath.quadTo(c, endPoint1);
+ shaftOutlinePath.moveTo(endPoint2);
+ shaftOutlinePath.quadTo(c, start2);
+ shaftOutlinePath.lineTo(start1);
}
setPos(startPoint);
setTransform(QTransform().rotate(-line.angle()));
}
+void ArrowItem::startDrawAnimation()
+{
+ if (!SettingsCache::instance().cardsDisplay().getArrowDrawAnimation() || centerLine.isEmpty()) {
+ return;
+ }
+
+ strokeDurationMs = qBound(kMinStrokeDurationMs, centerLine.length() * kMsPerPixel, kMaxStrokeDurationMs);
+ glowFadeDurationMs = kGlowFadeDurationMs;
+ // The clock is started on the first animationEvent() tick so that t=0
+ // corresponds to the first rendered frame. Starting it here would count
+ // the time spent before the item's first paint (event-loop delays, bursts
+ // of arrows created together), making the arrow appear already partway
+ // drawn when it first shows up.
+ animationStarted = false;
+ drawProgress = 0.0;
+ glowAlpha = 1.0;
+ update();
+ if (auto *scene = qobject_cast(this->scene())) {
+ scene->registerAnimationItem(this);
+ }
+}
+
+bool ArrowItem::animationEvent()
+{
+ if (!animationStarted) {
+ animationClock.start();
+ animationStarted = true;
+ }
+
+ const qint64 elapsed = animationClock.elapsed();
+ if (elapsed >= strokeDurationMs + glowFadeDurationMs) {
+ drawProgress = 1.0;
+ glowAlpha = 0.0;
+ update();
+ return false;
+ }
+
+ if (elapsed < strokeDurationMs) {
+ drawProgress = easeOutCubic(qBound(0.0, elapsed / strokeDurationMs, 1.0));
+ glowAlpha = 1.0;
+ } else {
+ drawProgress = 1.0;
+ glowAlpha = 1.0 - (elapsed - strokeDurationMs) / glowFadeDurationMs;
+ }
+ update();
+ return true;
+}
+
void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QColor paintColor(data->color);
@@ -132,8 +241,66 @@ void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
} else {
paintColor.setAlpha(150);
}
+
+ painter->save();
+ const QPen outlinePen = painter->pen();
painter->setBrush(paintColor);
- painter->drawPath(path);
+
+ const auto drawShaft = [this, painter, &outlinePen, paintColor]() {
+ painter->setPen(Qt::NoPen);
+ painter->drawPath(bodyPath);
+ painter->setPen(outlinePen);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawPath(shaftOutlinePath);
+ painter->setBrush(paintColor);
+ };
+
+ if (drawProgress >= 1.0 || path.isEmpty()) {
+ painter->drawPath(path);
+ } else if (drawProgress < headBaseFraction) {
+ // The reveal edge and the sheen share the same arc-length parameterization,
+ // so the stroke stays exactly in sync with the trailing sheen.
+ const qreal revealX = centerLine.pointAtPercent(drawProgress).x();
+ QPainterPath clip;
+ clip.addRect(QRectF(-glowExtent, path.boundingRect().top() - glowExtent, revealX + glowExtent,
+ path.boundingRect().height() + 2 * glowExtent));
+ painter->setClipPath(clip);
+ drawShaft();
+ } else {
+ // Once the reveal reaches the head base, pop the whole head in with a fade
+ // instead of slicing the triangle into a growing stub.
+ drawShaft();
+ const qreal headFadeIn = (drawProgress - headBaseFraction) / (1.0 - headBaseFraction);
+ painter->setOpacity(headFadeIn);
+ painter->setPen(Qt::NoPen);
+ painter->drawPath(headPath);
+ painter->setPen(outlinePen);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawPath(headPath);
+ painter->setOpacity(1.0);
+ painter->setBrush(paintColor);
+ }
+
+ if (glowAlpha > 0.0 && !centerLine.isEmpty()) {
+ // Sweep a bright band across the arrow. Clipping to the
+ // silhouette keeps it flat against the shaft so it reads as a light reflection.
+ const qreal anticipation = qMin(1.0, drawProgress / 0.08);
+ const QPointF sweep = centerLine.pointAtPercent(qMin(drawProgress, 1.0));
+ QLinearGradient sheen(sweep.x() - kSheenHalfWidth, 0.0, sweep.x() + kSheenHalfWidth, 0.0);
+ sheen.setColorAt(0.0, QColor(paintColor.red(), paintColor.green(), paintColor.blue(), 0));
+ sheen.setColorAt(0.5, QColor(255, 255, 255, 200));
+ sheen.setColorAt(1.0, QColor(paintColor.red(), paintColor.green(), paintColor.blue(), 0));
+ painter->save();
+ painter->setPen(Qt::NoPen);
+ painter->setClipPath(path);
+ painter->setBrush(sheen);
+ painter->setOpacity(glowAlpha * anticipation);
+ painter->drawRect(QRectF(sweep.x() - kSheenHalfWidth - glowExtent, path.boundingRect().top() - glowExtent,
+ (kSheenHalfWidth + glowExtent) * 2.0,
+ path.boundingRect().height() + glowExtent * 2.0));
+ painter->restore();
+ }
+ painter->restore();
}
void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
@@ -225,6 +392,12 @@ void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!startItem) {
+ // The source card was destroyed while the arrow was being drawn.
+ // Clean up the arrow and its children instead of leaking them.
+ delArrow();
+ for (auto *child : childArrows) {
+ child->mouseReleaseEvent(event);
+ }
return;
}
@@ -261,7 +434,7 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (startZone->getName() == ZoneNames::HAND) {
startCard->playCard(false);
CardInfoPtr ci = startCard->getCard().getCardPtr();
- bool playToStack = SettingsCache::instance().getPlayToStack();
+ bool playToStack = SettingsCache::instance().userInterface().getPlayToStack();
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
(playToStack && ci->getUiAttributes().tableRow != 0 &&
startCard->getZone()->getName() != ZoneNames::STACK))) {
@@ -348,6 +521,12 @@ void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!startItem) {
+ // The source card was destroyed while the arrow was being drawn.
+ // Clean up the arrow and its children instead of leaking them.
+ delArrow();
+ for (auto *child : childArrows) {
+ child->mouseReleaseEvent(event);
+ }
return;
}
diff --git a/cockatrice/src/game_graphics/board/arrow_item.h b/cockatrice/src/game_graphics/board/arrow_item.h
index 1c306e065..76a2d5d6c 100644
--- a/cockatrice/src/game_graphics/board/arrow_item.h
+++ b/cockatrice/src/game_graphics/board/arrow_item.h
@@ -2,9 +2,13 @@
#define ARROWITEM_H
#include "../../game/board/arrow_data.h"
+#include "../animated_item.h"
#include "arrow_target.h"
+#include "graphics_item_type.h"
+#include
#include
+#include
#include
#include
@@ -12,7 +16,7 @@ class CardItem;
class QGraphicsSceneMouseEvent;
class PlayerLogic;
-class ArrowItem : public QObject, public QGraphicsItem
+class ArrowItem : public QObject, public QGraphicsItem, public IAnimatedItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
@@ -21,6 +25,19 @@ signals:
private:
QPainterPath path;
+ QPainterPath bodyPath;
+ QPainterPath headPath;
+ QPainterPath shaftOutlinePath;
+ QPainterPath centerLine;
+ qreal headBaseFraction = 1.0;
+ QElapsedTimer animationClock;
+ qreal strokeDurationMs = 0;
+ qreal glowFadeDurationMs = 0;
+ qreal drawProgress = 1.0;
+ qreal glowAlpha = 0.0;
+ bool animationStarted = false;
+
+ static constexpr qreal glowExtent = 12.0;
protected:
QSharedPointer data;
@@ -32,17 +49,28 @@ protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
public:
+ enum
+ {
+ Type = typeArrow
+ };
+ [[nodiscard]] int type() const override
+ {
+ return Type;
+ }
ArrowItem(QSharedPointer _data, ArrowTarget *_startItem, ArrowTarget *_targetItem);
+ ~ArrowItem() override;
void onTargetDestroyed();
void delArrow();
void updatePath();
void updatePath(const QPointF &endPoint);
+ void startDrawAnimation();
+ bool animationEvent() override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
[[nodiscard]] QRectF boundingRect() const override
{
- return path.boundingRect();
+ return path.boundingRect().adjusted(-glowExtent, -glowExtent, glowExtent, glowExtent);
}
[[nodiscard]] QPainterPath shape() const override
{
@@ -106,4 +134,4 @@ protected:
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
};
-#endif
\ No newline at end of file
+#endif
diff --git a/cockatrice/src/game_graphics/board/card_item.cpp b/cockatrice/src/game_graphics/board/card_item.cpp
index cabe988c2..c40c8c214 100644
--- a/cockatrice/src/game_graphics/board/card_item.cpp
+++ b/cockatrice/src/game_graphics/board/card_item.cpp
@@ -1,6 +1,7 @@
#include "card_item.h"
#include "../../client/settings/cache_settings.h"
+#include "../../client/settings/card_counter_settings.h"
#include "../../game/phase.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
@@ -19,6 +20,7 @@
#include
#include